4

Winsockについて学び、単純な文字列を送受信するときに奇妙な問題が発生することを学びました。これが私のコードです(純粋なC):

クライアント:



//...
//Declarations and stuff

//----------- SEND SOME DATA -------------------------------------------------

    char string1[] = "string-1";
    int bytes_sent = 0;

    bytes_sent = send(client_socket, string1, strlen(string1), 0);  

    printf("BYTES SENT: %i\n", bytes_sent);
    printf("\n-----------------------------------------------\n\n");

    system("pause");

//...

サーバ:



//...
//Declarations and stuff

//----------- START LISTENING FOR REQUESTS ------------------------------------

    SOCKET ClientSocket;

    #define BUFFER_SIZE 256

    int size;
    struct sockaddr_in client_info;
    char client_ip[16];
    char data_received[BUFFER_SIZE];    
    int bytes_received = 0; 

    listen(ListenSocket, SOMAXCONN);

    while(1){           

        ClientSocket = accept(ListenSocket, (struct sockaddr *)&client_info, &size);        
        strcpy(client_ip, inet_ntoa(client_info.sin_addr));     

        do{

            bytes_received = recv(ClientSocket, data_received, BUFFER_SIZE, 0);

            if(bytes_received > 0){
                printf("DATA RECEIVED FROM %s: %s (%i bytes)\n", client_ip, data_received, bytes_received);
            }


        }while(bytes_received > 0);

        printf("\n-----------------------------------------------\n\n");


    }

//...

問題は、サーバーが私の文字列といくつかの奇妙な記号を出力することです(写真を参照)。

奇妙なシンボル

ストリームソケットを使用しています。例は非常に単純なので、何が間違っているのかわかりません。文字列またはサーバーのバッファサイズ、あるいはその両方をランダムに変更すると、問題は解消されます(サーバーは文字列をOKで出力します)。send()呼び出しでstrlen()の代わりにsizeof()を使用すると、問題が修正されます。ここで少し迷子になりました。私が何かを逃した場合は親切にしてください、これはここでの私の最初の投稿です。コード全体(基本的にはwinsockの開始とソケットの定義)を提供できます。

4

3 に答える 3

9

送信するデータに終了ヌル文字が含まれていません。

bytes_sent = send(client_socket, string1, strlen(string1), 0);

...strlen終了するnullをカウントしないため。これはそれ自体が問題ではなく、受信側で次のような事実と結びついています。

char data_received[BUFFER_SIZE];
// ...
bytes_received = recv(ClientSocket, data_received, BUFFER_SIZE, 0);

data_receivedBUFFER_SIZEは初期化されておらず、最大バイトを受信できます。これは、送信するデータがnullで終了していないため、次のことを意味します。

  • の場合bytes_received < BUFFER_SIZE、残りの部分は初期化されないdata_received 可能性があるため、アクセス/印刷は未定義の動作になります。ドキュメントに記載されているように、実際には100%明確ではありません。

    [...] recvを呼び出すと、現在利用可能なデータと同じ量のデータが返されます—指定されたバッファのサイズまで[...]

    ...つまり、バッファの残りの部分はそのままにしておくことを意味する場合があります。

  • の場合bytes_received == BUFFER_SIZE、nullターミネータがないためprintf、文字列がどこで停止するかわからず、配列をオーバーランするため、nullターミネータを出力しようとして未定義動作を呼び出します。

これらを修正する最も簡単な方法は、ヌルターミネータを送信することです。

bytes_sent = send(client_socket, string1, strlen(string1)+1, 0); // +1 here
bytes_sent = send(client_socket, string1, sizeof(string1), 0);   // same as above

...または1バイト少なく受信し、受信サイズにnullターミネータを配置します。

bytes_received = recv(ClientSocket, data_received, BUFFER_SIZE-1, 0); // -1 here
data_received[bytes_received] = 0;

私は個人的に最初のものと一緒に行きます。

于 2013-01-18T18:32:48.393 に答える
3

したがって、問題は、終了NULバイトを送信していないが、受信した文字列をC文字列として扱っているように見えることです(つまり、NULで終了していると想定します)。それを修正するには、代わりに

bytes_sent = send(client_socket, string1, strlen(string1), 0);

書きます

bytes_sent = send(client_socket, string1, strlen(string1) + 1, 0);

また、「誰も使用しない」とおっしゃっていstrlen(s) + 1ましたが、これはおそらく受信側で受信したバイト数に注意を払っているからでしょう。

于 2013-01-18T18:33:10.987 に答える
-1

すべての文字列データの長さを設定してから、次のようにサーバーで文字列を終了してみてください。

bzero(data_received, sizeof(data_received));
bytes_received = recv(ClientSocket, data_received, BUFFER_SIZE, 0);
data_received[bytes_received] = '\0';

これが解決しない場合は、おそらく@ H2CO3を使用すると、質問内容をよりよく読むことができます:]

于 2013-01-18T18:21:19.543 に答える