1,socket(套接字)
socket层
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口
server端
import socket sk = socket.socket() sk.bind(('127.0.0.1',8898)) #把地址绑定到套接字 sk.listen() #监听链接 conn,addr = sk.accept() #接受客户端链接 ret = conn.recv(1024) #接收客户端信息 print(ret) #打印客户端信息 conn.send(b'hi') #向客户端发送信息 conn.close() #关闭客户端套接字 sk.close() #关闭服务器套接字 根据情况选择
client 端
import socket sk = socket.socket() # 创建客户套接字 sk.connect(('127.0.0.1',8898)) # 尝试连接服务器 sk.send(b'hello!') ret = sk.recv(1024) # 对话(发送/接收) print(ret) sk.close() # 关闭客户套接字
2,粘包
1,什么是粘包 例如基于tcp的套接字客户端往服务端上传文件, 发送时文件内容是按照一段一段的字节流发送的, 在接收方看了,根本不知道该文件的字节流从何处开始,在何处结束 2,粘包是怎么造成的 发送方引起的粘包是由TCP协议本身造成的,TCP为提高传输效率, 发送方往往要收集到足够多的数据后才发送一个TCP段。 若连续几次需要send的数据都很少,通常TCP会根据优化算法把这些数据合成一个TCP段后一次发送出去, 这样接收方就收到了粘包数据。 3,tcp传输的原理 用TCP协议发送时,由于TCP是数据流协议,因此不存在包大小的限制(暂不考虑缓冲区的大小), 这是指在用send函数时,数据长度参数不受限制。 而实际上,所指定的这段数据并不一定会一次性发送出去, TCP特点: 会将数据量比较小的并且时间间隔比较短的数据 一次性打包发送给对方 4,发生黏包的两种情况: 情况一 发送方的缓存机制 发送端需要等缓冲区满才发送出去,造成粘包(发送数据时间间隔很短,数据了很小,会合到一起,产生粘包) 情况二 接收方的缓存机制 接收方不及时接收缓冲区的包,造成多个包接收(客户端发送了一段数据,服务端只收了一小部分, 服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包) ps:主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的 ***************** 解决方案: struct 模块 服务端 1.先制作一个发送给客户端的字典 2.制作字典的报头 3.发送字典的报头 4.发送字典 5.再发真实数据 客户端 1.先接受字典的报头 2.解析拿到字典的数据长度 3.接受字典 4.从字典中获取真实数据的长度 5.接受真实数据 把报头做成字典,字典里包含将要发送的真实数据的详细信息,然后json序列化,然后用struck将序列化后的数据长度打包成4个字节 发送时接收时先发报头长度
先收报头长度,用struct取出来再编码报头内容然后发送根据取出的长度收取报头内容,然后解码,反序列化最后发真实内容从反序列化的结果中取出待取数据的详细信息,然后去取真实的数据内容客户端
import socket import struct import json print("客户端") client = socket.socket() # 绑定服务器ip和端口 client.connect(('127.0.0.1', 8333)) # 循环收发数据 while True: msg = input('>>>>>:').encode('utf-8') # 为了防止出现你等我,我等你这种情况,(客户端按了end,服务端没接受到数据 # 而客户端此时也走到了recv阶段,服务端一直处于recv阶段,所以一直处于阻塞状态 if len(msg) == 0:continue # 所以要有这个判断,continue结束本次循环 client.send(msg) # 先接受报头长度 header_dict = client.recv(4) # 解析报头,获取字典的长度 dict_size = struct.unpack('i', header_dict)[0] dict_bytes = client.recv(dict_size) dict_json = json.loads(dict_bytes.decode('utf-8')) print(dict_json) recv_size = 0 real_data = b'' while recv_size < dict_json.get('file_size'): data = client.recv(1024) real_data += data recv_size += len(data) print(real_data.decode('gbk')) client.close() 服务端: import socket import subprocess import struct import json server = socket.socket() server.bind(('127.0.0.1',8080)) server.listen(5) while True: conn, addr = server.accept() while True: try: cmd = conn.recv(1024) if len(cmd) == 0:break cmd = cmd.decode('utf-8') obj = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) res = obj.stdout.read() + obj.stderr.read() d = {'name':'jason','file_size':len(res),'info':'asdhjkshasdad'} json_d = json.dumps(d) # 1.先制作一个字典的报头 header = struct.pack('i',len(json_d)) # 2.发送字典报头 conn.send(header) # 3.发送字典 conn.send(json_d.encode('utf-8')) # 4.再发真实数据 conn.send(res) # conn.send(obj.stdout.read()) # conn.send(obj.stderr.read()) except ConnectionResetError: break conn.close()转载于:https://www.cnblogs.com/Fzhiyuan/p/11318405.html
相关资源:GOLANG语言实现SOCKET通讯粘包问题解决示例