为什么断开的网络连接会导致标准输入出现 EOF?
Why does a broken network connection cause an EOF on stdin?
我有一个简单的服务器,它在一个单独的线程中等待网络连接,然后定期向客户端发送信息。主线程通过标准输入接受命令。我不明白的是为什么 stdin 在客户端终止时收到 EOF。
对于下面的示例代码,客户端可以像命令行中的'nc 127.0.0.1 1234'一样简单。当客户端被 'kill' 或 Ctl-C 中断时,服务器会由于标准输入上的 EOF 而退出。我当然很感激对此行为的解释以及使服务器保持运行的解决方法。
static void *WaitForConnections(void *p) {
int sockfd, newsockfd;
struct sockaddr_in server = { sizeof(server), AF_INET, htons(1234), INADDR_ANY};
if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket call failed");
exit(1);
}
if ( bind(sockfd, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) == -1){
perror("bind call failed");
exit(1);
}
if ( listen(sockfd, 0) == -1 ) {
perror("listen call failed");
exit(1);
}
for (;;) {
if ( (newsockfd = accept(sockfd, NULL, NULL)) != -1) { // new connection
for ( ;;) {
char c = 'd';
if (send(newsockfd, &c, sizeof(c), 0) != sizeof(c)) {
break;
}
sleep(1);
}
close(newsockfd);
}
else {
break;
}
}
close(sockfd);
return NULL;
}
int main(int argc, const char * argv[]) {
pthread_attr_t attr;
pthread_t p;
void * status;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
if (0 != pthread_create( &p, &attr, WaitForConnections, NULL )) {
fprintf(stderr, "thread creation failed\n");
exit(1);
}
while (getchar() != EOF) {}
pthread_join(p, &status);
return 0;
}
没关系,但这是在 MacOS X 10.10.1、Xcode 6.1.1 和 Apple LLVM 6.0 下。
您的服务器不会因为标准输入上的 EOF 而退出,它会退出是因为它试图在断开的 TCP 连接上发送数据,这会导致 SIGPIPE 信号被传送 - SIGPIPE 的默认操作是终止过程。
你应该忽略 SIGPIPE
signal(SIGPIPE,SIG_IGN);
这将导致 send()/write() 调用改为 return -1 并将 errno 设置为您的代码可以处理的 EPIPE。
我有一个简单的服务器,它在一个单独的线程中等待网络连接,然后定期向客户端发送信息。主线程通过标准输入接受命令。我不明白的是为什么 stdin 在客户端终止时收到 EOF。
对于下面的示例代码,客户端可以像命令行中的'nc 127.0.0.1 1234'一样简单。当客户端被 'kill' 或 Ctl-C 中断时,服务器会由于标准输入上的 EOF 而退出。我当然很感激对此行为的解释以及使服务器保持运行的解决方法。
static void *WaitForConnections(void *p) {
int sockfd, newsockfd;
struct sockaddr_in server = { sizeof(server), AF_INET, htons(1234), INADDR_ANY};
if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket call failed");
exit(1);
}
if ( bind(sockfd, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) == -1){
perror("bind call failed");
exit(1);
}
if ( listen(sockfd, 0) == -1 ) {
perror("listen call failed");
exit(1);
}
for (;;) {
if ( (newsockfd = accept(sockfd, NULL, NULL)) != -1) { // new connection
for ( ;;) {
char c = 'd';
if (send(newsockfd, &c, sizeof(c), 0) != sizeof(c)) {
break;
}
sleep(1);
}
close(newsockfd);
}
else {
break;
}
}
close(sockfd);
return NULL;
}
int main(int argc, const char * argv[]) {
pthread_attr_t attr;
pthread_t p;
void * status;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
if (0 != pthread_create( &p, &attr, WaitForConnections, NULL )) {
fprintf(stderr, "thread creation failed\n");
exit(1);
}
while (getchar() != EOF) {}
pthread_join(p, &status);
return 0;
}
没关系,但这是在 MacOS X 10.10.1、Xcode 6.1.1 和 Apple LLVM 6.0 下。
您的服务器不会因为标准输入上的 EOF 而退出,它会退出是因为它试图在断开的 TCP 连接上发送数据,这会导致 SIGPIPE 信号被传送 - SIGPIPE 的默认操作是终止过程。
你应该忽略 SIGPIPE
signal(SIGPIPE,SIG_IGN);
这将导致 send()/write() 调用改为 return -1 并将 errno 设置为您的代码可以处理的 EPIPE。