2012-04-11 11 views
1

私は、サーバのデーモンがTCPのunixドメイン/ローカルソケットでリッスンしています。同じマシン上で実行されている複数のクライアントが接続しています。デーモンはUDPインターネットソケットにもバインドされています。デーモンは、ローカルクライアントのいずれかからデータを受信するたびに、送信クライアント以外のすべての接続されたクライアントに同じデータを送信します。デーモンがUDPインターネットソケットでデータを受信する場合、デーモンはそのデータをすべてのローカル接続クライアントに送信する必要があります。デーモンがローカルソケット上のデータを受信すると、データの送受信は完全に機能します。ただし、サーバーがUDPインターネットソケットで受信したデータを送信すると、クライアントはデータを受信しません。クライアントは、サーバーデーモンが終了して接続が閉じられた後、またはいずれかのクライアントがサーバーにローカルにデータを送信したときに、インターネットデータを受信します。インターネットデータは、ローカルデータとともにクライアントによって受信される。 fcntl()を使用して、ローカルソケットとインセットソケットの両方をブロックとして設定しました。ここで私が持っているデーモン・コードは(私はすべての不要なコードを削除した)である:ソケットrecv()はデータを受信しません

while(1) 
{ 
    FD_SET(sockfd, &read_fds); 
    FD_SET(inet_sock, &read_fds); 
    for (i = 0; i < nclients; i++) 
    { 
    FD_SET(clients[i], &read_fds); 
    } 

    select(maxfd + 1, &read_fds, &write_fds, &except_fds, NULL); 

    /* Check for events on inet sock */ 
    if (FD_ISSET(inet_sock, &read_fds)) 
    { 
    /* Read from inet sock */ 
    socklen = sizeof(dest_sin); 
    rval = recvfrom(inet_sock, buf, BUFLEN-1, MSG_DONTWAIT, 
        (struct sockaddr *) &dest_sin, &socklen);   
    buf[rval]=0; 
    fprintf(stderr, "Received: %d (%d) bytes containing %s", rval, strlen(buf), buf); 

    /* Send the message to every other client */ 
    for(j=0; j < nclients; j++) 
    { 
     send(clients[j], buf, strlen(buf), MSG_DONTWAIT); 
    } 
    } 

    /* A read event on the local socket is a new connection */ 
    if (FD_ISSET(sockfd, &read_fds)) 
    { 
    socklen = sizeof(dest_sun); 
    /* Accept the new connection */ 
    rval = accept(sockfd, (struct sockaddr *) &dest_sun, &socklen); 

    /* Add client to list of clients */ 
    clients[nclients++] = rval; 
    if (rval > maxfd) maxfd = rval; 
    snprintf(s, BUFLEN, "You are client %d [%d]. You are now connected.\n\0", 
     nclients, rval); 
    send(rval, s, strnlen(s, BUFLEN), MSG_DONTWAIT); 
    } 

    /* Check for events from each client */ 
    for (i = 0; i < nclients; i++) 
    { 
    fprintf(stderr,"Checking client %d [%d] for read indicator.\n",i, clients[i]); 

    /* Client read events */ 
    if (FD_ISSET(clients[i], &read_fds)) 
    { 
     fprintf(stderr, "Client %d [%d] marked for read.\n", i, clients[i]); 

     /* Read from client */ 
     rval=recv(clients[i], buf, BUFLEN-1, MSG_DONTWAIT); 

     buf[rval]=0; 
     fprintf(stderr, "Received: %d (%d) bytes containing %s", rval, strlen(buf), buf); 

     /* Send the message to every other client */ 
     for(j=0; j < nclients; j++) 
     { 
     /* Skip the sender */ 
     if (j == i) continue; 
     /* Send the message */ 
     send(clients[j], s, strlen(s, BUFLEN), MSG_DONTWAIT); 
     } 
    } 
    } 
} 

ここで私が持っているクライアントコードは次のとおりです。

while(1) 
{ 
    FD_SET(fileno(stdin), &read_fds); 
    FD_SET(sockfd, &read_fds); 
    select(fileno(stdin) > sockfd ? fileno(stdin)+1 : sockfd+1, 
&read_fds, &write_fds, &except_fds, NULL); 

    if (FD_ISSET(sockfd, &read_fds)) 
    { 
    /* Read from socket and display to user */ 
    mlen = recv(sockfd, (void *)buf, BUFLEN-1, MSG_DONTWAIT); 
    buf[mlen]=0; 
    printf("Received %d bytes: %s", mlen, buf); 
    } 

    if (FD_ISSET(fileno(stdin), &read_fds)) 
    { 
    fgets(buf, BUFLEN, stdin); 
    fprintf(stderr, "Sent %d octets to server.", 
    send(sockfd, (void *)buf, (size_t) strnlen(buf, BUFLEN), 0)); 
    } 
} 

目標は、クライアントがデータを受信することですデーモンはそれらを送信します(デーモンがinetソケットで受け取るデータ)。

EDIT:デーモンがデータを送信すると、クライアント側のselect()はソケットが読み込み可能だが、recv()がブロックされていると判断したため、データが表示されません。クライアント側。どのようにこれを修正するための任意の提案?

send(clients[j], buf, strlen(buf),  MSG_DONTWAIT); 
send(rval,  s, strnlen(s, BUFLEN), MSG_DONTWAIT); 
send(clients[j], s, strlen(s, BUFLEN), MSG_DONTWAIT); 

私はここにいくつかの矛盾を参照してください。ここで

+0

何も飛び出さないうちに、フォームの問題と同じように、printf()文の中でsend()を発行しないでください。また、あなたはコードを削除したと言いました。実際の動作例でコードがエラーコードを返しますか? – Duck

+0

はい、実際のプログラムはエラーチェックを行います。 – ddd

+0

私に飛びつくことは、 'send'と' recv'呼び出しの戻り値を決してチェックしないことです。また、サーバーとクライアントの両方で、どのようにUDPソケットを作成しますか? –

答えて

1

は、あなたのコードからsend()コール、抽出されたと整列です。場合によってはstrlen()と、ときにはstrnlen()と、時にはstrlen()に2つの引数を付けて呼び出すこともあります(私はそのことについて何も知らない)。

あなたが見ている問題は、メッセージ間の境界がどこにあるかを示すソケットに関する情報を送信していないという事実に関連している可能性があります。ストリームソケット上で、メッセージの境界はは保存されていない、あなたは、受信機が個々のメッセージを抽出できるように、プロトコルに適切なフレーミング情報を含めるように注意する必要があります。 send()コールがあったので、recv()コールを経由してくるバイト数とまったく同じバイト数に依存することはできません。 合計(ストリームソケットのポイント)同じ順序でバイト数を取得しますが、メッセージが統合または分割され、その制御がありません。

関連する問題