приложение для чата с сокетом, т.е. я хочу общаться с несколькими клиентами одновременно? - PullRequest
0 голосов
/ 01 декабря 2010

Я работаю над приложением для чата с сокетом, т.е. я хочу общаться с несколькими клиентами одновременно. Я написал следующую программу. Сервер принимает несколько клиентов, но я могу общаться только с последним клиентом. Я не могу общаться с предыдущим клиентом, может кто-нибудь объяснить мне, почему?

/* tcpserver.c */

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>

void *thread(int *);

int main()
{
        int sock, connected, true = 1,n=1; 
    pthread_t tid;
        struct sockaddr_in server_addr,client_addr;   
        int sin_size;

        if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
            perror("Socket");
            exit(1);
        }

        if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&true,sizeof(int)) == -1) {
            perror("Setsockopt");
            exit(1);
        }

        server_addr.sin_family = AF_INET;        
        server_addr.sin_port = htons(5000);    
        server_addr.sin_addr.s_addr = INADDR_ANY;
        bzero(&(server_addr.sin_zero),8);

        if (bind(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr))
                                                                       == -1) {
            perror("Unable to bind");
            exit(1);
        }

        if (listen(sock, 5) == -1) {
            perror("Listen");
            exit(1);
        }

    printf("\nTCPServer Waiting for client on port 5000");
        fflush(stdout);


        while(n<=5)
        { 

            sin_size = sizeof(struct sockaddr_in);

            connected = accept(sock, (struct sockaddr *)&client_addr,&sin_size);

            printf("\n I got a connection from (%s , %d)",
                   inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
        pthread_create(&tid,NULL,thread,&connected);
        n++;
    }

      close(sock);
      return 0;
}


void *thread(int *nfd)
{
        char send_data [1024] , recv_data[1024];      
        int bytes_recieved;   
        while (1)
            {
              printf("\n SEND (q or Q to quit) : ");
              gets(send_data);

              if (strcmp(send_data , "q") == 0 || strcmp(send_data , "Q") == 0)
              {
                send(*nfd, send_data,strlen(send_data), 0);
                close(nfd);
                break;
              }

              else
                 send(*nfd, send_data,strlen(send_data), 0); 

              bytes_recieved = recv(*nfd,recv_data,1024,0);

              recv_data[bytes_recieved] = '\0';

              if (strcmp(recv_data , "q") == 0 || strcmp(recv_data , "Q") == 0)
              {
                close(*nfd);
                break;
              }

              else
              printf("\n RECIEVED DATA = %s " , recv_data);
              fflush(stdout);
            }

}







/* tcpclient.c */

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>


int main()

{

        int sock, bytes_recieved; 
        char send_data[1024],recv_data[1024];
        struct hostent *host;
        struct sockaddr_in server_addr; 

        host = gethostbyname("127.0.0.1");

        if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
            perror("Socket");
            exit(1);
        }

        server_addr.sin_family = AF_INET;    
        server_addr.sin_port = htons(5000);  
        server_addr.sin_addr = *((struct in_addr *)host->h_addr);
        bzero(&(server_addr.sin_zero),8);

        if (connect(sock, (struct sockaddr *)&server_addr,
                    sizeof(struct sockaddr)) == -1)
        {
            perror("Connect");
            exit(1);
        }

        while(1)
        {

          bytes_recieved=recv(sock,recv_data,1024,0);
          recv_data[bytes_recieved] = '\0';

          if (strcmp(recv_data , "q") == 0 || strcmp(recv_data , "Q") == 0)
          {
           close(sock);
           break;
          }

          else
           printf("\nRecieved data = %s " , recv_data);

           printf("\nSEND (q or Q to quit) : ");
           gets(send_data);

          if (strcmp(send_data , "q") != 0 && strcmp(send_data , "Q") != 0)
           send(sock,send_data,strlen(send_data), 0);

          else
          {
           send(sock,send_data,strlen(send_data), 0);  
           close(sock);
           break;
          }

        }  
return 0;
}

Ответы [ 3 ]

2 голосов
/ 01 декабря 2010

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

Совет: не используйте потоки.Опрос () занимает много ресурсов.Используйте select ().

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

alt text

1 голос
/ 01 декабря 2010

(На самом деле это не ответ :) Вы должны использовать несколько потоков только тогда, когда хотите заставить многопроцессорную машину одновременно использовать ее разные процессоры.Например, когда вы рисуете сложный математический график, вы вполне можете разбить график на несколько частей, чтобы каждый процессор мог вычислять разные его части одновременно.Многие могут не согласиться, но если вам нужно многопоточность, потому что вы хотите разблокировать ввод-вывод, вы делаете это неправильно.

Здесь вы хотите многопоточность просто потому, что хотите разблокировать ввод-вывод.Один более простой способ - это разветвить () сервер в дочерние процессы, которые выполняют простую запись сообщения в назначенные им сокеты.
Лучшим способом является многоадресное приведение, как упомянуто Alastair.Но многоадресность также может быть выполнена плохо. Это хороший текст

0 голосов
/ 01 декабря 2010

Это вопрос с подвохом, верно?

Вы передаете адрес «подключен» в поток, а не значение. Как только новое соединение вступает в силу, значение перезаписывается, и в результате два потока взаимодействуют с одним и тем же соединением.

Кстати, почему вы используете многопоточность? poll () - лучшее решение. Вы легко сможете создать сервер, который будет обрабатывать несколько клиентов в одном потоке. Это действительно не сложно.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...