今日内容

  • socket 套接字编程

    • 简易服务端与客户端代码实现
  • 通信循环
  • 黏包现象(TCP协议)
  • 报头制作、struct 模块、封装形式

内容详细

一、socket 套接字编程

实现一款能够进行数据交互的程序。

他们互通信息就得通过网络传输数据,那就肯定会涉及 OSI 七层协议的操作,而每次传输数据都要对OSI 七层协议进行操作,就会重复很多相似的工作,这时候就出现了 socket 模块,封装了OSI 七层协议的操作代码,我们在传输数据时,就可以通过socket 实例化的对象以点的形式方便快捷调用操作方法。

  • socket 模块

下面,我就用 socket 模块实现一个最简易的套接字编程

注意:先有服务端启动,客户端才能够成功连接服务端,实现数据互通

服务端

import socket

# 实例化一个套接字对象
server = socket.socket() # 给'服务端(应用程序)'绑定一个 IP + 端口号,作为唯一标识
server.bind(('192.168.11.134', 8080)) # 设置半连接池,最多容量(等待连接数)为5
server.listen(5) # 监听,当有客户端申请连接,获取它的socket对象和应用程序地址(IP+端口)
sock, address = server.accept() # 接收数据
data = sock.recv(1024) print(data.decode('utf8')) # 发送数据
sock.send('elijah is very good'.encode('utf8')) # 关闭与客户端连接的socket对象
sock.close() # 关闭服务端自己的socket对象
server.close()

客户端

import socket

# 实例化客户端的socket对象
client = socket.socket() # 客户端根据 IP+端口 精准连接服务端
client.connect(('192.168.11.134', 8080)) # 给服务端发送数据
client.send('i am client'.encode('utf8')) # 接收服务端回传的数据
data = client.recv(1024) print(data.decode('utf8')) # 关闭客户端
client.close()

二、通信循环

给简易版本升一下级,让服务端与客户端可以输入自定义的信息,并且不会一传输完数据就结束进程,让服务端一直处于监听状态,随时可以与客户端进行连接。

服务端

import socket

# 实例化一个套接字对象
server = socket.socket() # 给'服务端(应用程序)'绑定一个 IP + 端口号,作为唯一标识
server.bind(('192.168.11.134', 8080)) # 设置半连接池,最多容量(等待连接数)为5
server.listen(5) # 监听,当有客户端申请连接,获取它的socket对象和应用程序地址(IP+端口)
sock, address = server.accept() while True:
# 接收数据
client_data = sock.recv(1024) print(client_data.decode('utf8')) # 发送数据
server_data = input('输入您的回复>>>: ')
sock.send(server_data.encode('utf8'))

客户端

import socket

# 实例化客户端的socket对象
client = socket.socket() # 客户端根据 IP+端口 精准连接服务端
client.connect(('192.168.11.134', 8080)) while True:
# 给服务端发送数据
client_data = input('输入您的信息>>>: ')
client.send(client_data.encode('utf8')) # 接收服务端回传的数据
data = client.recv(1024) print(data.decode('utf8'))

实现你一句我一句的通信:

代码优化

1、让服务端一直处于监听状态,当服务端回复空消息,则断开与当前客户端的连接,回到监听状态
2、客户端发送的消息不可以为空(避免两者都处于revc等待状态)
3、服务端添加兼容性代码(mac linux)
4、服务端重启频繁报端口占用错误
from socket import SOL_SOCKET, SO_REUSEADDR
server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) # 在bind前加
5、客户端异常关闭服务端报错的问题
异常捕获 6.服务端链接循环
7.半连接池
设置可以等待的客户端数量(超出数量会报错)

服务端

import socket

# 实例化一个套接字对象
server = socket.socket() # 给'服务端(应用程序)'绑定一个 IP + 端口号,作为唯一标识
server.bind(('192.168.11.134', 8080)) # 设置半连接池,最多容量(等待连接数)为5
server.listen(5) while True:
# 监听,当有客户端申请连接,获取它的socket对象和应用程序地址(IP+端口)
sock, address = server.accept() while True:
# 处理客户端异常断开错误
try:
# 接收数据
client_data = sock.recv(1024) print(client_data.decode('utf8')) # 发送数据
server_data = input('输入您的回复>>>: ')
if len(server_data) == 0:
break
sock.send(server_data.encode('utf8'))
except Exception as e:
print(e)
break

客户端

import socket

# 实例化客户端的socket对象
client = socket.socket() # 客户端根据 IP+端口 精准连接服务端
client.connect(('192.168.11.134', 8080)) while True:
# 给服务端发送数据
client_msg = input('输入您的信息>>>: ')
if len(client_msg) == 0:
continue
client.send(client_msg.encode('utf8')) # 接收服务端回传的数据
data = client.recv(1024) print(data.decode('utf8'))

三、黏包问题

由于TCP协议也是一个流式协议,数据是会像流水一样进行传输

当客户端向服务端发起命令请求,服务端返回很大容量的数据,而客户端一次只接收1024字节,显然接收不完,剩余的数据不会丢失,而是会堵在传输通道中,等客户端下一次发起申请命令时,剩余的数据就会涌入,导致答非所问的问题。

TCP协议有一个特性

当发送的数据量比较少,多次发送,且发送时间间隔比较短
那么TCP会自动把这些数据全部打包成一个数据包接收 sock.send('litle')
sock.send('ll')
sock.send('a') client.recv()
client.recv()
client.recv()
---》 litlella

解决黏包问题

  • 制作报头

报头用于标识即将到来的数据具体信息

比如,数据的具体大小,这样,接收方就可以根据这个数据大小的具体信息,决定接收多大的数据

client.recv(4343534)

简易版本报头

import socket
import subprocess
import json
import struct server = socket.socket()
server.bind(('127.0.0.1', 8080))
server.listen(5) while True:
sock, address = server.accept()
while True:
data = sock.recv(1024) # 接收cmd命令
command_cmd = data.decode('utf8')
sub = subprocess.Popen(command_cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
res = sub.stdout.read() + sub.stderr.read() # 结果可能很大
# 1.制作报头
data_first = struct.pack('i', len(res))
# 2.发送报头
sock.send(data_first)
# 3.发送真实数据
sock.send(res) import socket
import struct client = socket.socket() # 买手机
client.connect(('127.0.0.1', 8080)) # 拨号 while True:
msg = input('请输入cmd命令>>>:').strip()
if len(msg) == 0:
continue
client.send(msg.encode('utf8'))
# 1.先接收固定长度为4的报头数据
recv_first = client.recv(4)
# 2.解析报头
real_length = struct.unpack('i',recv_first)[0]
# 3.接收真实数据
real_data = client.recv(real_length)
print(real_data.decode('gbk'))

可以把报头制作成字典的形式,这样,除了可以接收数据具体大小信息,还可以接收更多其它的数据信息,并且strut 打包时 'i' 模式也不会数据过大而报错

拓展知识

在阅读源码的时候
1.变量名后面跟冒号 表示的意思是该变量名需要指代的数据类型
2.函数后更横杆加大于号表示的意思是该函数的返回值类型

socket 套接字编程的更多相关文章

  1. linux网络环境下socket套接字编程(UDP文件传输)

    今天我们来介绍一下在linux网络环境下使用socket套接字实现两个进程下文件的上传,下载,和退出操作! 在socket套接字编程中,我们当然可以基于TCP的传输协议来进行传输,但是在文件的传输中, ...

  2. linux网络编程-(socket套接字编程UDP传输)

    今天我们来介绍一下在linux网络环境下使用socket套接字实现两个进程下文件的上传,下载,和退出操作! 在socket套接字编程中,我们当然可以基于TCP的传输协议来进行传输,但是在文件的传输中, ...

  3. socket套接字编程 HTTP协议

    socket套接字编程  套接字介绍  1. 套接字 : 实现网络编程进行数据传输的一种技术手段  2. Python实现套接字编程:import  socket  3. 套接字分类 >流式套接 ...

  4. Linux之socket套接字编程20160704

    介绍套接字之前,我们先看一下传输层的协议TCP与UDP: TCP协议与UDP协议的区别 首先咱们弄清楚,TCP协议和UCP协议与TCP/IP协议的联系,很多人犯糊涂了,一直都是说TCP/IP协议与UD ...

  5. 基于TCP协议的socket套接字编程

    目录 一.什么是Scoket 二.套接字发展史及分类 2.1 基于文件类型的套接字家族 2.2 基于网络类型的套接字家族 三.套接字工作流程 3.1 服务端套接字函数 3.2 客户端套接字函数 3.3 ...

  6. 基于TCP连接的socket套接字编程

    基于TCP协议的套接字编程(简单) 服务端 import socket server = socket.socket() server.bind( ('127.0.0.1', 9999) ) serv ...

  7. day31 socket套接字编程

    为什么要有套接字编程? 在上节课的学习中,我们学习了OSI七层协议,但是如果每次进行编程时我们都需要一层一层的将各种协议使用在我们的程序中,这样编写程序实在是太麻烦了,所以为了让程序的编写更加的简单, ...

  8. socket套接字编程(1)——基本函数

    TCP交互流程: 服务器:1. 创建socket:2. 绑定socket和端口号:3. 监听端口号:4. 接收来自客户端的连接请求:5. 从socket中读取字符:6. 关闭socket. 客户端:1 ...

  9. 19、网络编程 (Socket套接字编程)

    网络模型 *A:网络模型 TCP/IP协议中的四层分别是应用层.传输层.网络层和链路层,每层分别负责不同的通信功能,接下来针对这四层进行详细地讲解. 链路层:链路层是用于定义物理传输通道,通常是对某些 ...

随机推荐

  1. tomcat启动卡在了 At least one JAR was scanned for TLDs yet contained no TLDs 的根本原因与解决办法

    1.前言 有时候服务器开启时启动不了,卡在了 org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned fo ...

  2. HTTP 408 问题 - Koa body parser

    环境描述: 1.nodejs 作为 api 服务器,转发请求给 nginx 2.用 curl 测试,返回 408 找了很久没有找到原因,发现了一篇文章: https://lujunda.cn/2016 ...

  3. 第10组 Alpha冲刺 (6/6)

    1.1基本情况 ·队名:今晚不睡觉 ·组长博客:https://www.cnblogs.com/cpandbb/p/14008187.html ·作业博客:https://edu.cnblogs.co ...

  4. Word文档学习小练习链接

    1. < Word2010初学> https://www.toutiao.com/i6487370439910752782/ 2. <Word2010格式化可爱的家乡> htt ...

  5. MATLAB中插值算法实现

    %%%1.M文件%(1).以往少的程序可以在命令行窗口进行编码,但大量的程序编排到命令行窗口,%会有造成乱码的危险.(2).如果将命令编成程序存储在一个文件中(M文件),依次运行文件中的命令,则可以重 ...

  6. vue2如何根据不同的环境配置不同的baseUrl

    在正常的开发中,通常我们需要在线上的测试环境中运行代码来检查是否有些线上才会出现的bug或者是问题.每次去特意的修改我们的baseUrl显然是不现实的,而且说不定哪天忘记了估计会被大佬喷死 首先,这是 ...

  7. Python 为什么不设计 do-while 循环结构?

    在某些编程语言中,例如 C/C++.C#.PHP.Java.JavaScript 等等,do-while 是一种基本的循环结构. 它的核心语义是:先执行一遍循环体代码,然后执行一遍条件语句,若条件语句 ...

  8. 18个示例详解 Spring 事务传播机制(附测试源码)

    什么是事务传播机制 事务的传播机制,顾名思义就是多个事务方法之间调用,事务如何在这些方法之间传播. 举个例子,方法 A 是一个事务的方法,方法 A 执行的时候调用了方法 B,此时方法 B 有无事务以及 ...

  9. 【刷题-PAT】A1101 Quick Sort (25 分)

    1101 Quick Sort (25 分) There is a classical process named partition in the famous quick sort algorit ...

  10. 如何获取Repeater行号(索引)、记录总数?

    Repeater控件想必搞ASP.NET开发的人,基本上都到了用的炉火纯青的地步了.今个又吃了懒的亏,翻了好几个项目的代码都没找到如何获取Repeater记录总数的代码来,又Google了半天难得从老 ...