2016-12-07 21 views
2

クライアントとサーバーの2つのプログラムを作成しようとしています。クライアントはソケット接続を開き、接続を受け入れると新しいスレッドが生成された後、デタッチして残りの読み取り/書きます。問題は、複数の書き込みを行い、クライアントからの読み取りで正しいデータが得られないが、サーバー側では正しいデータが送信されたことが印刷されるということです。スレッドを使用してソケットから複数の読み込み/書き込みを処理するには?

これは、私のコードが新しいスレッドを生成するように見えるもので、それらのスレッドをどのように処理するかです。

while(1){ 
    listen(sockfd,5); 

    // determine the size of a clientAddressInfo struct 
    clilen = sizeof(clientAddressInfo); 
    int *newsockfd = malloc(sizeof(int)); 
    // block until a client connects, when it does, create a client socket 
    *newsockfd = accept(sockfd, (struct sockaddr *) &clientAddressInfo, &clilen); 
    // if the connection blew up for some reason, complain and exit 
    if (*newsockfd < 0){ 
     error("ERROR on accept"); 
    } 
    connection_args *args = malloc(sizeof(connection_args)); 
    args->file_descrp = newsockfd; 
    pthread_t tid; 
    pthread_create(&tid,NULL, handle_connect, args); 
} 

void * handle_connect(void* args){ 
    connection_args* connect_arg = (connection_args*)args; 
    pthread_detach(pthread_self()); 
    int n = -1; 
    char buffer[256]; 
    bzero(buffer,256); 
    //while not close; 
    while(1){ 
     // try to read from the client socket 
     n = read(*connect_arg->file_descrp,buffer,255); 
     printf("input: %s\n", buffer); 
     // if the read from the client blew up, complain and exit 
     if (n < 0){ 
      error("ERROR reading from socket"); 
     } 
     int fd; 
     if(strcmp("open",buffer) == 0){ 
      fd = open("file.txt",0); 
      bzero(buffer,256);  
      sprintf(buffer,"%d",fd); 
     }else if(strcmp("read",buffer) == 0){ 
      char *read_buffer = malloc(sizeof(char)*256); 
      bzero(read_buffer,256); 
      fd = read(get_filedescrp(),read_buffer,30); 
      bzero(buffer,256); 
      sprintf(buffer,"%s,%d",read_buffer,fd); 

     }else if(strcmp("close",buffer) == 0){ 
      break; 
     } 
     printf("buffer_send: %s\n",buffer); 
     // try to write to the client socket 
     n = write(*connect_arg->file_descrp,buffer,sizeof(buffer)); 
     // if the write to the client below up, complain and exit 
     if (n < 0){ 
      printf("here!!\n"); 
      error("ERROR writing to socket"); 
     } 
     bzero(buffer,256); 
    } 
    printf("Left thread\n"); 
    return NULL; 
} 
+1

ちょうど一般的にWiresharkと[Netcat](https://linux.die.net/man/1/nc)を使ってネットワークコードをデバッグすることをお勧めします。 Wiresharkはあなたが送信しているものを見せるようにします。また、既知のサーバとクライアントとして 'nc'を使用することで、サーバとクライアントを分離して、一度に取り込む変数の数を減らすことができます。 – yano

+1

'accept()'ループの中で 'listen()'を呼び出さないでください。それを1回呼び出してから、ループに入ります。そして、あなたのソケット記述子を 'malloc()'する必要はありません。そして、 'printf()'や 'strcmp()'のように、ヌル終了した操作を実行する前に 'buffer'をヌル文字で終わらせるわけではありません。また、TCPがストリーミング転送であることを考慮していないので、 'read()'が完全な文字列を受け取るという保証はなく、時には部分的なデータを受け取ることができます。送信側でコマンドを区切り、読み込み側で区切り文字を探す必要があります。 –

+0

クライアント側でread()を2回呼び出すと、正しいデータが得られます。私はTCPがストリーミングトランスポートであるという事実をどのように説明しますか?ヌル以外の応答が得られるまでread()を呼び出し続けますか?ヌル終了文字についても、ヌル終了文字で文字列を送ると、読み込んだ後に手動で再追加する必要がありますか? – user1457388

答えて

1

何らかのプロトコルなしでTCP/IP経由でクライアントサーバー通信を実装することはできません。送信者によって書き込まれたデータは、途中でスライスされ、ダイスされ、リーダ側とは異なるチャンク長で来る。あなたは、データを解釈しようとする前にフルフレームを受け取ったかどうかを知る方法が必要です。

たとえば、非常に単純なラインベースのプロトコルを使用することができます:データを最大で読み取り、'\n'バイトを含む。リテインバッファに一度に1バイトを読み込むことはやや非効率ですが、実装は簡単です。

1

ソケット読み込み呼び出しでは、1回の呼び出しでクライアントから送信されたデータ全体が返される場合と返されない場合があります。 各読み取り呼び出しは、その呼び出しで読み取られたバイト数を返します。したがって、アプリケーションは、予想されるバイト数が読み取られるまでループ内でreadを呼び出す必要があります。

関連する問題