2013-10-13 4 views
6

Ich habe einen einfachen Server und Client C-Code, um einen Chatroom für Multiclients mit Threads (Pthread-Bibliothek) zu tun. Das Problem, das ich hatte, ist, dass ich keine Möglichkeit finde, den Server dazu zu bringen, jede Nachricht zu schreiben, die ein Client über den Socket an alle anderen Clients sendet. Ich habe andere ähnliche Beiträge hier gelesen und es war hilflos. Bitte helfen Sie mir, ich muss das für die Schule tun. Ich werde beide Codes sofort senden.Chatroom in C/Socket-Programmierung unter Linux

server.c:

#include<stdio.h> 
#include<string.h> //strlen 
#include<stdlib.h> //strlen 
#include<sys/socket.h> 
#include<arpa/inet.h> //inet_addr 
#include<unistd.h> //write 

#include<pthread.h> //for threading , link with lpthread 

void *connection_handler(void *); 


int main(int argc , char *argv[]) 
{ 
    int socket_desc , new_socket , c , *new_sock; 
    struct sockaddr_in server , client; 
    char *message; 

    //Create socket 
    socket_desc = socket(AF_INET , SOCK_STREAM , 0); 
    if (socket_desc == -1) 
    { 
     printf("Could not create socket"); 
    } 

    //Prepare the sockaddr_in structure 
    server.sin_family = AF_INET; 
    server.sin_addr.s_addr = INADDR_ANY; 
    server.sin_port = htons(8888); 

    //Bind 
    if(bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0) 
    { 
     puts("bind failed"); 
     return 1; 
    } 
    puts("bind done"); 

    //Listen 
    listen(socket_desc , 3); 

    //Accept and incoming connection 
    puts("Waiting for incoming connections..."); 
    c = sizeof(struct sockaddr_in); 
    while((new_socket = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c))) 
    { 
     puts("Connection accepted"); 

     pthread_t sniffer_thread; 
     new_sock = malloc(1); 
     *new_sock = new_socket; 

     if(pthread_create(&sniffer_thread , NULL , connection_handler , (void*) new_sock) < 0) 
     { 
      perror("could not create thread"); 
      return 1; 
     } 

     //Now join the thread , so that we dont terminate before the thread 
     //pthread_join(sniffer_thread , NULL); 
     puts("Handler assigned"); 
    } 

    if (new_socket<0) 
    { 
     perror("accept failed"); 
     return 1; 
    } 

    return 0; 
} 

/* 
* This will handle connection for each client 
* */ 
void *connection_handler(void *socket_desc) 
{ 
    //Get the socket descriptor 
    int sock = *(int*)socket_desc; 
    int read_size; 
    char *message , client_message[2000]; 


    //Receive a message from client 
    while((read_size = recv(sock , client_message , 2000 , 0)) > 0) 
    { 
     //Send the message back to client 
     write(sock , client_message , strlen(client_message)); 
    } 

    if(read_size == 0) 
    { 
     puts("Client disconnected"); 
     fflush(stdout); 
    } 
    else if(read_size == -1) 
    { 
     perror("recv failed"); 
    } 

    //Free the socket pointer 
    free(socket_desc); 

    return 0; 
} 

client.c

#include<stdio.h> //printf 
#include<string.h> //strlen 
#include<sys/socket.h> //socket 
#include<arpa/inet.h> //inet_addr 

int main(int argc , char *argv[]) 
{ 
    int sock; 
    struct sockaddr_in server; 
    char message[1000] , server_reply[2000]; 

    //Create socket 
    sock = socket(AF_INET , SOCK_STREAM , 0); 
    if (sock == -1) 
    { 
     printf("Could not create socket"); 
    } 
    puts("Socket created"); 

    server.sin_addr.s_addr = inet_addr("127.0.0.1"); 
    server.sin_family = AF_INET; 
    server.sin_port = htons(8888); 

    //Connect to remote server 
    if (connect(sock , (struct sockaddr *)&server , sizeof(server)) < 0) 
    { 
     perror("connect failed. Error"); 
     return 1; 
    } 

    puts("Connected\n"); 
    puts("Bienvenido al Chatroom, puedes empezar a escribir en la sala!"); 

    //keep communicating with server 
    while(1) 
    { 

     printf("Enter message: "); 
    fgets(message, sizeof(message),stdin); 
     //scanf("%s" , message); 

     //Send some data 
     if(send(sock , message , strlen(message) , 0) < 0) 
     { 
      puts("Send failed"); 
      return 1; 
     } 

     //Receive a reply from the server 
     if(recv(sock , server_reply , 2000 , 0) < 0) 
     { 
      puts("recv failed"); 
      break; 
     } 

    printf("Server Reply: %s\n", server_reply); 
    server_reply[0]='\0'; 
    } 

    close(sock); 
    return 0; 
} 

Diese Programme sind sehr einfach, sendet der Client, was der Benutzer in der Konsole schreibt, und der Server die gleiche Nachricht zurückschicken. Ich brauche nur den Server, um dieselbe Nachricht an jeden verbundenen Thread (Client) zu senden (nicht nur an den, der die ursprüngliche Nachricht gesendet hat).

Ich weiß, das lang ist für jedermann, zu kümmern, aber wenn Sie können, ich werde froh sein, etwas Hilfe zu bekommen :)

+0

Ist es erforderlich, dass Sie Threads dafür verwenden? Ein einfacherer Entwurf wäre single-threaded und multiplexen die E/A-Operationen mit select() oder poll(). Dann könnte das Schreiben in alle Sockets aller Clients mit einer einfachen For-Schleife erfolgen. –

+0

Oh danke, das wird wahrscheinlich einfacher sein. Trotzdem weiß ich nicht, wie man select() oder poll() haha ​​benutzt. Ich habe Threads verwendet, weil ich vor kurzem gelernt habe, wie man sie benutzt und sie schienen eine ziemlich pro-Lösung für mein Problem zu sein, haha. Gibt es eine Chance, dass Sie mir ein paar Details über die Verwendung dieser Funktionen geben könnten? :) –

+0

Fäden sind starke Medizin - sie können dich beißen, wenn du nicht sehr vorsichtig bist. Ich versuche, sie nicht zu benutzen, es sei denn, es gibt keinen anderen Weg, diese Aufgabe zu erfüllen. Wie für select(), siehe diese Links: http://www.lowtek.com/sockets/select.html http://www.binarytides.com/multiple-socket-connections-fdset-select-linux/ –

Antwort

5

Sie brauchen eine globale Tabelle aller Kunden, durch einen Mutex geschützt. Wenn ein neuer Client eine Verbindung herstellt, fügen Sie sie zur globalen Tabelle der Clients hinzu. Wenn ein Client die Verbindung trennt, entfernen Sie sie aus der globalen Tabelle.

Wenn ein Client eine Nachricht sendet, erwerben Sie die Sperre für die globale Tabelle und durchlaufen sie. Senden Sie die Nachricht an alle Clients (außer an denjenigen, der die Nachricht gesendet hat, wenn Sie eine Nachricht nicht an die Quelle zurücksenden möchten).

Dies ist eine grobe Vereinfachung, wie echte Server es tun. Aber es sollte genug sein, um Sie zu beginnen.