我正在编写一个函数来从套接字接收数据,将其存储在缓冲区中返回我读取的字节数和其他一些检查,我几天无法调试它。
单元测试:
#define BUFFSIZE 2
void
test_handle_read_socket() {
/* Arrangement */
struct conn sender;
int sockfd[2];
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd) == -1) {
perror("Failed creating pair sockets.");
return;
}
// int flags = fcntl(sockfd[0], F_GETFL, 0);
// fcntl(sockfd[0], F_SETFL, flags | O_NONBLOCK);
// write "123" to the pipe.
sender.pfd.fd = sockfd[0];
send(sockfd[1], "123", 3, 0);
eqint(2, handle_read_socket(&sender));
eqnstr("12", sender.client_buff, 2);
eqint(1, handle_read_socket(&sender)); // Tag: The problem, return -1 instead of 1
eqnstr("3", sender.client_buff, 1);
/* Teardown */
close(sockfd[1]);
close(sockfd[0]);
}
实施:
struct conn {
struct pollfd pfd;
struct sockaddr_in client_addr;
char client_buff[BUFFSIZE];
char server_buff[BUFFSIZE];
};
int
handle_read_socket(struct conn *client) {
int total_read = 0;
int readsize = 0;
while (1) {
readsize = recv(client->pfd.fd, client->client_buff + total_read,
BUFFSIZE - total_read, 0);
if (readsize > 0) {
total_read += readsize;
if (total_read == BUFFSIZE) {
// Buffer is full.
break;
}
} else if (readsize == 0) {
// client closed connection.
if (errno == EOF) {
return -1;
}
else {
// An error happened.
LOG_ERROR("Something unpredictable happened.");
return -1;
}
} else {
// Client has no data(non blocking).
if (errno == EAGAIN || errno == EWOULDBLOCK) {
break;
}
// An error happened.
LOG_ERROR("Could not read from client and Error happened.")
return -1;
}
}
return total_read;
}
当它第一次循环时(单元测试中的标签)recv()返回1,这是正确的,但缓冲区中的字符“3”,但第二次recv()返回-1并将errno设置为22,这是我的问题。 (将文件描述符设置为非阻塞模式不起作用。)
我相信你的问题就在这里:
} else if (readsize == 0) {
// client closed connection.
if (errno == EOF) {
return -1;
}
特别是,第二次调用
handle_read_socket()
时,会调用recv()
,recv()
会返回1
;然后handle_read_socket()
将再次调用recv()
(因为total_read < BUFFSIZE
),这次recv()
将返回0
(因为服务器在发送所有三个字节后已关闭TCP连接),这会导致上面的代码无济于事地返回 -1,即使它已经读取了一个字节的有效数据。
作为修复,您可以将代码更改为类似这样的内容:
} else if (readsize == 0) {
// client closed connection.
if (errno == EOF) {
return (total_read > 0) ? total_read : -1;
}
...这样,读取一些有效数据的事实将如您所期望的那样反映在返回值中。 如果第三次调用
handle_read_socket()
,则 recv()
将在第一次尝试时返回 0
,此时将返回 -1
以指示出现问题。