2016-03-30 12 views
0

ソケットを使用してチャットサーバー用のサーバーとクライアントを構築しようとしています。私はselect()を使って複数のソケットから入力を得ることになっていることを知っていますが、それをどうやって行うのかよくわからず、正しく読み込みます。私のコードが座っていると、1つのクライアントから完全に正常に読み込まれますが、2つが開いていると、2番目のクライアントが行うことはすべて無視されます。複数のソケット接続にSelectを使用するC

私は複数のソケットから入力を取ることができるようにselectを正しく実装する方法を知りたいと思います。前もって感謝します。心の中で

#include "../../include/my.h" 

#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <signal.h> 
#include <stdlib.h> 
#include <string.h> 
#include <stdio.h> 

void interrupt(); 

void interrupt() 
{ 
    my_str("Server exiting.\n"); 
    exit(0); 
} 

int str_to_num(char* str)  
{ 
     int i = 0; 
     int numDigits = 0; 
     int ret = 0; 

     while (str[numDigits] != '\0') 
     { 
       numDigits++; 
     } 

     while (i < numDigits) 
     { 
       int digit = str[i]; 

       if (digit < 48 && digit > 57) 
         return -1; 

       digit -= 48; 

       ret += digit * my_pow(10, numDigits - i - 1); 
       i++; 
     } 

     return ret; 
} 

char* add_null_term(char* str) 
{ 
    int i = 0; 

    while (str[i] != '\0') 
     i++; 

    str[i] = '\0'; 

    return str; 
} 
int main(int argc, char **argv) 
{ 
    int sockfd, newsockfd, portnum; 
    int len; 
    char buffer[256]; 
    /*char *username = (char*)malloc(256*sizeof(char));*/ 
    socklen_t clilen; 
    struct sockaddr_in serv_addr, cli_addr; 

    /*check args*/ 
    if (argc < 2) 
    { 
     my_str("Usage: ./server <port_number>\n"); 
     exit(0); 
    } 

    portnum = str_to_num(argv[1]); 

    if (portnum < 1024) 
    { 
     perror("Ports below 1024 are reserved for root access.\n"); 
     exit(0); 
    } 

    if (portnum < 1 || portnum > 65535) 
    { 
     my_str("Port must be between 1 and 65535\n"); 
     exit(0); 
    } 

    signal(SIGINT, interrupt); 

    sockfd = socket(AF_INET, SOCK_STREAM, 0); 

    bzero((char*)&serv_addr, sizeof(serv_addr)); 

    serv_addr.sin_family = AF_INET; 

    serv_addr.sin_port = htons(portnum); 

    serv_addr.sin_addr.s_addr = INADDR_ANY; 

    if (bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr))<0) 
    { 
     perror("bind"); 
     exit(0); 
    } 

    listen(sockfd, 5); 

    clilen = sizeof(cli_addr); 

    while(1) 
    { 
     if ((newsockfd=accept(sockfd, (struct sockaddr*)&cli_addr, &clilen)) < 0) 
     { 
      perror("accept"); 
      exit(0); 
     } 

     usleep(2000); 

     my_str("Server received: "); 

     while ((len = read(newsockfd, &buffer, 256)) > 0) 
     { 
      buffer[my_strlen(buffer)] = '\0'; 

      if (my_strcmp(buffer, "/") == 0) 
      { 
       my_str("Error: command "); 
       my_str(buffer); 
       my_str("not found.\n"); 
       bzero((char*)&buffer, sizeof(buffer)); 
      } 

      /*if (count == 0) 
      { 
       my_strcpy(username, buffer); 
       my_str("setting nickname to: "); 
       my_str(username); 
       bzero((char*)&buffer, sizeof(buffer)); 
       my_str(buffer); 
       count++; 
       my_str("\n"); 
      }*/ 

      /*else if (my_strncmp(buffer, "/me", 3) == 0) 
      { 
       my_str(username); 
       my_str(" "); 
       my_str(&buffer[4]); 
       bzero((char*)&buffer, sizeof(buffer)); 
       my_str("\n"); 
      } 

      else if (my_strncmp(buffer, "/nick", 5) == 0) 
      { 
       my_str("Changing nickname of "); 
       my_str(username); 
       my_strcpy(username, &buffer[6]); 
       my_str(" to "); 
       my_str(username); 
       bzero((char*)&buffer, sizeof(buffer)); 
       my_str("\n"); 
      }*/ 

      /*else 
      {*/ 
       /*my_str(username); 
       my_str(": ");*/ 
       my_str(buffer); 
       bzero((char*)&buffer, sizeof(buffer)); 
       my_str(buffer); 
       my_str("\n"); 
      /*}*/ 
     } 

     my_str("\nServer: Message end. Waiting for next connection.\n"); 
    } 

    return 0; 
} 
+0

私はselectを使用してみました代わりの文の場合、最初に受け入れ、そしてもちろんFD_SETと必要な他を追加しましたビット。サーバーは起動しましたが、入力を受け付けません – spicelord

+0

受け入れの代わりに選択を使用しようとしましたか?選択して受け入れることは、さまざまなことをする。これは、ヘッドホンの代わりにハンマーを使い、まだ音楽を聞くことを期待するようなものです。実際には意味をなさないのです。 – immibis

+0

これは非常に役に立ちます。もちろん彼らはそうします。私は、受け入れの代わりに選択を適切に使うために何をすべきかを知ろうとしています。 – spicelord

答えて

0

あなたの質問を選択し使用する方法である場合は()サーバーで...ここ はあなたが始めるために一の技術 の私の頭の上からの抜粋です...クマのすべてのエラーチェック 存在せず、ラウンドロビン 的に機能するように最適化されていない...

listen(sockfd, SOMAXCONN) 

fd_set my_set; 
fd_set wk_set; 

FD_ZERO(&my_set);   /* initialize fd_set */ 
FD_SET(sock_fd, &my_set) /* put listener into fd_set */ 
max_fd = sockfd; 

while(TRUE) 
{ 
    memcpy(&wk_set, &my_set, sizeof(my_set)); 

    rc = select(max_fd + 1, &wk_set, NULL, NULL, NULL) 
    if (rc == -1) 
    { 
     if (errno == EINTR) 
      continue; 
     printf("select failed: errno = %d\n", errno); 
     exit(1); 
    } 
    for(i = 0; i < max_fd; i++) /* check everything in wk_set */ 
    { 
     if (FD_ISSET(i, &wk_set) 
     { 
      if (i == sockfd) /* is it the listener socket?? */ 
      { 
       wk_sock=accept(sockfd, (struct sockaddr*)&cli_addr, &clilen); 
       if (wk_sock == -1) 
       { 
        printf("accept failed: errno=%d\n", errno); 
        exit(1); 
       } 
       FD_SET(wk_sock, &my_set); /* put into fd_set */ 
       if (wk_sock > max_sock) 
        max_sock = wk_sock; 
      }else{ 
       /* ready to read from this socket */ 
       recv_len = recv(i, ....) 
       if (recv_len == 0) /* client disconnected */ 
       { 
        close(i); 
        FD_CLR(i, &my_set); 
        if (i == max_fd) 
        { 
         for(x=0;x<max_fd;x++) /* find new max_fd */ 
         { 
          if (FD_ISSET(x, &my_set) 
           max_fd = x; 
         } 
        } 
       } else { 
       handle message from client 
       } 
      } 
     } 
    } 
} 
関連する問題