1.写在前面的话:
这两天在帮实验室老板打工,需要实现局域网通信,本来觉得挺简单的,网上那么多,Ctrl+C,Ctrl+V谁不会,自己测试的时候发送接受一两条消息没啥问题,直到联调的时候,发送接受数据速度和量上去,问题一堆,直接搞心态。所以,还是编程基础太差,另外没搞清楚原理就上,学校还好,以后出去打工不得背锅。基础不牢,地动山摇。
之后,上网查了一些相关资料,找到了一篇大佬的文章,详细介绍了TCP协议,粘包和半包问题,产生的原因,以及java编程的三种解决方案,本文参考这篇文章,采用了其中的第二种,python 编程以做演示。
Socket粘包问题的3种解决方案,最后一种最完美! - Java中文社群 - 博客园
2.问题描述:
在server和client端,socket编程发送和接受数据时候使用TCP 协议,出现了粘包和半包的情况。
3.原因分析:
4.解决方案:
在另外一篇文章中看到:使用特殊字符结尾的解决方案并不被看好,其中优劣,各位看官自行斟酌,个人选择了数据包封装的方法。
【Python】TCP Socket的粘包和分包的处理_代码就是生产力!-CSDN博客_python socket 粘包
5.python编程实现:(解决方案二)
server:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket
import struct
# 创建一个socket套接字,该套接字还没有建立连接
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定监听端口,这里必须填本机的ip,后面6688是端口号,自选
server.bind(('192.168.0.105', 6688))
# 开始监听,并设置最大连接数
server.listen(5)
print(u'waiting for connect...')
# 等待连接,一旦有客户端连接后,返回一个建立了连接后的套接字和连接的客户端的IP和端口元组
connect, (host, port) = server.accept()
print(u'the client %s:%s has connected.' % (host, port))
while True:
# 接受客户端的数据
# 先接收保存有数据长度的4个byte
rec_data_len = connect.recv(4)
# 得到数据长度
rec_data_len1=struct.unpack('i',rec_data_len)[0]
# 接收得到数据长度的数据
data=connect.recv(rec_data_len1)
# 如果接受到客户端要quit就结束循环
if data == b'quit' or data == b'':
print(b'the client has quit.')
break
else:
# 发送数据给客户端
connect.send(b'your words has received.')
print(b'the client say:' + data)
# 结束socket
server.close()
client:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket
import struct
# 创建一个socket
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 主动去连接局域网内IP为192.168.27.238,端口为6666的进程,即服务器端设置的ip和端口
client.connect(('192.168.0.105', 6688))
while True:
# 接受控制台的输入
data =input()
# 对数据进行编码格式转换,不然报错
data = data.encode('utf-8')
# 如果输入quit则退出连接
if data == b'quit':
print(b'connect quit.')
break
else:
#确定要发送数据的长度
data_len=len(data)
#将这个长度打包成特定byte的数据,参数'i'表明4个byte
send_data_len=struct.pack('i',data_len)
# 发送数据长度
client.send(send_data_len)
#发送数据
client.send(data)
# 接收服务端的反馈数据
# 先接收保存有数据长度的4个byte
rec_data_len = client.recv(4)
# 得到数据长度
rec_data_len1=struct.unpack('i',rec_data_len)[0]
# 接收得到数据长度的数据
rec_data=client.recv(rec_data_len1)
print(b'form server receive:' + rec_data)
# 发送数据告诉服务器退出连接
client.sendall(b'quit')
client.close()
6.发展中进步:
在总结这些的过程中发现,可以使用json文件进行文件收发,这样可以带来更多便利,之后可以学习一下,另外,多client连接server也有必要学习一下,期待我之后的总结吧!!