粘包
tcp粘包其实就是服务器端接收数据分界线不明确导致的, tcp数据传输是以流的方式传输的,在接收端有一个缓冲区,所有的信息都存储在这个缓冲区中,
在程序中接收数据是要有一个明确的接收长度的,客户端发送过来的数据长度不明确,服务器端用一个固定长度的数据进行接收导致数据接收分界线不明确从而导致粘包现象
如何解决
1 客户端告诉服务器本次数据的长度不就行了嘛, 这种适用于像聊天数据这种不定长的数据
2 客户端和服务器两者之间传输一个固定长度的信息,这种一般在文件传输中使用
聊天服务器版
# 服务器
import socket
import struct
def ReadMsg(Client):
head_len = 4
while True:
# 获取数据请求头, 获取数据长度
msg_len = Client.recv(head_len)
if not msg_len:
break
# 解析msg数据len长度
msg_len = struct.unpack("i", msg_len)
# 从缓存中获取真正的数据
msg_data = Client.recv(msg_len[0])
print(msg_len, msg_data.decode(), msg_data)
Client.close()
def main():
# 创建tcp连接
tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定tcp
tcp_server.bind(("", 8868))
# tcp转监听
tcp_server.listen()
while True:
print(‘开始接收客户端请求: ‘)
Client, addr = tcp_server.accept()
print("接收到来自 ip为:{} 端口为:{} 的请求 :".format(addr[0], addr[1]))
ReadMsg(Client)
if __name__ == ‘__main__‘:
main()
聊天客户端版
import socket
from random import randint
import struct
basemsg = "abc啊啊def中文gh吧ekkA冲EGO不jo包iewpF"
def ClientSend(tcp_client):
for i in range(10):
# 获取随机字符串
rad = randint(1, len(basemsg) - 1)
msg = "{msg: ‘%s‘}" % basemsg[0:rad]
# 获取要发送的信息二进制的长度,在python 中 字符串的长度和二进制的长度不一样的,
# 在二进制中中文占三个字节,在字符串中中文占1个字节
msg_len = len(msg.encode())
print(msg_len, struct.pack("i", msg_len), msg)
# 拼接数据,数据长度固定占4位,
msg = struct.pack("i", msg_len) + msg.encode()
tcp_client.send(msg)
def main():
# 创建tcp连接
tcp_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 客户端连接服务器
tcp_client.connect(("127.0.0.1", 8868))
ClientSend(tcp_client)
if __name__ == ‘__main__‘:
main()
文件系统服务器
import socket
import threading
def ReadFile(Client):
# 每次发送数据长度
red_buffsize = 2048
with open("./wallpaper.zip", "rb") as f:
while 1:
data = f.read(red_buffsize)
if not data:
break
Client.send(data)
Client.close()
def main():
# 创建tcp连接
tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定tcp
tcp_server.bind(("", 8868))
# tcp转监听
tcp_server.listen()
while True:
print(‘开始接收客户端请求: ‘)
Client, addr = tcp_server.accept()
print("Connection from :", addr)
t = threading.Thread(target=ReadFile, args=(Client,))
t.start()
if __name__ == ‘__main__‘:
main()
文件系统客户端
import socket
def main():
# 创建tcp连接
tcp_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 客户端连接服务器
tcp_client.connect(("127.0.0.1", 8868))
# 每次接收数据长度
buf_size = 2048
with open("./wallpaper.zip", "wb+") as f:
while 1:
# 接收数据
data = tcp_client.recv(buf_size)
if not data:
break
# 写入文件
f.write(data)
if __name__ == ‘__main__‘:
main()