- 主题:怎么样传输大的数据结构?
哈哈~~
【 在 fanci 的大作中提到: 】
: 粘包适合楼主
--
FROM 114.135.208.*
啥乱七八糟的,tcp哪来的包,就一字节流...
【 在 confinement 的大作中提到: 】
: pb没用过不熟
: tcp本来就会分包啊,协议规定的数据帧容量限定的,一般默认1500字节的mtu(还要除去大概二十个字节的包头才能装用户数据),好像现在很多网络支持大的可以到9000还是多少来着,但终究也是有限的。然后系统的socket api收发的时候就按这个来,应用层需要自己组装数据的。这么多年过去了,这种麻烦的事情肯定有人帮我们做好,所以我就是要找一个方便的序列化库来帮我干这些事
:
--
FROM 123.122.60.*
可能是我搞错了。我们不是专业码农,算法为主,但有时候干杂活什么都干,我是网上抄别人的代码改,可能是别人代码里recv的buffer给的小,所以要多次读取...
【 在 milksea 的大作中提到: 】
: tcp给上层调用者根本没有片的概念。传输数据必须自己写长度或分隔符来划分不同的消息。编程时收发操作和二进制文件读写是差不多的。
: 比如 asio::read 读 20 字节,可能内部一次读完,也可能内部 17 次读完,具体用了几个 ip 包是不可预料的,但你用起来就是一次调用,没收完就阻塞。
--
FROM 223.104.63.*
我不知道,反正就是调用socket 那一套, send 发送, recv 接收。昨天你们说了之后我还以为是不是我接收端的buff整的太小了,今天又试了一下,send 这端是不管的,一下发出去,recv(connction, buffer, recv_size, 0) 这个buffer,和recv_size 都搞大了,结果还是分片呀,比如send一个几万字节的buffer,recv函数一次可能只接收了数千个字节,需要循环调N次才能接收完
请问要怎么样一次发送完一次接收完?
【 在 eggcar 的大作中提到: 】
: 啥乱七八糟的,tcp哪来的包,就一字节流...
:
--
修改:confinement FROM 223.104.63.*
FROM 223.104.63.*
我不知道,反正就是调用socket 那一套, send 发送, recv 接收。昨天你们说了之后我还以为是不是我接收端的buff整的太小了,今天又试了一下,send 这端是不管的,一下发出去,recv(connction, buffer, recv_size, 0) 这个buffer,和recv_size 都搞大了,结果还是分片呀,比如send一个几万字节的buffer,recv函数一次可能只接收了数千个字节,需要调N次才能接收完
请问要怎么样一次发送一次接收?
【 在 milksea 的大作中提到: 】
: tcp给上层调用者根本没有片的概念。传输数据必须自己写长度或分隔符来划分不同的消息。编程时收发操作和二进制文件读写是差不多的。
: 比如 asio::read 读 20 字节,可能内部一次读完,也可能内部 17 次读完,具体用了几个 ip 包是不可预料的,但你用起来就是一次调用,没收完就阻塞。
--
修改:confinement FROM 223.104.63.*
FROM 223.104.63.*
转:
http://www.cnitblog.com/donne/archive/2010/12/23/72500.htmlIP分片 在以太网上,由于电气限制,一帧不能超过1518字节,除去以太网帧头14字节(mac地址等)和帧尾4字节校验,还剩1500字节,这个大小称为MTU(最大传输单元)。 如果你的IP包大于1500字节,IP层就会分片了。 而1492的MTU值的来源,是因为PPPoE协议。PPP协议是宽带运营商用于对用户认证计费的(TCP/IP以太网无此功能)。PPPoE头尾一共8字节,所以有效载荷MTU变小了,原来有1500字节,现在只剩1492了。 这1492还包含20字节IP头,8字节UDP头或者20字节TCP头。所以真正的不分片数据,UDP为1492-28=1464,TCP为1492-40=1452字节。 TCP的确是流的,所以TCP一个包可以包含的数据大小为65536(包头长度定义为2字节).a向b连续发送数据,b在每次接受到数据大小大于其低水位后,你的recv就会返回(假设是阻塞模式),并得到数据长度。当然你要持续接受和处理数据。 如果实际数据大于1452字节,IP会分片,但IP也会重组分片,所以还是一次recv就可以收到(不一定全,但跟分片无关)。 如果一个分片丢失,则整个TCP包都会重发,因为IP层不会将没收完的分片交给传输层。 ACK确认的时机,是收到了就会确认上一次的完整包的TCP序列号,如果不完整当然要等收完整,也不会交互到应用层,也不会发送ACK确认(可以通过3次确认上一个完整的序列号以让发送方快传)。 握手协商和ACK TCP在发起3次握手时,会协商MSS(最大分节大小),这个值一般是路径最小MTU-IP头-TCP头,如果MTU是1500,则1500-20-20=1460字节。这样,每个包就不用IP层再分片了。所以你发2000字节,你调用一次send,如果发送缓冲区移动窗口够大,应该会全部成功。否则,会返回实际发送的字节。假设2000字节全部成功,tcp实际会将其分为1460和540两个包发送,接受端接受到1460这个包就会回一次ACK,接到540大小这个再ACK一次。每个分节都带有IP头和TCP头的。 IP分片只有第一个带有传输层头,其余的分片只有IP头
--
FROM 223.104.63.*
你这个想法就完全不对
stream不存在什么一次发送完一次接收完,只保证每个字节按顺序到达,ip层分几个包 每个字节中间延迟多少 对你都是不可见的
你要自己把收到的所有字节丢到缓冲区里,再按协议解析流
【 在 confinement 的大作中提到: 】
: 我不知道,反正就是调用socket 那一套, send 发送, recv 接收。昨天你们说了之后我还以为是不是我接收端的buff整的太小了,今天又试了一下,send 这端是不管的,一下发出去,recv(connction, buffer, recv_size, 0) 这个buffer,和recv_size 都搞大了,结果还是分片呀,比如send一个几万字节的buffer,recv函数一次可能只接收了数千个字节,需要循环调N次才能接收完
: 请问要怎么样一次发送完一次接收完?
:
--
FROM 111.198.57.*
你安心用 http, zeromq 等等别人已经折腾好的协议。别一上来就什么都自己轮。
你转的这个跟你的问题一点关系都没有。。
有句话叫思而不学则殆。你应该去看看别人做的协议和源码,每一段代码都是什么意思都搞清楚,认真学习一番。瞎想有什么用呢。
【 在 confinement (禁闭) 的大作中提到: 】
: 转:
http://www.cnitblog.com/donne/archive/2010/12/23/72500.html: IP分片 在以太网上,由于电气限制,一帧不能超过1518字节,除去以太网帧头14字节(mac地址等)和帧尾4字节校验,还剩1500字节,这个大小称为MTU(最大传输单元)。 如果你的IP包大于1500字节,IP层就会分片了。 而1492的MTU值的来源,是因为PPPoE协议。PPP协议是宽带运
--
FROM 183.250.222.*
socket 的 recv 不保证一次接收,asio::read 就保证了,而 asio::read_some 又不保证了。不同函数功能不一样,你好好看文档,掌握好第一手材料。
【 在 confinement 的大作中提到: 】
: 我不知道,反正就是调用socket 那一套, send 发送, recv 接收。昨天你们说了之后我还以为是不是我接收端的buff整的太小了,今天又试了一下,send 这端是不管的,一下发出去,recv(connction, buffer, recv_size, 0) 这个buffer,和recv_size 都搞大了,结果还是分片呀,比如send一个几万字节的buffer,recv函数一次可能只接收了数千个字节,需要调N次才能接收完
:
: 请问要怎么样一次发送一次接收?
: ...................
--
FROM 114.249.193.*
【 在 confinement 的大作中提到: 】
: 我不知道,反正就是调用socket 那一套, send 发送, recv 接收。昨天你们说了之后我还以为是不是我接收端的buff整的太小了,今天又试了一下,send 这端是不管的,一下发出去,recv(connction, buffer, recv_size, 0) 这个buffer,和recv_size 都搞大了,结果还是分片呀,比如send一个几万字节的buffer,recv函数一次可能只接收了数千个字节,需要调N次才能接收完
: 请问要怎么样一次发送一次接收?
:
本来就是需要循环接收的。每次接收多少字节并不确定。
自己写个循环接收程序。
另外,发送也不保证一次发完,也需要循环。
所以通常都需要自己搞一个程序。
while(bcount<n){
if((br=read(socket,buf,n-bcount))>0){
bcount+=br;
buf+=br;
continue;
}
if(fflag==-1 && errno==EAGAIN) return TIMEOUTERR;
if(br<=0 && errno && errno != EAGAIN){
if(errno!=ECONNRESET)
ShowLog(1,"%s:br=%d,err=%d,%s",__FUNCTION__,br,errno,strerror(errno));
break;
}
}
--
修改:ylh1969 FROM 221.221.46.*
FROM 221.221.46.*