user-0 提问: 关于socket通信send和recv中buffer长度的问题

回复:
user: user-1
content: tcp是基于流的，不是发100，就一定收100 有可能收了95个，然后又收了5 和网络状况没有直接关联， 所以tcp数据接收，进行“拼包”（一次发送多次接收）、“分包”（多次发送一次接收）是基本操作。

user: user-2
content: offset = byte_num; 改成 offset += byte_num;

user: user-2
content: 一个包不一定能送完数据，可能送多个包 所以你应该用循环接收，直到byte_num为-1才算接受完。每次接收到的数据自己保存，最后再拼装成一个完整的数据 int byte_num = 0, offset = 0； char data[4096] = {0}; while(byte_num != -1) { //多次接收直到没有数据     byte_num = recv(server_sock_fd, buf_rec, 4096, 0);     memcpy(data+offset, buf_rec, byte_num); //把每次接收的数据保存     offset = byte_num; }

user: user-0
content: 引用 11 楼 beastsam 的回复:[quote=引用 10 楼 轻箬笠 的回复:] [quote=引用 6 楼 beastsam 的回复:] [quote=引用 4 楼 轻箬笠 的回复:] recv和send的处理方式不太一样。一般我们都是循环接收的，以保证数据的完整性。所以通行的办法是弄个固定长度的报文头，报文头中带报文长度数据，然后循环接收，直到长度满足要求为止。最简单的报文头就是，前4个字节（即int）就代表了报文的长度。  这个难道不是应该是tcp层处理的么？我理解tcp分片，但是不应该是系统接收完所有的4096分片后才把数据返回给recv里的buf么？而且我看很多教程说循环接受是为了防止发送的数据超过recv里buf的长度，但是我这个并没有超过啊？[/quote] 这个还真不是，曾经在项目中碰到过，发送几百个字节，第一次接收只有几十个字节的情况。[/quote]  这样啊，好吧，谢谢您，我还有个关于带宽的问题不知道您了解么？ 我的虚拟机开了3个系统，分别运行了10个客户端，一个中继转发，10个服务器，1个客户端通过中继连接1个服务器，我让服务器同时开始传输200KB的文件，大小分成4096的数据块，发送间隔35ms 我的中继上传和下载带宽都设置的是1MiB/S，虚拟机之间延迟为0,但是我在中继用wireshark抓包发现他的上传和下载每秒的峰值只有0.5MiB，请问这个为什么不是1MiB?[/quote]  额，是我蠢了，没事，是时间间隔的问题

user: user-0
content: 引用 8 楼 qybao 的回复:[quote=引用 5 楼 beastsam 的回复:] TCP分片这个我知道，但是按理来说recv的工作原理难道不是等接收够4096所有的分片包后才把数据返回给recv里的buf么？而且buf长度是足够接收的啊？多次接收的这个我理解是recv中设置的buf长度不够，所以需要循环多次接收，不知道我这么理解问题在哪 通道流一般是有缓存的，它会等到缓存满了就往buf送，这个缓存不一定就是4096（也就是不一定会等到4096才往buf送），所以正确的做法就是循环接收，因为你不能保证一次就接收完整。[/quote]  我还想再请教您一个问题  我的虚拟机开了3个系统，分别运行了10个客户端，一个中继转发，10个服务器，1个客户端通过中继连接1个服务器，我让服务器同时开始传输200KB的文件，大小分成4096字节的数据块，发送间隔35ms 我的中继上传和下载带宽都设置的是1MiB/S，客户端和服务器的带宽设置的是不限制，虚拟机之间延迟为0,但是我在中继用wireshark抓包发现他的上传和下载每秒的峰值只有0.5MiB，请问这个为什么不是1MiB?

user: user-0
content: 引用 10 楼 轻箬笠 的回复:[quote=引用 6 楼 beastsam 的回复:] [quote=引用 4 楼 轻箬笠 的回复:] recv和send的处理方式不太一样。一般我们都是循环接收的，以保证数据的完整性。所以通行的办法是弄个固定长度的报文头，报文头中带报文长度数据，然后循环接收，直到长度满足要求为止。最简单的报文头就是，前4个字节（即int）就代表了报文的长度。  这个难道不是应该是tcp层处理的么？我理解tcp分片，但是不应该是系统接收完所有的4096分片后才把数据返回给recv里的buf么？而且我看很多教程说循环接受是为了防止发送的数据超过recv里buf的长度，但是我这个并没有超过啊？[/quote] 这个还真不是，曾经在项目中碰到过，发送几百个字节，第一次接收只有几十个字节的情况。[/quote]  这样啊，好吧，谢谢您，我还有个关于带宽的问题不知道您了解么？ 我的虚拟机开了3个系统，分别运行了10个客户端，一个中继转发，10个服务器，1个客户端通过中继连接1个服务器，我让服务器同时开始传输200KB的文件，大小分成4096的数据块，发送间隔35ms 我的中继上传和下载带宽都设置的是1MiB/S，虚拟机之间延迟为0,但是我在中继用wireshark抓包发现他的上传和下载每秒的峰值只有0.5MiB，请问这个为什么不是1MiB?

user: user-3
content: 引用 6 楼 beastsam 的回复:[quote=引用 4 楼 轻箬笠 的回复:] recv和send的处理方式不太一样。一般我们都是循环接收的，以保证数据的完整性。所以通行的办法是弄个固定长度的报文头，报文头中带报文长度数据，然后循环接收，直到长度满足要求为止。最简单的报文头就是，前4个字节（即int）就代表了报文的长度。  这个难道不是应该是tcp层处理的么？我理解tcp分片，但是不应该是系统接收完所有的4096分片后才把数据返回给recv里的buf么？而且我看很多教程说循环接受是为了防止发送的数据超过recv里buf的长度，但是我这个并没有超过啊？[/quote] 这个还真不是，曾经在项目中碰到过，发送几百个字节，第一次接收只有几十个字节的情况。

user: user-0
content: 引用 8 楼 qybao 的回复:[quote=引用 5 楼 beastsam 的回复:] TCP分片这个我知道，但是按理来说recv的工作原理难道不是等接收够4096所有的分片包后才把数据返回给recv里的buf么？而且buf长度是足够接收的啊？多次接收的这个我理解是recv中设置的buf长度不够，所以需要循环多次接收，不知道我这么理解问题在哪 通道流一般是有缓存的，它会等到缓存满了就往buf送，这个缓存不一定就是4096（也就是不一定会等到4096才往buf送），所以正确的做法就是循环接收，因为你不能保证一次就接收完整。[/quote]  您说的应该没错，因为当我把虚拟机的通信延迟设置成0之后，就没问题了，看来还即使recv的buf足够，但还是需要循环接收。

user: user-2
content: 引用 5 楼 beastsam 的回复:TCP分片这个我知道，但是按理来说recv的工作原理难道不是等接收够4096所有的分片包后才把数据返回给recv里的buf么？而且buf长度是足够接收的啊？多次接收的这个我理解是recv中设置的buf长度不够，所以需要循环多次接收，不知道我这么理解问题在哪 通道流一般是有缓存的，它会等到缓存满了就往buf送，这个缓存不一定就是4096（也就是不一定会等到4096才往buf送），所以正确的做法就是循环接收，因为你不能保证一次就接收完整。

user: user-0
content: 引用 3 楼 xian_wwq 的回复:tcp是基于流的，不是发100，就一定收100 有可能收了95个，然后又收了5 和网络状况没有直接关联， 所以tcp数据接收，进行“拼包”（一次发送多次接收）、“分包”（多次发送一次接收）是基本操作。  对啊，但是tcp难道不是应该在底层等待接收完所有的4096分片的包之后才把数据返回给recv里的buf么？

user: user-0
content: 引用 4 楼 轻箬笠 的回复:recv和send的处理方式不太一样。一般我们都是循环接收的，以保证数据的完整性。所以通行的办法是弄个固定长度的报文头，报文头中带报文长度数据，然后循环接收，直到长度满足要求为止。最简单的报文头就是，前4个字节（即int）就代表了报文的长度。  这个难道不是应该是tcp层处理的么？我理解tcp分片，但是不应该是系统接收完所有的4096分片后才把数据返回给recv里的buf么？而且我看很多教程说循环接受是为了防止发送的数据超过recv里buf的长度，但是我这个并没有超过啊？

user: user-0
content: 引用 1 楼 qybao 的回复:一个包不一定能送完数据，可能送多个包 所以你应该用循环接收，直到byte_num为-1才算接受完。每次接收到的数据自己保存，最后再拼装成一个完整的数据 int byte_num = 0, offset = 0； char data[4096] = {0}; while(byte_num != -1) { //多次接收直到没有数据     byte_num = recv(server_sock_fd, buf_rec, 4096, 0);     memcpy(data+offset, buf_rec, byte_num); //把每次接收的数据保存     offset = byte_num; }  TCP分片这个我知道，但是按理来说recv的工作原理难道不是等接收够4096所有的分片包后才把数据返回给recv里的buf么？而且buf长度是足够接收的啊？多次接收的这个我理解是recv中设置的buf长度不够，所以需要循环多次接收，不知道我这么理解问题在哪

user: user-3
content: recv和send的处理方式不太一样。一般我们都是循环接收的，以保证数据的完整性。所以通行的办法是弄个固定长度的报文头，报文头中带报文长度数据，然后循环接收，直到长度满足要求为止。最简单的报文头就是，前4个字节（即int）就代表了报文的长度。