11

クライアントとサーバーがあります。クライアントに 2 つの read() があり、サーバー コードに 2 つの write() があります。サーバーは最初の write() でクライアントにデータを送信し、クライアントは読み取りとバッファーへの保存を行いますが、読み取りを停止せず、サーバーの 2 番目の write() を読み取り続けます。ストリームで255を読んでください(私の理解から)。最初の write() のデータ データ サイズがどのくらいの長さかわからないため、255 を入れました。これを修正するにはどうすればよいですか?

クライアント:

n = read(sockfd,buffer,255);
if (n < 0) 
     error("ERROR reading from socket");
      printf("%s\n",buffer);

 n = read(sockfd,buffer,255);
if (n < 0) 
     error("ERROR reading from socket");
      printf("%s\n",buffer);

サーバ:

  n = write(newsockfd,datasize,strlen(datasize));
if (n < 0) error("ERROR writing to socket");

n = write(newsockfd,data,255);
if (n < 0) error("ERROR writing to socket");
4

4 に答える 4

14

あなたが経験しているのは、TCP がどのように機能するかです。クライアントが を呼び出す前にサーバーが をwrite()複数回呼び出す場合read()read()指定した最大バッファ サイズまで、以前に書き込まれたすべてのデータを受け取ることができます。TCP には、UDP のようなメッセージ境界の概念がありません。それは何も悪いことではありません。あなたはそれを説明する必要があるだけです、それだけです。

あるメッセージがどこで終わり、次のメッセージが始まるかを知る必要がある場合は、単にメッセージを組み立てるだけです。これを行うには、いくつかの方法があります。

  1. 実際のデータを送信する前にデータ長を送信して、クライアントが読み取るデータ量を認識できるようにします。たとえば、次のようになります。

    サーバ:

    int datalen = ...; // # of bytes in data
    int tmp = htonl(datalen);
    n = write(newsockfd, (char*)&tmp, sizeof(tmp));
    if (n < 0) error("ERROR writing to socket");
    n = write(newsockfd, data, datalen);
    if (n < 0) error("ERROR writing to socket");
    

    クライアント:

    int buflen;
    n = read(sockfd, (char*)&buflen, sizeof(buflen));
    if (n < 0) error("ERROR reading from socket");
    buflen = ntohl(buflen);
    n = read(sockfd, buffer, buflen);
    if (n < 0) error("ERROR reading from socket");
    else printf("%*.*s\n", n, n, buffer);
    
  2. 実際のデータには表示されない区切り文字でデータをラップすると、クライアントは読み取りを続けてそれらの区切り文字を探すことができます。データに適した区切り文字 (STX/ETX、改行、特別な予約文字など) を使用します。

    サーバ:

    char delim = '\x2';
    n = write(newsockfd, &delim, 1);
    if (n < 0) error("ERROR writing to socket");
    n = write(newsockfd, data, datalen);
    if (n < 0) error("ERROR writing to socket");
    delim = '\x3';
    n = write(newsockfd, &delim, 1);
    if (n < 0) error("ERROR writing to socket");
    

    クライアント:

    char tmp;
    
    do
    {
        n = read(sockfd, &tmp, 1);
        if (n < 0) error("ERROR reading from socket");
    
        if (tmp != '\x2')
            continue;
    
        buflen = 0;
    
        do
        {
            n = read(sockfd, &tmp, 1);
            if (n < 0) error("ERROR reading from socket");
    
            if (tmp == '\x3')
                break;
    
            // TODO: if the buffer's capacity has been reached, either reallocate the buffer with a larger size, or fail the operation...
            buffer[buflen] = tmp;
            ++buflen;
        }
        while (1);
    
        printf("%*.*s\n", buflen, buflen, buffer);
        break;
    }
    while (1);
    
于 2013-10-01T23:15:39.817 に答える
3

1 回の読み取りで、1 回の書き込みで書き込まれた内容が正確に読み取られるとは限りません。TCP はバイト ストリーム プロトコルです。メッセージの境界はありません。read() は、送信側でも受信側でも制御できない、到着したデータに応じて、1 バイトから指定した長さまで読み取ることができます。また、TCP が発信書き込みを 1 つのセグメントに結合するかどうかを制御することもできません。

メッセージが必要な場合は、自分で実装する必要があります。たとえば、行、長さの単語のプレフィックス、タイプの長さの値、STX/ETX、XML などです。

注意 エラーが発生した場合、自分で考案したメッセージを出力するだけではいけません。エラーを印刷します。この場合、'perror()' を呼び出すか、'strerror' でフォーマットされた文字列を作成します。

于 2013-10-01T23:03:53.967 に答える
0

ソケット == バイトのストリーム。パケット化などは行われません。したがって、サーバーがクライアントに 2 つのパケットを送信する必要がある場合は、クライアントがそれぞれを区別できるように何かを行う必要があります。たとえば、サーバーがそれぞれ 255 バイトずつ 2 つのパケットを送信する必要があると判断した場合、1 つのパケットを受信するクライアント プロシージャは次のようになります。

int count = 0;
while (count < 255) {
    n = read(sockfd, buffer + count, 255 - count);
    if (n < 0) {
         error("ERROR reading from socket");
          printf("%s\n",buffer);
         return;
    } 
    count += n;
}
// here buffer has 255 bytes for the packet

0 から 255 の間の任意の数値、またはソケットが閉じられている場合は負の値を読み取ることができるため、プログラムにはサイクルがあります。2 番目のパケットについても同じことができます。パケットのサイズが異なる場合は、サーバーからクライアントにパケット サイズを伝える必要があります。最初の 2 バイトでパケットの長さを送信し、上記のコードで定数 255 の代わりに数値を使用できます。

于 2013-10-01T23:12:34.020 に答える