2013-09-16 21 views
0

我想用C寫多會話聊天服務器。我從一個終端託管服務器,從其他終端託管服務器。 在VMWare播放器上使用ubuntu 13.04。C中的多會話聊天服務器

發生了什麼是這樣的:
我正在將循環從3增加到fdmax,以接受使用sd(偵聽器)的新連接,並且newsd代表新的套接字描述符。

當我在一個窗口中打印'hi'時,它會打印所有窗口,包括我輸入的窗口。另外,大量隨機垃圾不斷出現。 我只想要輸入的內容(我如何擺脫垃圾>),並在除了輸入的所有窗口之外的所有窗口中!

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

void *get_in_addr(struct sockaddr *sa) 
{ 
    if (sa->sa_family == AF_INET) 
    { 
    return &(((struct sockaddr_in*) sa)->sin_addr); 
    } 

    return &(((struct sockaddr_in6*) sa)->sin6_addr); 
} 

int main(int argc, char **argv) 
{ 
    //ptr used for traversal, serv used for the linked list of struct addinfos , hints for  the getaddrinfo function 
    struct addrinfo *ptr, hints, *serv; 
    int max_cli, dat, x, i; 
    struct sockaddr_storage cli_addr; 
    socklen_t addr_size; 
    char cli_ip[INET_ADDRSTRLEN]; 
    char inc[256]; //one command line is 80 characters 
    memset(inc, 0, strlen(inc)); 
    int sd, newsd; 
    fd_set master; 
    fd_set read_fds; 
    char value[256]; 

    FD_ZERO(&master); 
    FD_ZERO(&read_fds); 

    //argv[1]-server ip argv[2]-server port argv[3]-maximum client number 

    int fdmax; 
    int opt = 1; 

    /*if(argc!=4) 
    { 
    printf("Please re-enter data. Data insufficient\n"); 
    exit(1); 
    } 
    if(atoi(argv[2])<1025) 
    { 
    printf("Reserved port. Please try again\n"); 
    exit(1); 
    }*/ 
    max_cli = atoi(argv[3]); 

    memset(&hints, 0, sizeof hints); 
    hints.ai_family = AF_INET; 
    hints.ai_socktype = SOCK_STREAM; 
    hints.ai_flags = AI_PASSIVE; 

    /* Verify the inputs and generate linked list of possible IPs to use*/ 

    if (sd = getaddrinfo(argv[1], argv[2], &hints, &serv)) 
    { 
    fprintf(stderr, "Error calling getaddrinfo %s\n", gai_strerror(sd)); 
    exit(1); 
    } 

    for (ptr = serv; ptr != NULL ; ptr = ptr->ai_next) 
    { 

    void *addr; 
    if (ptr->ai_family == AF_INET) 
    { 
     struct sockaddr_in *ipv4 = (struct sockaddr_in *) ptr->ai_addr; 
     addr = &(ipv4->sin_addr); 
    } 
    inet_ntop(ptr->ai_family, addr, value, sizeof value); 
    //printf("%s\n",value);  

    //Form connection with one of the IP addresses 
    sd = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol); 
    if (sd < 0) 
     continue; 

    setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt); 

    if (bind(sd, ptr->ai_addr, ptr->ai_addrlen) < 0) 
    { 
     close(sd); 
     continue; 
    } 

    break; //Indicates one working socket found and bound 
    } //end for 

    if (ptr == NULL) 
    { 
    fprintf(stderr, "Bind failed\n"); 
    exit(2); 
    } 

    freeaddrinfo(serv); 

    if (listen(sd, 15) == -1) 
    { 
    printf("Error occurred while listening\n"); 
    exit(3); 
    } 

    /* Socket found, bound and now listening for active connections*/ 

    FD_SET(sd, &master); 

    fdmax = sd; //Latest active socket descriptor 

    while (1) 
    { 

    read_fds = master; //Copy the master list so that the original list doesn't get damaged 

    if (select(fdmax + 1, &read_fds, NULL, NULL, NULL) == -1) 
    { 
     perror("Select failed.\n"); 
     exit(4); 
    } 

    for (i = 3; i <= fdmax; i++) 
    { 
     //printf("i"); 
     //printf("entered for loop\n"); 
     if (FD_ISSET(i,&read_fds)) //new connection->false, existing one->true 
     { 
     // printf("Started reading descriptors!\n"); 

     if (i == sd) //primary connection,exists, accept new file descriptor 
     { //printf("Read first connection!\n"); 
      addr_size = sizeof cli_addr; 
      newsd = accept(sd, (struct sockaddr *) &cli_addr, &addr_size); 
      printf("Accepted new connection socket %d\n", newsd); 
      FD_SET(newsd, &master); 
      if (newsd == -1) 
      { 
      perror("accept"); 
      } 
      if (newsd > fdmax) 
      { 
      fdmax = newsd; 
      } 
      printf("%d %d\n", newsd, fdmax); 
      continue; 
     } 
     else if (i != sd) //existing connection, so accept data 
     { 
      if (dat = recv(i, &inc, sizeof inc, 0) <= 0) 
      { 
      if (dat == 0) 
      { 
       printf(" Socket %d has quit the chatroom", i); 
      } 
      if (dat < 0) 
      { 
       perror("Error on Receive"); 
      } 
      // char *s=&inc; 
      //printf("%d\n %s",dat); 
      close(i); 
      FD_CLR(i, &master); 
      } 

      //Nothing wrong with the input from client i. Broadcast! 
      else 
      { 
      for (x = 3; x <= fdmax; x++) 
      { 
       if (FD_ISSET(x,&master)) 
       { 
       if (x != sd) 
       { 
        //send(x,&inc,sizeof inc,0); 
        if (send(x, &inc, sizeof inc, 0) < 0) 
        { 
        perror("Send"); 
        } 
       } 
       } 
      } 
      } 
     } 

     } 

     /*else// new connection 
     { break; 

     printf("SERVERBOT: new connection from %s on socket %d\n",inet_ntop(cli_addr.ss_family,get_in_addr((struct sockaddr*)&cli_addr),cli_ip, INET6_ADDRSTRLEN),newsd); 
     }////change this to 'username' has joined the room*/ 

    } 
    } 

    return 0; 
} 
+2

沒有看到的源泉 - 不大可能。 – viraptor

+0

@viraptor我很抱歉:|只是印上了 – tvishwa107

+0

@goldilocks,謝謝!監督。 – tvishwa107

回答

1

首先,當你發送接收到的數據,您使用sizeof運營商,它給你整個陣列的尺寸。您應該發送的字節數與收到的字節數相同,通常較少。使用返回值recv來知道實際接收的字節數。一般來說,C陣列沒有動態大小,你必須自己跟蹤。

然後關於垃圾,您可能會打印緩衝區內容而不終止'\0'字符。因此,在打印或使用其他字符串函數之前添加(確保緩衝區中有1個字節的額外空間!),或者在終止nul丟失的情況下使用接受最大字符串大小的打印函數。

+0

我不能upvote,但這對我來說工作得很好。謝謝。順便說一句,你不是說'\ 0'嗎? – tvishwa107

+0

修正了斜槓。是的,upvoting需要一點名譽,不用擔心。 – hyde

0

爲啓動發送必須使用DAT作爲長度不的sizeof(INC)