关于TCP通信中,recv函数接收数据大小的问题,之前一直觉得,只要是客户端与服务器一发一收的模式,那么recv接收的数据大小一定是函数中指定的数据大小。这次写了客户端与服务器通信的程序,在这上面栽了一个大跟斗。
程序功能如下:通过客户端与服务器的通信,实现文件的传输,客户端每次发送1k的数据,服务器每次接收1k大小数据并将数据存储到文件中,就这样一发一收的循环发送接收,实现了文件的拷贝。
但在实际的测试中,发现不能实现文件的拷贝,因为对每个1k大小的发送包都编了序号,发现在传输的过程出现了错误,但TCP是的宗旨是可靠传输,这就相互矛盾了。为此我到网上去搜索相关信息,看广大网友对此的看法以及解决方法。在网上搜索的信息不多,只发现一个解决该问题方法,那就是让服务器sleep一秒,我将服务器睡眠一秒后运行,发现是能够解决一点问题,但只能将错误的概率减少,不能彻底解决问题。
既然网上暂时没有找到解决方法,我只能够自己慢慢测试了。因为之前觉得TCP的可靠带着recv一起可靠了所以没有对返回值进行判断,现在加上对返回值的判断,发现
错误传输时,recv返回值只有几百K(所以说一定一定要对函数返回值进行判断,这样能减少程序BUG,也能更加快速找到问题所在),发现问题所在了。
原来当recv去接收时,内核只传送了几百k到用户空间,并没有传送1k(至于为什么会这样,我就不得知道了,没有去深究),这样我对返回值进行判断,等于指定值时,就接着循环接收,少于指定值时,多加一个循环结束,直到将1K全部接收为止,这样就完美的解决了,部分代码如下
while (1)
{
memset(&recv_buf, 0, sizeof(DATA));
recv_back = recv(client_fd, &recv_buf, sizeof(DATA), 0);
if ((0 == recv_back) || (recv_back < 0))
{
perror("fail to recv");
break;
}
#if 1
/* 判断数据是否接收完整 */
if (recv_back < sizeof(DATA))
{
remain_data_size = 1036 - recv_back; // 剩余数据长度
while (1)
{
printf("recv_back = %d\n", recv_back);
memset(data_buf, 0, sizeof(data_buf));
recv_back = recv(client_fd, data_buf, remain_data_size, 0);
printf("recv_back = %d\n", recv_back);
if ((0 == recv_back) || (recv_back < 0))
{
perror("fail to recv");
break;
}
m = 1036 - remain_data_size - 4; // m为上一次接收得数据量 - 4
for (n = 0; n < remain_data_size; n++)
{
k = m + n;
if (k > 1023 && k < 1028) // size
{
//printf("size data_buf[%d] = %d\n", n, data_buf[n]);
recv_buf.size = recv_buf.size + (data_buf[n] << ((k - 1024) * 8));
}
else if (k >= 1028) // num
{
//printf("num data_buf[%d] = %d\n", n, data_buf[n]);
recv_buf.num = recv_buf.num + (data_buf[n] << ((k - 1028) * 8));
}
else
{
recv_buf.data[k] = data_buf[n];
}
}
/* 当两个值相等时,代表数据接收完毕 */
if (recv_back == remain_data_size)
{
printf("size = %d num = %d\n", recv_buf.size, recv_buf.num);
break;
}
remain_data_size = 1036 - recv_back - remain_data_size;
}
}
}
因为一直没有对返回值进行判断,这个问题困扰了我好久,,所以再次劝解各位(包括我自己),一定要对函数返回值进行判断。