Многопоточное программирование клиент-серверных сокетов на C

#c #sockets #tcp-ip #lwip

#c #сокеты #tcp #lwip

Вопрос:

Я реализую многопоточное программирование сокетов клиент-сервер на C на одном компьютере с одним и тем же IP-адресом, но с разными портами для клиента и сервера. Я реализовал это, используя концепции pthread в среде C. Но я вижу, что запущен только мой клиентский поток, тогда как мой серверный поток остановился, как только он достиг процедуры ‘accept ()’. Мне интересно, в чем может быть проблема. Если кто-нибудь сможет выяснить, где я допускаю ошибку, это было бы действительно полезно

Мой КЛИЕНТСКИЙ код выглядит следующим образом:

 void *client_connect(void *arg)
{

   int client_socket;
   struct sockaddr_in Serv_Addr;
   struct sockaddr_in Client_Addr;
   int addrlen=sizeof(Client_Addr);

   char send_buffer_client[] = {"server message"};
   char recv_buffer_client[1024];
   int nbytes;

   client_socket = lwip_socket(AF_INET, SOCK_STREAM, 0);
   if (client_socket < 0) ;

   memset((char *)amp;Serv_Addr, 0, sizeof(Serv_Addr));
   Serv_Addr.sin_family = AF_INET;
   Serv_Addr.sin_len = sizeof(Serv_Addr);
   Serv_Addr.sin_addr.s_addr = inet_addr("1.2.3.4");
   Serv_Addr.sin_port = 9999;
   memset((char *)amp;Client_Addr, 0, sizeof(Client_Addr));
   Client_Addr.sin_family = AF_INET;
   Client_Addr.sin_len = sizeof(Client_Addr);
   Client_Addr.sin_addr.s_addr = inet_addr("1.2.3.4");
   Client_Addr.sin_port = 5555;

   lwip_connect(client_socket, (struct sockaddr *)amp;Serv_Addr, sizeof(Serv_Addr));

   while (1) {

               do{
                   nbytes = lwip_recv(client_socket, recv_buffer_client, sizeof(recv_buffer_client),0);
                   if (nbytes>0) lwip_send(client_socket, send_buffer_client, sizeof(send_buffer_client), 0);

                   printf("server message = %sn", recv_buffer_client);
               }  while (nbytes>0);

               sleep(10);

       }
       lwip_close(client_socket);
}
  

Мой СЕРВЕРНЫЙ код:

 void *server_connect(void *arg)
{

   int server_socket;
   struct sockaddr_in Serv_Addr;
   struct sockaddr_in Client_Addr;
   int addrlen=sizeof(Client_Addr);
   int clientfd;
   char send_buffer[] = {"Server message"};
   char recv_buffer[1024];
   int nbytes_server, client_length;

   server_socket = lwip_socket(AF_INET, SOCK_STREAM, 0);
   if (server_socket < 0)
   printf("could not create server socket");
   else
   printf("created SERVER socket");

   memset((char *)amp;Serv_Addr, 0, sizeof(Serv_Addr));
   Serv_Addr.sin_family = AF_INET;
   Serv_Addr.sin_len = sizeof(Serv_Addr);
   Serv_Addr.sin_addr.s_addr = inet_addr("1.2.3.4");
   Serv_Addr.sin_port = 9999;


   client_length = sizeof(Client_Addr);
   if (lwip_bind(server_socket, (struct sockaddr *)amp;Serv_Addr, sizeof(Serv_Addr)) < 0) {           
           printf("could not BIND");
   }

   if ( lwip_listen(server_socket, 20) != 0 ){
            printf("could not BIND");
   }
   while (1) {
                lwip_accept(server_socket, (struct sockaddr*)amp;Client_Addr, amp;client_length);                

               do{
                nbytes_server = lwip_recv(server_socket, recv_buffer, sizeof(recv_buffer),0);
                if (nbytes_server>0){lwip_send(server_socket, send_buffer, sizeof(send_buffer), 0);}

                printf("client message = %sn", recv_buffer);
                }while(nbytes_server>0); 
                sleepms(10);
       }
       lwip_close(server_socket);
}

void main(void)
{
    pthread_t  client_thread;
    pthread_t  server_thread;

    pthread_create(amp;server_thread, NULL, server_connect, NULL);
    pthread_create(amp;client_thread, NULL, client_connect, NULL);

    while(1){
        sleepms(1);
        }
}
  

Пожалуйста, дайте мне знать, если я делаю это неправильно

С уважением, Deb

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

1. вам нужно попробовать переформатировать свой код. Также на стороне клиента, if (client_socket < 0); выглядит неправильно.

2. Во-первых, я бы добавил » n» и вышел / вернул после сбоя printf; код продолжается после ошибок на данный момент. Далее, пропустите создание потоков и вызовите server_connect напрямую. Затем попробуйте подключиться через telnet и посмотрите, подключаетесь ли вы.

Ответ №1:

Вот по крайней мере 3 ошибки:

lwip_accept() возвращает новый дескриптор сокета, вы должны использовать его для чтения с клиента, а не из исходного сокета сервера (обратите также внимание, что lwip_accept будет блокироваться до тех пор, пока кто-то действительно не подключится к серверу).

Ваши номера портов также могут быть отключены, если вы используете небольшую конечную машину, обычно они расположены в сетевом порядке байтов, вам следует сделать Serv_Addr.sin_port = htons(9999); то же самое для клиентского порта — htons преобразует short из host endian в network endian

Вы не отправляете никаких данных! Ваш клиент ожидает, пока сервер отправит ему что-нибудь. Но ваш сервер ничего не отправляет, он ожидает, пока клиент что-нибудь отправит. Ничего не произойдет.

Проверьте, не происходит ли сбой lwip_connect тоже, и проверьте, errno предоставляет ли ваша среда это, поскольку это может дать подсказки о том, что идет не так

Ответ №2:

Если вы находитесь на одном компьютере, используемый вами IP-адрес 1.2.3.4 не является типичным адресом для localhost, который должен быть 127.0.0.1. Если вы на самом деле не задали IP-адрес компьютера с помощью маршрутизатора или каким-либо другим способом IP-адрес 1.2.3.4, этот адрес не будет разрешен, и даже если вы пытаетесь запустить клиент и сервер на одном компьютере, они не найдут друг друга, поскольку нет способа разрешить 1.2.3.4 для данного компьютера в сети.

Также вам не нужно привязывать сервер к определенному IP-адресу, вы можете просто использовать константу INADDR_ANY from netinet/in.h , которая привяжет сокет к любому интерфейсу в системе. Хотя на стороне клиента вам все равно понадобится правильный IP-адрес, но опять же, если это localhost, вы можете просто использовать 127.0.0.1.

Ответ №3:

(1) Похоже, что и клиент, и сервер ожидают получения чего-либо, прежде чем повторить это обратно. Кто-то должен заговорить первым.

(2) Я не вижу, где ваш lwip_accept возвращает новый сокет, с помощью которого можно взаимодействовать с клиентом. В конечном итоге вы выполняете recv / send в прослушивающем сокете.

(3) Также рассмотрим ваш код здесь:

 while (1)
{
    lwip_accept(server_socket, (struct sockaddr*)amp;Client_Addr, amp;client_length);

    do
    {
        nbytes_server = lwip_recv(server_socket, recv_buffer, sizeof(recv_buffer), 0);

        if (nbytes_server > 0)
        {
            lwip_send(server_socket, send_buffer, sizeof(send_buffer), 0);
        }

        printf("client message = %sn", recv_buffer);
    }
    while (nbytes_server > 0);

    sleepms(10);
}
  

Вы читаете и повторяете сообщение, но никогда не закрываете сокет (вероятно, разумно, потому что это прослушивающий сокет!) и немедленно возвращаетесь к блокировке при приеме снова. Если клиент не подключится снова, вы будете заблокированы в этом accept навсегда.

(4) Вам не нужны эти вызовы sleepms (). Используйте pthread_join() в main и просто избавьтесь от всего остального. Похоже, что все ваши вызовы в любом случае блокируются.