2013-10-13 19 views
6

Basit bir sunucuya ve istemci C koduna sahip, çokyönlüler için bir konu sohbet odası (pthread kütüphanesi) kullanarak sohbet odası yapıyorum. Sorun şu ki, sunucunun bir istemcinin soket üzerinden diğer tüm istemcilere gönderdiği her mesajı yazmasını sağlamanın bir yolu düşünemem. Burada başka benzer yazılar okudum ve çaresizdi. Lütfen bana okul için bunu yapmam için bana yardım edin. Her iki kodu da hemen göndereceğim.Linux'ta C/Soket programlamasındaki sohbet odası

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

Bu programlar çok basit, istemci kullanıcı konsolda yazıyor ve sunucu tekrar aynı mesajı göndermek neyi gönderir. Aynı mesajı sadece her mesaja (istemci) bağlı olarak göndermek için sunucuya ihtiyacım var (sadece orijinal mesajı gönderen değil).

Herkes bakım için bu uzun olduğunu biliyorum ama eğer yapabilirsen, ben bir muteks ile korunan tüm istemciler küresel bir tablo, gerek biraz yardım :)

+0

Bunun için iş parçacığı kullanmanız gerekli mi? Daha kolay bir tasarım, tek iş parçacıklı olabilir ve select() veya poll() kullanarak G/Ç işlemlerini çoğaltır. Sonra tüm istemcilerin soketlerine yazmak basit bir for döngüsü kullanarak yapılabilir. –

+0

Oh teşekkürler, muhtemelen daha kolay olacaktır. Yine de select() veya poll() haha'yı nasıl kullanacağımı bilmiyorum. İplik kullandım çünkü son zamanlarda onları nasıl kullanacağımı öğrendim ve problemim için oldukça etkili bir çözüm gibi görünüyorlar haha. Bu fonksiyonlardan herhangi birinin nasıl kullanıldığına dair bana biraz bilgi verebilir misin? :) –

+0

Dişler güçlü bir ilaçtır - çok dikkatli olmadıkça sizi ısıtabilirler. Görevini gerçekleştirmenin başka bir yolu olmadıkça bunları kullanmamayı denerim. Select() için şu bağlantılara bakın: http://www.lowtek.com/sockets/select.html http://www.binarytides.com/multiple-socket-connections-fdset-select-linux/ –

cevap

5

almak memnuniyet duyarız. Yeni bir müşteri bağlandığında onları global istemciye ekleyin. Bir müşteri bağlantıyı kesince, onları global tablodan kaldırın.

İstemci bir ileti gönderdiğinde, genel tablodaki kilidi alın ve taşıyın. İletiyi tüm istemcilere (kaynağına geri bir ileti yankılamak istemiyorsanız, iletiyi gönderen dışında) gönderin.

Bu, gerçek sunucuların bunu nasıl gerçekleştirdiğinin aşırı derecede basitleştirilmesidir. Ama başlaman için yeterli olmalı.