考虑下面的基本客户端和服务器程序(只是简单的 / 来说明我的问题)。客户端启动与服务器的连接,提示用户输入一条消息,然后将其发送到服务器并打印到屏幕上。
如果我在循环中间突然退出客户端程序(例如通过关闭终端窗口),有时客户端会继续循环循环一段时间(即最后一条消息发送到服务器/当前驻留在客户端关闭时的写入缓冲区会重复发送到服务器,通常直到循环耗尽)。然而,其他时候,服务器上的 read() 调用正确返回 0,并且连接没有问题地关闭(行为似乎相当随机)。
我不太明白这里发生了什么。首先,为什么程序关闭后会发生额外的循环迭代?终端窗口关闭和实际进程本身结束之间是否只有延迟时间?即使确实发生了额外的循环迭代,对 fgets() 的调用是否应该在用户输入消息之前阻塞?
我正在使用带有 XFCE 桌面的 Fedora 25 工作站。
我尝试搜索有关此的信息,但运气不佳(我不确定如何以简洁的方式搜索此信息)。任何帮助深表感谢。
谢谢
客户:
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <sys/socket.h>
#include <unistd.h>
int main(void) {
int sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(3000);
inet_pton(AF_INET, "127.0.0.1", &server.sin_addr);
connect(sockfd, (struct sockaddr *)&server, sizeof(server));
int i;
for (i = 0; i < 20; i++) {
char buf[512];
printf("Send a message: ");
fgets(buf, 512, stdin);
write(sockfd, buf, sizeof(buf));
}
close(sockfd);
}
服务器:
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <sys/socket.h>
#include <unistd.h>
int main(void) {
int listenfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(3000);
inet_pton(AF_INET, "127.0.0.1", &server.sin_addr);
bind(listenfd, (struct sockaddr *)&server, sizeof(server));
listen(listenfd, 10);
printf("Listening...\n");
struct sockaddr_in client;
socklen_t client_size = sizeof(client);
int clientfd = accept(listenfd, (struct sockaddr *)&client, &client_size);
for (;;) {
char buf[512];
int i = read(clientfd, buf, sizeof(buf));
if (i == 0) {
close(clientfd);
printf("Connection Closed\n");
break;
} else {
printf("%s", buf);
}
}
close(listenfd);
}