10分
处理粘包有2种做法比较常见的做法
1.发送定长包,就是每次发送的数据包长度不变,这样
server端就可以根据收到的数据长度,判定多收了,还是少收了。
2.在数据包头写的数据长度,这种方式灵活,server接收到数据后,
首先获取包长,以此为依据来分包。
1.发送定长包,就是每次发送的数据包长度不变,这样
server端就可以根据收到的数据长度,判定多收了,还是少收了。
2.在数据包头写的数据长度,这种方式灵活,server接收到数据后,
首先获取包长,以此为依据来分包。
—-
能简短的来段示范代码吗?
—-
http://blog.csdn.net/bdmh/article/details/25367297
我一般这么干,仅供参考,视具体情况定
我一般这么干,仅供参考,视具体情况定
—-
不管你发送的是多少,即使是1个字节,也将它放到一个1024的buffer中,保证每次发送的都是1024个长度,与服务端保持一致,这样也可以,就是有点浪费网络资源,高并发的情况下,不提倡。你写的这段思路看懂了,但是不会写,因为我刚刚接触这块,只会模仿着写。能给点具体的代码吗?谢谢拉
—- 10分
http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket(v=vs.110).aspx
这个实例中的SocketSendReceive 方法,将
这个实例中的SocketSendReceive 方法,将
Byte[] bytesReceived = new Byte[256];
放到do while循环里,可能是你想要的。
—- 10分
…… 粘包啊,
这个涉及到自己定义数据格式了
比如头4个字节定义传输长度,后面接数据,然后根据头4个字节来获取数据。
4|n4|n4|n
当然这只是最简单的方式。主要的解决方式就是自己定义数据格式,这点有些像通信协议。
有兴趣的话可以自己看看socket通信协议,模拟这个写就OK。
数据就像古文,这么断句要先告诉别人,要不就等着百家争鸣吧
这个涉及到自己定义数据格式了
比如头4个字节定义传输长度,后面接数据,然后根据头4个字节来获取数据。
4|n4|n4|n
当然这只是最简单的方式。主要的解决方式就是自己定义数据格式,这点有些像通信协议。
有兴趣的话可以自己看看socket通信协议,模拟这个写就OK。
数据就像古文,这么断句要先告诉别人,要不就等着百家争鸣吧
—- 10分
先写长度可以大体这样做,你把例子拷贝到你的服务/客户程序上,双方就可以发字符串聊天了:
static void SendString(Socket socket, string str) { byte[] utf8 = Encoding.UTF8.GetBytes(str); Send(socket, BitConverter.GetBytes(utf8.Length)); // 先发内容的长度 Send(socket, utf8); // 再发实际内容 } static string ReceiveString(Socket socket) { byte[] lengthBytes = Receive(socket, 4); int length = BitConverter.ToInt32(lengthBytes, 0); // 先收内容长度 byte[] strBytes = Receive(socket, length); return Encoding.UTF8.GetString(strBytes); //再收内容 } static byte[] Receive(Socket socket, int length) { byte[] bytes = new byte[length]; for (int offset = 0; offset < length; ) { int received = socket.Receive(bytes, offset, bytes.Length - offset, SocketFlags.None); if (received == 0) throw new Exception("socket closed"); offset += received; } return bytes; } static void Send(Socket socket, byte[] bytes) { for (int offset = 0; offset < bytes.Length; ) { offset += socket.Send(bytes, offset, bytes.Length - offset, SocketFlags.None); } }
—- 10分
先发长度再发包
—-
问题在于,如果发送的长度和数据包都粘包了,怎么办,这种多次发送个人认为不可取啊
—- 10分
把实际内容拼接到长度的后面,一个包发送出去,不行?
—-
不会拼接啊,能否来段代码看下呢?
—-
所谓拼接,不就是操作byte[ ]数组吗
比如先定义一个byte[ ] b1=new byte[1000];
再定义一个byte[ ] b2=new byte[4];
如果b1里是当前要发送的内容,计算出有效数据的长度(字节数),转成byte[ ],赋值给b2
然后循环b1,全部往后移动4个字节,再把b2内容赋值给b1的前4个字节,然后有效数据长度+=4
发送
比如先定义一个byte[ ] b1=new byte[1000];
再定义一个byte[ ] b2=new byte[4];
如果b1里是当前要发送的内容,计算出有效数据的长度(字节数),转成byte[ ],赋值给b2
然后循环b1,全部往后移动4个字节,再把b2内容赋值给b1的前4个字节,然后有效数据长度+=4
发送
接收到之后,前4个字节就表示后面的数据位数,如果收到的总长度不等于这个数字+4,说明不是多了就是少了
—-
有个简单办法,发送方发送完一包后就等待接收方回复确认,收到确认后再发下一包,唯一缺点是减慢了数据传输速度,不过大部分情况这都不是问题。
—-
这样做没有实际的优点。
UDP是基于消息的,因此你一次发一个UDP包,对方要么收不到,要么就完整的收到一个UDP包。
但TCP是基于字节流的,它从来就没有保证过按发送的批次来进行数据分割的。因此,你发两次数据和发一次数据,接收方并不能区别,他可能一次就收到两批数据,也可能五次才收到一批数据。
所谓的’粘包‘,并不是由发送批次造成的,而是由于误解TCP的流式传输而形成的错误程序设计造成的。
TCP是可靠的协议,只要双方的约定正确,那里有’粘包‘的困扰?
—-
另外,科普一下。
目前流行的Socket实现中都用了Nagle algorithm。
它使得少量数据不会被马上传送出去,而是积累到一定数量或超过一定的时间,才进行传输。
这是因为每个IP+TCP包都有至少40个字节的开销,立即传送几个字节的数据会造成浪费。
也就是说,先发几个字节接着发一段数据,跟事先合并字节与数据,没有实际上的区别。
—-
包头+包体+数据
包体=数据的长度(知道固定长度的字节)
接受端,接受包头+包体
包体=数据的长度(知道固定长度的字节)
接受端,接受包头+包体
—-
包体里存着 数据的实际长度,这样后面怎么粘包,也不会多接收,
—-
这位朋友你所指的约定正确是怎么个做法,能详细说明下吗?
—-
自定义协议头,协议尾,数据帧= 协议头+数据长度+数据+协议尾。接收到数据后找到协议头,根据数据长度算得协议尾的位置,如果那个位置的数据确实是协议尾 这就是一条完整的数据帧。