在使用TCP套接字时,C send
函数是否可能返回零?手册只说它会返回发送的字节数,但我不确定当无法发送任何数据时它是否只会返回 -1。
在使用TCP套接字时,C send
函数是否可能返回零?手册只说它会返回发送的字节数,但我不确定当无法发送任何数据时它是否只会返回 -1。
我十分肯定,尽管这个记忆已经深深埋在时间的迷雾中,我以前曾经遇到过它返回零的情况,当时是在传输大量数据的情况下,对端无法跟上的情况下。
根据我的记忆,在那种情况下,远端TCP堆栈缓冲区已经填满,堆栈通知本地端必须等待一些空间腾出来,然而本地缓冲区也随之填满了。
此时,虽然技术上不算错误(因此没有返回-1),但本地堆栈无法接受任何数据。
我不太确定现在是否还是这种情况,因为当前的Posix标准似乎表明会在这种情况下阻塞(或者如果设置了非阻塞则会失败)。
但是,我认为这已经不重要了。你有可能会收到少于所请求发送字节数的数据,因此你应该有相应的代码来处理这种情况。
而且,既然处理“比请求的少一个字节”和处理“零字节”的逻辑基本相同,你也可以假定它会返回0。
有时候你传递的字节数为零,这种情况下,“返回发送的字节数”会指示应该返回零字节。
最好还是正确处理返回零的情况;这不会有害,但可能会有帮助。
send
在你使用 send(socket, buf, 0, 0)
时返回 0。
我想提供简单的代码供其他人测试。
在一个终端中:
nc -l localhost 10086
在另一个终端中:
#include <cstdio>
#include <cstdlib>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
int create_socket()
{
addrinfo hints = {};
addrinfo* servinfo;
int sockfd = -1;
int rv;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = 0;
if ((rv = getaddrinfo("localhost", "10086", &hints, &servinfo)))
{
printf("getaddrinfo failed: %s\n", gai_strerror(rv));
exit(1);
}
for(auto p = servinfo; p; p = p->ai_next)
{
if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1)
{
perror("socket");
continue;
}
else
{
if(connect(sockfd, p->ai_addr, p->ai_addrlen) == -1)
{
close(sockfd);
perror("connect");
continue;
}
else
puts("client: connected");
}
break;
}
freeaddrinfo(servinfo);
return sockfd;
}
void client()
{
int socket = create_socket();
if(socket == -1)
{
puts("no good");
exit(1);
}
char buf[100] = {0};
while(1){
int ret = send(socket, buf, 0, 0);
if (ret == 0){
printf(".");
}else{
printf("xxxxxxx\n");
}
}
}
int main()
{
setvbuf(stdout, NULL, _IONBF, 0);
client();
return 0;
}
g++ -g -Wall -o send_zero_bytes send_zero_bytes.cpp
./send_zero_bytes
AF_UNIX
类型的套接字上从send(2)
返回了零值。size
字段引起的。