Сокет TCP-сервера не прослушивается методом addrinfo

#c #sockets #server #tcp

Вопрос:

Итак, вот код, код успешно компилируется…

 #include <stdio.h> // for printf
#include <linux/if_tun.h> //for IFF_TUN
#include <sys/socket.h> //socket, struct sockaddr_in
#include <fcntl.h> // for O_RDWR macros
#include <string.h> //for strcpy
#include <unistd.h> //for read();
#include <netdb.h> //for struct sockaddr
#include <net/if.h> //struct ifreq and IFNAMSIZ and other macros
#include <errno.h>
#include <stdlib.h>

// _check: error handler
static int _check(int retval, const char *msg)
{
    if(retval == -1)
    {
        fprintf(stderr, "%s: %sn", msg, strerror(errno));
        exit(EXIT_FAILURE);
    }
    return retval;
}


int tcp_listen_sock(int listen_connection)
{
    /*-------------------------socket-----------------------*/
    int sock, tcp_sock;
    struct addrinfo hints, *resu<
    struct sockaddr *addrin;

    memset(amp;hints ,0 , sizeof(hints));
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    const char *host;

    host = "0.0.0.0";

    _check(getaddrinfo(host, NULL, amp;hints, amp;result), "getaddrinfo");

    if (result->ai_family == AF_INET)
    ((struct sockaddr_in *)result->ai_addr)->sin_port = htons(5678);
  else if (result->ai_family == AF_INET6)
    ((struct sockaddr_in6 *)result->ai_addr)->sin6_port = htons(5678);
  else {
    fprintf(stderr, "unknown ai_family %d", result->ai_family);
    freeaddrinfo(result);
    return -1;
  }
    memcpy(addrin, result->ai_addr, result->ai_addrlen);
//  *client_len = result->ai_addrlen;

    _check((sock = socket(AF_INET, SOCK_STREAM, 0)), "socket");
    
    struct ifreq ifr;

    memset(amp;ifr, 0, sizeof(ifr));
    snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "enp0s3");
    _check(setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, (void *)amp;ifr, sizeof(ifr)), "setsockopt");

    int flags;
    if((flags = fcntl(sock, F_GETFL)) != -1)
    {
        fcntl(sock, F_SETFL, flags | O_NONBLOCK);
    }
    else
    perror("socket fcntl");

            _check(bind(sock,result->ai_addr, result->ai_addrlen), "tcp bind");


    int len = sizeof(struct sockaddr);
    _check(listen(sock, listen_connection), "listen");
    tcp_sock = accept(sock, result->ai_addr, amp;result->ai_addrlen );
    
    printf("now listening on tcp!n");
    
    return tcp_sock;
    
}

int main(int argc, char **argv)
{
    printf("Starting programn");
    int tcp = tcp_listen_sock(5);
   printf("ending programn");
    return 0;
}
 

и ,

выход

 Starting program
now listening on tcp!
ending program
 

но сокет сервера на самом деле не слушает…

ожидаемый результат:

 Starting program
now listening on tcp!
read...
write...
read...
write...
read...
write..
 

Я не могу понять, чего мне не хватает, я знаю, что еще не реализовал чтение, запись, но я сделаю это после того, как сокет сервера, кажется, будет работать нормально и правильно прослушиваться.

ПРИМЕЧАНИЕ: Я делаю это в linux (в частности, в ubuntu)

Любая помощь будет оценена по достоинству…

Комментарии:

1. Как ты думаешь ((struct sockaddr_in *)result->ai_addr)->sin_port = htons(5678); , что на самом деле происходит? Вы отбрасываете ai_addr элемент , возвращенный из getaddrinfo() в struct sockaddr_in , пытаясь изменить его?!?!?

2. result Переменная заполняется функцией getaddrinfo . Переменная выделена вами, и вы можете изменить ее, если хотите. Но указатели в этой переменной указывают на места, которые вам не принадлежат. Вы не должны пытаться изменить его. Скопируйте addrin и обновите номер порта в ваших собственных данных.

3. Я ценю ваши ответы, ребята.. но после того, как я почесал в затылке, я сделал перерыв и прочитал код, отследив код еще раз, так что я обнаружил, что забыл обработку ошибок «принять»… да, глупый я… но после этого я обнаружил, что accept возвращал ошибку из-за fcntl… после удаления он работает нормально…

4. итак, может ли кто-нибудь подсказать мне, что мне делать.. как я решил этот вопрос, так должен ли я удалить этот вопрос или опубликовать свое решение?

5. Если вы хотите назначить номера портов getaddrinfo() возвращаемому списку, то вам следует передать номер порта getaddrinfo() в его 2-м параметре, т. Е.: getaddrinfo(host, "5678", amp;hints, amp;result) . Затем он проанализирует и скопирует это значение в результирующее sockaddr значение s для вас.

Ответ №1:

Вызов getaddrinfo для инициализации сокета локального списка кажется излишним.

Начните с этого. Это простой пример кода «создайте сокет для прослушивания и дождитесь входящего TCP-соединения».

 int tcp_socket_listen(int listen_connection)
{
     struct sockaddr_in addr = {0};
     sockaddr_in addrRemote = {0};
     socklen_t sizeRemote = 0;
     int tcp_socket = -1;

     s = socket(AF_INET, SOCK_STREAM, 0);
     _check(s, "socket");

     addr.sin_family = AF_INET;
     addr.sin_port = htons(5678);
     _check(bind(s, (sockaddr*)amp;addr, sizeof(addr)), "bind");

     _check(listen(sock, listen_connection), "listen");

     sizeRemote = sizeof(addrRemote);
     tcp_sock = accept(s, (sockaddr*)amp;addrRemote, amp;sizeRemote);

     _check(tcp_sock, "accept");

     printf("now listening on TCPn");

     return tcp_sock;
}
 

Теперь, если вы хотите привязаться к определенному адаптеру (например, «enp0s3») вместо стандартного («все адаптеры») или вам нужна поддержка IPV6, вы можете ознакомиться с моим примером кода на github здесь GetSocketAddressForAdapter и использовать этот адрес для bind вызова вместо addr адреса по умолчанию выше. Это C , но вы, вероятно, можете перенести его на прямой C с небольшой работой.

Комментарии:

1. Спасибо за вашу помощь, я ценю это, но я хочу сделать именно так, потому что у меня тоже есть другие вещи, с которыми можно легко справиться таким образом… и да, я решил это, поэтому, пожалуйста, проверьте мой комментарий.. в чем была ошибка.