C# TCP socket发送大数据包时,接收端和发送端数据不一致 服务端接收Receive不完全
C# TCP socket发送大数据包时,接收端和发送端数据不一致 服务端接收Receive不完全
在发送端,一次发送200k个字节,在接收端,一次接收200k个字节,
但是在接收端,经常会出现 socket.receive 接收不全的情况 ,
偶尔接收的包也是正常的,用Wireshark抓包发现,每次发送都分成了多个1514字节长的数据包,一次数据有多个数据包,
标准以太网帧长度下限为:64 字节
标准以太网帧长度上限为:1518 字节
每个数据包含1448字节有效数据
这也正好解释了为什么接收数据包不完整时接收到的长度都正好是1448的倍数如1448,2896,4344等等
所以需要多次接收然后对数据进行合并,代码如下:
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); listener.ReceiveBufferSize = 100 * 1024 * 1024; listener.ReceiveTimeout = 100000; listener.Bind(localEndPoint); Socket sock = listener.Accept(); byte[] bs = new byte[1024*1024]; int ilen = sock.Receive(bs); uint length = ByteTouint(bs, 3, 4); while (ilen < length) { int ii = sock.Receive(bs, ilen, 500 * 1024, SocketFlags.None); ilen = ilen + ii; }
这样接收的内容就对了。
异步方式里 C# 的TCP Socket (异步方式) ,在ReadCallback里
while (bytesRead < state.bodybuffer.Length) { int ii = handler.Receive(state.bodybuffer, bytesRead, state.bodybuffer.Length - bytesRead, SocketFlags.None); bytesRead = bytesRead + ii; }
链接:https://www.zhihu.com/question/21524257/answer/118266374
来源:知乎
著作权归作者所有,转载请联系作者获得授权。
最早的以太网工作方式:载波多路复用/冲突检测CSMA/CD,因为网络是共享的,即任何一个节点发送数据之前,先要侦听线路上是否有数据在传输,如果有,需要等待,如果线路可用,才可以发送。
假设A发出第一个bit位,到达B,而B也正在传输第一个bit位,于是产生冲突,冲突信号得让A在完成最后一个bit位之前到达A,这个一来一回的时间间隙slot time是57.6μs.
在10Mbps的网络中,在57.6μs的时间内,能够传输576个bit,所以要求以太网帧最小长度为576个bits,从而让最极端的碰撞都能够被检测到。这个576bit换算一下就是72个字节,去掉8个字节的前导符和帧开始符,以太网帧的最小长度为64字节。
如果说以太网帧的最小长度64byte是由CSMA/CD限制所致,那最大长度1500byte又是处于什么考虑的呢?
IP头total length为两个byte,理论上IP packet可以有65535 byte,加上Ethernet Frame头和尾,可以有65535 +14 + 4 = 65553 byte。如果在10Mbps以太网上,将会占用共享链路长达50ms,这将严重影响其它主机的通信,特别是对延迟敏感的应用是无法接受的。
由于线路质量差而引起的丢包,发生在大包的概率也比小包概率大得多,所以大包在丢包率较高的线路上不是一个好的选择。
但是如果选择一个比较小的长度,传输效率又不高,拿TCP应用来说,如果选择以太网长度为218byte,TCP payload = 218 - Ethernet Header -IP Header - TCP Header=218-18 - 20 -20= 160 byte
那有效传输效率=160/218= 73%
而如果以太网长度为1518,那有效传输效率=1460/1518=96%
通过比较,选择较大的帧长度,有效传输效率更高,而更大的帧长度同时也会造成上述的问题,于是最终选择一个折衷的长度:1518 byte ! 对应的IP packet 就是 1500 byte,这就是最大传输单元MTU的由来。