2

以下は、ソケットプログラミングに問題があるコードフラグメントです。ここでselect呼び出しの後、Windows XP で 9 行目をスリープしないと、11 行目で 1 バイトが受信され (代わりにサーバーから整数として 4 バイトが送信されます)、xmlSize を確認すると 0 に設定されます。 iResult が 1 であるため実行が継続され、15 行目で xmlSize=0 で receive が呼び出され、iResult=0 接続が閉じられているため、iResult が 0 以降に設定されます。

しかし、Windows 7 ではこれは発生せず、プログラムは問題なく 4 バイトを読み取り、通常の実行を続けました。ただし、XPではスリープ(これを作成したばかり)で動作しましたが、なぜですか??

このコードの欠陥は何ですか?

1   while(is_running())
2   {
3       FD_ZERO(&readfds);
4       FD_SET(server_socket, &readfds);
5       iResult = select(server_socket+1, &readfds, NULL, NULL, &tv);
6       if  (!(iResult != SOCKET_ERROR && FD_ISSET(server_socket, &readfds) )) {
7           continue;
8       }
9       Sleep(500); // This Sleep is not required on Windows 7, but is required on 10 XP but WHY? 
11      iResult = recv(server_socket, (char *)&xmlSize, sizeof(xmlSize), 0);
12      xmlSize = htonl(xmlSize);
13      if ( iResult > 0 ){
13          printf("Bytes received: %d, XML Size:%d", iResult, xmlSize);
14          
15          iResult = recv(server_socket, xml, xmlSize, 0);
16          if ( iResult > 0 ){
17              xml[xmlSize] = '\0';
18              printf("Bytes received: %d", iResult);              
19              operation_connection(xml);
20          }
21          else if ( iResult == 0 ){
22              printf(LL_INTERR, CLOG("Connection closed"));
23              break;
24          }
25          else{
26              printf("recv failed with error: %d", WSAGetLastError());
27              break;
28          }
29      }
30      else if ( iResult == 0 ){
31          printf(LL_INTERR, CLOG("Connection closed"));   
32          break;
33      }
34      else{
35          printf("recv failed with error: %d", WSAGetLastError());
36          break;
37      }
38  }
4

2 に答える 2

7

これが TCP ソケットであれば、気にする必要はありません。ソケットはstreamwrite()を配信します。これは、元の s のサイズにまったく対応していません。

メガバイトを 100 万の 1 バイトread()s、または単一の 1MB として、またはその間の任意の組み合わせとして配信できます。

TCP 接続で配​​信されたデータの「チャンク」のサイズに依存している場合、それは間違っています。

ある種のメッセージ区切りが必要な場合は、HTTP などで改行 + 改行が使用されるように、プロトコルに明示的に設計します。プロトコルが ASCII であるため、これらの特定のバイトを使用してメッセージを分離できない場合、2 つの従来のアプローチがあります。

  • 他のバイト シーケンス、おそらく ASCII 0x1E、「レコード セパレータ」を使用します。
  • メッセージに CR+LF が含まれている場合はエスケープして、「プレーンな」ものをセパレーターとして機能させます。プロトコルがテキストであることを「望んでいる」場合、これはより良い解決策です。

もう 1 つの方法は、ストリーム自体の各メッセージの長さを、できればプレフィックスとして明示的にエンコードすることです。これにより、予想されるデータ量がわかります。

于 2010-02-01T11:42:30.747 に答える
3

回答とコード例については、この他のSOの質問を参照してください。

ソケットからの読み取り:少なくともxバイトを取得することが保証されていますか?

于 2010-02-01T12:08:15.870 に答える