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

ss命令确实表明应用程序已经在监听绑定端口.

我知道我已经调用了listen(),因此应用程序将监听绑定的端口.但根据同样的语义,应该在服务器接受连接之前调用accept().

在listen()手册页面中,它写道(Italian是我的):

listen()将sockph引用的插槽标记为被动插槽,即socket that will be used to accept incoming connection requests using accept(2).

而accept()手册页上写道:

它提取监听插座的前connection request on the queue of pending connections

由此可以理解,在建立连接之前应该调用accept().

我在这里错过了什么?如果这是标准行为,我可以被指出给主要来源吗?或者只是具体实施?

下面是我正在使用的代码.如果我在调用listen()之前停止执行它,使用netcat会显示发送的SEN会被一个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;
}

推荐答案

要listen()的"backlog"integer参数(您指定5的参数)确定可以接受多少个连接,达到该限制后,将忽略或拒绝新的SY will.

它允许这些连接排队,例如在单线程服务器中排队,当BDS sockets API最初设计时可能会找到该服务器(如果我的历史记录正确的话,它早于线程).服务器可能必须在接受()下一个客户端之前fork(),或者如果请求是简单的协议(例如基本Whois或QotD服务器),它甚至可能决定在到达下一个客户端之前立即在同一线程中服务请求.

如果服务器根本没有响应,客户端将很快达到连接超时;但一旦建立连接,超时可能会更长(例如,RTP定义了问候语之前的超时时间为five minutes).话虽如此,我不知道在创建此API时什么样的延迟是"正常的",所以这其中存在一些猜测.

C++相关问答推荐

char为16位且Short也为16位的c环境合法吗

为什么这个C程序代码会产生以下结果?

getchar读css + z还是返回css?

VS代码C/C++扩展intellisense无法检测环境特定函数'

如何在Visual Studio代码中关闭此函数名称显示功能?

显式地将值转换为它从函数返回的类型的含义是什么?

带有sigLongjMP中断I/O的异常处理程序

为什么数组的最后一个元素丢失了?

为什么未初始化的 struct 的数组从另一个数组获取值?

Printf()在C中打印终止字符之后的字符,我该如何解决这个问题?

某些EAX值的不同调用方的CPUID结果不一致

向左移位3如何得到以字节为单位的位数?

共享目标代码似乎不能在Linux上的进程之间共享

强制GCC始终加载常量(即只读),即使启用了优化

用C++初始化局部数组变量

C语言中的指针和多维数组

在列表中查找素数

C/C++编译器可以在编译过程中通过按引用传递来优化按值传递吗?

子进程不会修改父进程中的统计信息

文件指针引起的C程序分段错误