44138


閲覧ありがとうございます。

C言語でサーバプログラミングをしています。  
実装したいことはサーバーのプログラムでマルチスレッドのスレッドプールというものです。

実装したい内容としては

「子スレッドを5つつくり、この5つで  
クライアントからの接続に対応する。」

「5つまでしか接続できない」

「小スレッドは終了させず、接続が切れたら次の接続を待つ」

の3点となります。  
マルチスレッドではなく、forkで実装したところ  
うまくいったのですが、マルチスレッドではタイトルのように  
bindエラーが出て困っているのでお力を貸して頂きたいです。

コード内容は以下の通りです。

[code]

    #define PRCS_LIMIT 5 /* 小スレッド数制限 */
    #define BUFSIZE 50   /* バッファサイズ */
    
    void * execute(void *arg);
    int init_tcpserver(in_port_t myport, int backlog);
    
    int main(int argc, char *argv[]) {
        int *port_number;
        int temp;
        pthread_t tid;
    
        temp = atoi(argv[1]);
        port_number = &temp;
    
        /* 子スレッドを5つ生成する */
        int i;
        for (i = 1; i <= PRCS_LIMIT; i++) {
            if (pthread_create(&tid, NULL, execute, (void *) port_number) != 0) {
                exit_errmesg("pthread_create()");
            }
        }
    
        //親スレッドは終わらせない。
        while(1){
    
        }
        return 0;
        /* never reached */
    }
    
    /* スレッドの本体 */
    void * execute(void *arg) {
        int sock_accepted;
        int sock_listen;
        char buf[BUFSIZE];
        int strsize;
    
        /* サーバの初期化 */
        sock_listen = init_tcpserver(*(int *) arg, 5);
    
        /* クライアントの接続を受け付ける */
        sock_accepted = accept(sock_listen, NULL, NULL);
    
        pthread_detach(pthread_self()); /* スレッドの分離(終了を待たない) */
    
        close(sock_listen);
    
        while (1) {
            /* 文字列をクライアントから受信する */
            send(sock_accepted, ">", 2, 0);
            if ((strsize = recv(sock_accepted, buf, BUFSIZE, 0)) == -1) {
                exit_errmesg("recv()");
            }
    
            if (strstr(buf, "end") != NULL) {
                close(sock_accepted);
    
                /* サーバに接続する */
                sock_listen = init_tcpserver(*(int *) arg, 5);
                /* クライアントの接続を受け付ける */
                sock_accepted = accept(sock_listen, NULL, NULL);
    
            }
            /* 文字列をクライアントに送信する */
            if (send(sock_accepted, buf, strsize, 0) == -1) {
                exit_errmesg("send()");
            }
        }
    
        return (NULL);
    }
    
    int init_tcpserver(in_port_t myport, int backlog)
    {
      struct sockaddr_in my_adrs;
      int sock_listen;
      int yes = 1;
    
      /* サーバ(自分自身)の情報をsockaddr_in構造体に格納する */
      memset(&my_adrs, 0, sizeof(my_adrs));
      my_adrs.sin_family = AF_INET;
      my_adrs.sin_port = htons(myport);
      my_adrs.sin_addr.s_addr = htonl(INADDR_ANY);
    
      /* 待ち受け用ソケットをSTREAMモードで作成する */
      if((sock_listen = socket(PF_INET, SOCK_STREAM, 0)) == -1){
        exit_errmesg("socket()");
      }
    
      //TIME_WAIT状態でもbindできるようにする。
      setsockopt(sock_listen, SOL_SOCKET, SO_REUSEADDR, (const char *)&yes, sizeof(yes));
    
      /* 待ち受け用のソケットに自分自身のアドレス情報を結びつける */
      if(bind(sock_listen, (struct sockaddr *)&my_adrs, sizeof(my_adrs)) == -1 ){
        exit_errmesg("bind()");
      }
    
      /* クライアントからの接続を受け付ける準備をする */
      if(listen(sock_listen, backlog) == -1){
        exit_errmesg("listen()");
      }
    
      return(sock_listen);
    }
    
[/code]


CC BY-SA 4.0
2018-05-21T13:24:42.553
44137
2018-05-21T14:08:59.710
2018-05-21T14:08:59.710
26577
26577
question
linux c tcp socket マルチスレッド
Linux C言語 ソケット通信 子スレッドで待ち受けするとbindエラーが出る


エラーの通りで`bind()`で指定する`address :
port`のペアはシステム内で一意の必要があります。`fork()`でうまくいったのはよくわかりません。

また[`listen()`](https://linuxjm.osdn.jp/html/LDP_man-pages/man2/listen.2.html)は

> sockfd が参照するソケットを接続待ちソケット (passive socket) として印をつける。

だけです。実際に待ち受けるには`accept()`を使います。つまり、`socket()`、`bind()`、`listen()`までの処理はスレッドを作成する前に完了させておく必要があります。その上で各スレッドで`accept()`を実行すればよいでしょう。


CC BY-SA 4.0
2018-05-21T13:35:19.557
44138
2018-05-21T13:35:19.557
4236
44137
answer