1

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

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 ソケットで受信するデータ) をすぐにクライアントに受信させることです。

編集:デーモンがデータを送信すると、クライアント側の select() はソケットが読み取り可能であることを返しますが、recv() がブロックされているため、クライアント側でデータを取得していないことがわかりました。これを修正する方法について何か提案はありますか?

4

1 に答える 1

1

コードからのsend()呼び出しを抽出して整列させたものを次に示します。

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);

ここにいくつかの矛盾が見られます。を呼び出すこともあれば、 を呼び出すstrlen()こともありstrnlen()strlen()引数を 2 つ指定することもあります (それが何をするのかさえわかりません)。

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

于 2012-04-11T00:13:50.267 に答える