为什么listen()(在调用accept()之前)足以让应用程序完成3次握手?

问题描述 投票:0回答:1

我正在 Linux 上用 C 语言调试一个非常基本的 tcp 服务器。我在调用 Accept() 的行之前停止了执行。令我惊讶的是,当客户端发送 SYN 时,tcpdump 显示服务器使用 SYN-ACK 进行响应(客户端很容易用最终 ACK 进行回复)。

ss 命令确实显示应用程序已经在监听绑定的端口。

我知道我已经调用了listen(),所以应用程序将监听绑定的端口。但是,按照相同的语义,应该在服务器接受连接之前调用accept()。

在listen()手册页中它读到(斜体是我的):

listen() 将 sockfd 引用的套接字标记为被动套接字,即,作为将用于使用accept(2)接受传入连接请求的套接字

虽然accept()手册页说:

它提取监听套接字的待处理连接队列中的第一个

连接请求

由此可知,应该在建立连接之前调用accept()。

我在这里缺少什么?如果这是标准行为,是否可以向我指出主要来源?或者只是具体实现?

下面是我正在使用的代码。如果我在调用listen()之前停止其执行,则使用netcat会显示发送的SYN并用RST进行回复。但是如果我在执行listen()后执行相同的操作,tcpdump将显示服务器用SYN-ACK进行回复。

#include <unistd.h> #include <stdio.h> #include <sys/wait.h> void error(const char* message) { printf("%s %s\n", message, strerror(errno)); } int main(int argc, char** argv) { const int sockfd = socket(AF_INET, SOCK_STREAM, 0); if ( sockfd == -1 ) { error("Socket error:"); return 1; } struct sockaddr_in servaddr; memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(12345); servaddr.sin_addr.s_addr = htonl(INADDR_ANY); if ( bind(sockfd, (struct sockaddr*) &servaddr, sizeof(servaddr)) == - 1 ) { error("Bind error:"); return 1; } if ( listen(sockfd, 5) == -1 ) { error("Listen error: "); return 1; } printf("Ready.\n"); struct sockaddr_in cliaddr; socklen_t cliaddrlen = sizeof(cliaddr); char response[512]; while (1) { const int connfd = accept(sockfd, (struct sockaddr*) &cliaddr, &cliaddrlen); if ( connfd == -1 ) { printf("Accept error: %s\n", strerror(errno)); return 1; } const pid_t pid = fork(); if ( pid == -1 ) { printf("Fork error: %s\n", strerror(errno)); continue; } if ( pid == 0 ) { close(sockfd); char buffer[16]; inet_ntop(AF_INET, &cliaddr.sin_addr, buffer, 16); printf("Connection from %s accepted.\n", buffer); while ( 1 ) { int nread = read(connfd, response, 512); if ( nread == -1 ) { printf("%s\n", strerror(errno)); } if (nread == 1 && response[0] == '\n') { break; } write(connfd, response, nread); //write(STDIN_FILENO, response, nread); } printf("Good bye!\n"); close(connfd); return 0; } close(connfd); wait(NULL); } return 0; }


linux unix tcp c sockets
1个回答
0
投票

如果服务器根本没有响应,客户端很快就会达到连接超时;但一旦建立连接,超时可能会更长(例如,SMTP 定义超时为

五分钟

,直到出现问候语)。话虽这么说,我不知道在创建此 API 时什么样的延迟是“正常”的,因此对此有一些猜测。 listen() 的“backlog”整数参数决定了可以接受多少个连接;达到该限制后,新的 SYN

被忽略或拒绝。

© www.soinside.com 2019 - 2024. All rights reserved.