この問題を回避するにはどうすればよいですか?
したがって、TCP(バイトストリーム指向の転送メカニズム)を使用していますが、メッセージ指向の動作が必要です。 TCPが動作する方法を変更することはできません(バイトがすべて受信され、同じ順序で受信される限り、どのようなサイズのグループでもバイトを転送することができます)。しかし、TCPの上にレイヤーを追加して、パケット指向の動作をシミュレートすることができます。
たとえば、1000バイトの「パケット」の送信をシミュレートするとします。
size_t myPacketSize = 1000; // or whatever the size of your packet is
uint32_t bePacketSize = htonl(myPacketSize); // convert native-endian to big-endian for cross-platform compatibility
if (send(sd, &bePacketSize, sizeof(bePacketSize), 0) != sizeof(bePacketSize))
{
perror("send(header)");
}
....そして、その直後:あなたの送信プログラムは、最初(4バイト、のは言わせて)「パケット」は含まれていますバイトどのように多くの受信機を言うだろうヘッダーを固定サイズを送ることができあなたは、パケットのペイロードデータを送信したい:
if (send(sd, packetDataPtr, myPacketSize, 0) != myPacketSize)
{
perror("send(body)");
}
受信機は、ヘッダ/サイズ値を受け取り、その大きさの配列を割り当て、そこにペイロードデータを受信する必要があります。それは、パケットが様々に組み合わされていることではないということ
void HandleReceivedPseudoPacket(const char * packetBytes, uint32_t packetSizeBytes)
{
// Your received-packet-handling code goes here
}
// Parses an incoming TCP stream of header+body data back into pseudo-packets for handling
void ReadPseudoPacketsFromTCPStreamForever(int sd)
{
uint32_t headerBuf; // we'll read each 4-byte header's bytes into here
uint32_t numValidHeaderBytes = 0; // how many bytes in (headerBuf) are currently valid
char * bodyBuf = NULL; // will be allocated as soon as we know how many bytes to allocate
uint32_t bodySize; // How many bytes (bodyBuf) points to
uint32_t numValidBodyBytes = 0; // how many bytes in (bodyBuf) are currently valid
while(1)
{
if (bodyBuf == NULL)
{
// We don't know the bodySize yet, so read in header bytes to find out
int32_t numBytesRead = recv(sd, ((char *)&headerBuf)+numValidHeaderBytes, sizeof(headerBuf)-numValidHeaderBytes, 0);
if (numBytesRead > 0)
{
numValidHeaderBytes += numBytesRead;
if (numValidHeaderBytes == sizeof(headerBuf))
{
// We've read the entire 4-byte header, so now we can allocate the body buffer
numValidBodyBytes = 0;
bodySize = ntohl(headerBuf); // convert from big-endian to the CPU's native-endian
bodyBuf = (char *) malloc(bodySize);
if (bodyBuf == NULL)
{
perror("malloc");
break;
}
}
}
else if (numBytesRead < 0)
{
perror("recv(header)");
break;
}
else
{
printf("TCP connection was closed while reading header bytes!\n");
break;
}
}
else
{
// If we got here, then we know the bodySize and now we need to read in the body bytes
int32_t numBytesRead = recv(sd, &bodyBuf[numValidBodyBytes], bodySize-numValidBodyBytes, 0);
if (numBytesRead > 0)
{
numValidBodyBytes += numBytesRead;
if (numValidBodyBytes == bodySize)
{
// At this point the pseudo-packet is fully received and ready to be handled
HandleReceivedPseudoPacket(bodyBuf, bodySize);
// Reset our state variables so we'll be ready to receive the next header
free(bodyBuf);
bodyBuf = NULL;
numValidHeaderBytes = 0;
}
}
else if (numBytesRead < 0)
{
perror("recv(body)");
break;
}
else
{
printf("TCP connection was closed while reading body bytes!\n");
break;
}
}
}
// Avoid memory leak if we exited the while loop in the middle of reading a psuedo-packet's body
if (bodyBuf) free(bodyBuf);
}
注:このコードは正常に関係なく、それぞれのrecv()の呼び出しによって返されるバイト数、受信データを処理しないために持っているので、それは少し複雑送信コードよりもですあなたが各recv()呼び出しから出てくるバイトシーケンスのサイズは、ネットワークパケットのサイズとは無関係であることに注意してください。 –
答えは、TCPがストリーミングプロトコルであるため、TCPではなくUDPを使用することです。あなたはパケットのようなものがないので、どのようにパケットが受信されるのかは、サーバまたはクライアント上で決して頼りすぎてはいけません。これは、カーネルの動作に影響を与える遅延のために経験した方法で受信されるようなバイトの連続ストリームです。 –