粘包问题可能发生在数据量很小的情况下,经过底层算法的优化,就把几条很小的数据合并发送了。只会发生在TCP的情况下,UDP一般不会。
那么如何解决呢?
度娘们给我的回答都能一致,大致的思路就是设置一个数据长度的标志位,并且都是要求占4个字节,有的是说数据标志位和数据一起发送,有的说是先发送标志位,然后紧接着接收数据,害,我感觉都一样。
如果先发送标志位的话,额,倒也是可以,首先直接设定接收4个字节的数据,然后byte转为数字,再次接收真实数据。
如下:注释应该是写的比较清楚了
python 2.*服务端
# coding=utf-8
# 使用utf-8编码
import socket
import select
import struct
# the max player number
playerNumber = 10
# host and port
host = socket.gethostname()
port = 12345
# create socket named mySocket,based on TCP
mySocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# bind
mySocket.bind(("127.0.0.1",port))
# listen
mySocket.listen(playerNumber)
Socket_List = [mySocket]
while True:
myEvent,wret,xret = select.select(Socket_List,[],[])
# print myEvent
for i in myEvent:
if i is mySocket:
conn,addr = i.accept()
Socket_List.append(conn)
else:
# 接收到消息,输出
try:
receiveData = i.recv(4)
# 这里是将byte转为整数
data = struct.unpack('i',receiveData)
print type(data[0]),data[0]
receiveData = i.recv(data[0])
print receiveData
# 铭记,客户端正常关闭的话
# 这里直接判断接收的是否为空字符串即可
# if receiveData == "88" or receiveData == "":
if receiveData == "":
Socket_List.remove(i)
i.close()
continue
# 客户端关闭了,从sockelist中删除
except:
Socket_List.remove(i)
i.close()
continue
Socket_List.remove(mySocket)
mySocket.close()
配套C#客户端
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace TCP客户端
{
class Program
{
static void Main(string[] args)
{
//创建socket
Socket mySocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//链接
mySocket.Connect(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 12345));
for (int i = 0; i < 200; i++)
mySocket.Send(MessageUtil.GetBytes(i.ToString()));
mySocket.Close();
}
}
}
配套的MessageUtil类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TCP客户端
{
class MessageUtil
{
public static byte[] GetBytes(string message)
{
byte[] messageBytes = Encoding.UTF8.GetBytes(message);
int messageLength = messageBytes.Length;
//将长度变为byte数组
byte[] messageLengthBytes = BitConverter.GetBytes(messageLength);
byte[] resultBytes = messageLengthBytes.Concat(messageBytes).ToArray();
return resultBytes;
}
}
}
执行效果,没有粘包现象发生
不错处理的话,可以发现,即使就200次循环,还是有很多粘包发生