3

重複の可能性:
C/C++ で TCP ソケットから読み取る正しい方法は何ですか?

TCP クライアント/サーバーを開発しようとしています。私の問題は、クライアントからデータを送信しようとすると、一度に送信することです。

しかし、特定の構造を持つデータを受信しようとすると問題が発生します。つまり、最初の 8 バイトで日付を設定し、次の 10 バイトで名前を設定し、未定義のバイト数でテキストを設定します (このテキストは /r/n で終わります) /r/n)

クライアントは次のように送信します。

char date[8];
char name[10];
char msg[4096];

strcpy(msg,"12/10/12"); //8 bytes
strcat(msg,"Kevin Fire"); //10 bytes
strcat(msg,"abcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcde\r\n\r\n");

nbytes_sent = send(sock,(char *)msg,sizeof(msg),0);
printf("Bytes_sent: %s -> %i\n",msg,nbytes_sent);

サーバーは、次のようにソケットからのデータを解析しようとします。

char date[8];
char name[10];
char * text;
char buf[1024];

int i=0;
for(i=0; i < 8; i++)
    date[i] = '\0';
for(i=0; i < 10; i++)
    name[i] = '\0';

nbytes_read=recv(sclient,(char *)date,sizeof(date),0);
if(nbytes_read > 0){
    printf("Date: %s (%i)\n",date,nbytes_read);
    //cout.flush();
    nbytes_read=recv(sclient,(char *)name,sizeof(name),0);
    if(nbytes_read > 0){
        printf("Name: %s (%i)\n",name,nbytes_read);
        //cout.flush();
        nbytes_read=recv(sclient,(char *)buf,sizeof(buf),0);
        strcpy(text,buf);
        while(nbytes_read > 0){
            nbytes_read=recv(sclient(char*)buf,sizeof(buf),0);
            strcat(text,buf);
        }
    }
}

printf("Date: %s. Name: %s. Text: %s\n",date,name,text);
4

3 に答える 3

6

簡単な「すべてを受け取る」機能は次のとおりです。

int recv_all(int sockfd, void *buf, size_t len, int flags)
{
    size_t toread = len;
    char  *bufptr = (char*) buf;

    while (toread > 0)
    {
        ssize_t rsz = recv(sockfd, bufptr, toread, flags);
        if (rsz <= 0)
            return rsz;  /* Error or other end closed cnnection */

        toread -= rsz;  /* Read less next time */
        bufptr += rsz;  /* Next buffer position to read into */
    }

    return len;
}
于 2012-10-02T18:35:54.647 に答える
1

@hmjdの検索に追加:

vardeclsで宣言されているのはテキストポインタです...

char * text;

じゃあ後で...

strcpy(text,buf);
while(nbytes_read > 0){
   nbytes_read=recv(sclient(char*)buf,sizeof(buf),0);
   strcat(text,buf);
}

たぶん、ランダムなスタック値の横にあるものにその「テキスト」ポインタを設定してみてください。

弾幕を続けると、以下は必ずしも爆発するわけではありませんが、date変数は次のようになります。

char date[8];

クライアント側とサーバー側の両方でクライアント変数はまったく使用されません。ただし、サーバー変数は次のとおりです。

nbytes_read=recv(sclient,(char *)date,sizeof(date),0);
if(nbytes_read > 0){

問題は、送信した日付が実際にはすでに8文字幅であるということです:「12/10/12」。したがって、文字列の最後にnullターミネータを固定した場合でも、これは常に関係なく実行する必要があります(グッドプラクティス)。

date[ sizeof(date)/sizeof(date[0])-1 ] = 0;

日付の最後の文字を切り捨てます。

これには他にも問題があります。ほんの少しだけ指摘しました。配列内のこれらのデータ値のそれぞれに長さプレフィックスを送信し、期待どおりの結果が得られるようにチェックまたは範囲を指定することを検討してください。

最後に、デバッガーのビジネスエンドに時間を費やすと、特にサーバー側で非常にうまくいくでしょう。

于 2012-10-02T14:19:22.137 に答える
1

1つの(繰り返される)間違いは次のとおりです。

nbytes_read=recv(sclient,(char *)date,sizeof(date),0);

recv()null 終了しません。これは、バイトが読み取られたdate場合、null ターミネータがないことを意味します。sizeof(date)これは、NULL で終了しない文字列が引数としてprintf()with"%s"フォーマット指定子に渡された場合に問題になります。文字列が null で終了していない場合、実際の文字列データの後に不要な文字が表示されることがあります。ターゲット バッファーよりも 1 つ少ない値を読み取り、null 終了するか、null 終了"%*.s"を必要としない形式指定子を使用する必要があります。

printf("%.*s", n, s); /* Prints first 'n' bytes from 's'. */

char[]aを使用する代わりに、a をすべての null に初期化できることに注意してforください。

char date[8] = "";

または使用できますmemset()

于 2012-10-02T14:12:15.113 に答える