Почему Listen() (до вызова Accept()) достаточно, чтобы приложение завершило трехстороннее рукопожатие?Linux

Ответить Пред. темаСлед. тема
Anonymous
 Почему Listen() (до вызова Accept()) достаточно, чтобы приложение завершило трехстороннее рукопожатие?

Сообщение Anonymous »

Я занимаюсь отладкой очень простого TCP-сервера на языке C в Linux. Я остановил выполнение прямо перед строкой, в которой вызывается метод Accept(). К моему удивлению, когда клиент отправляет SYN, tcpdump показывает, что сервер отвечает SYN-ACK (на который сразу же приходит окончательный ответ от клиента).
Команда ss действительно показывает, что приложение уже прослушивает связанный порт.
Я понимаю, что я уже вызвал метод Listen(), поэтому приложение будет прослушивать связанный порт. Но тогда, согласно той же семантике, метод Accept() должен вызываться до того, как сервер сможет принять соединение.
На страницах руководства Listen() он читает (курсив мой):

listen() помечает сокет, на который указывает sockfd, как пассивный сокет, то есть как сокет, который будет использоваться для приема входящего соединения. запросы с использованием Accept(2).

Хотя на странице руководства Accept() написано:

Он извлекает первый запрос на соединение из очереди ожидающих соединений для прослушивающего сокета

Из то можно было понять, что Accept() следует вызывать до того, как соединение будет установлено.
Что мне здесь не хватает? Если это стандартное поведение, можно ли мне указать на первоисточник? Или это просто особенность реализации?
Ниже приведен код, который я использую. Если я остановлю его выполнение прямо перед вызовом Listen(), использование netcat покажет, что на отправленный SYN отвечает RST. Но если я сделаю то же самое после выполнения Listen(), tcpdump покажет, что сервер отвечает SYN-ACK.
#include
#include
#include

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;
}


Подробнее здесь: https://stackoverflow.com/questions/783 ... to-complet
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Linux»