我在 C 中模拟 Windows 上的 TCP 通信。我有发送者和接收者通信。
发送方将特定大小的数据包发送给接收方。接收方获取它们并将接收到的每个数据包的 ACK 发送回发送方。如果发送方没有收到特定的数据包(它们在数据包内的标头中编号),它会再次将数据包发送给接收方。这是接收方的 getPacket 函数:
//get the next packet from the socket. set the packetSize to -1
//if it's the first packet.
//return: total bytes read
// return: 0 if socket has shutdown on sender side, -1 error, else number of bytes received
int getPakcet(char* chunkBuff, int packetSize, SOCKET AcceptSocket)
{
int totalChunkLen = 0;
int bytesRecv = -1;
bool firstTime = false;
if(packetSize == -1)
{
packetSize = MAX_PACKET_LENGTH;
firstTime = true;
}
int needToGet = packetSize;
do
{
char* recvBuff;
recvBuff = (char*)calloc(needToGet, sizeof(char));
if(recvBuff == NULL)
{
fprintf(stderr, "Memory allocation problem\n");
return -1;
}
bytesRecv = recv(AcceptSocket, recvBuff, needToGet, 0);
if(bytesRecv == SOCKET_ERROR)
{
fprintf(stderr, "recv() error %ld.\n", WSAGetLastError());
totalChunkLen = -1;
return -1;
}
if(bytesRecv == 0)
{
fprintf(stderr, "recv(): socket has shutdown on sender side");
return 0;
}
else if(bytesRecv > 0)
{
memcpy(chunkBuff + totalChunkLen, recvBuff, bytesRecv);
totalChunkLen += bytesRecv;
}
needToGet -= bytesRecv;
}
while((totalChunkLen < packetSize) && (!firstTime));
return totalChunkLen;
}
我使用firstTime
是因为第一次接收方不知道发送方要发送给它的正常包大小,所以我使用 aMAX_PACKET_LENGTH
来获取一个包,然后将正常包大小设置为我收到的字节数.
我的问题是最后一个包裹。它的尺寸小于包装尺寸。所以让我们说最后一个包大小是2,正常包大小是4。所以recv()
得到两个字节,继续while条件,然后totalChunkLen < packetSize
因为2<4
它再次迭代循环并且卡住了,recv()
因为它阻塞了,因为发送者没有什么可以发送.
在发送方我无法关闭连接,因为我没有收到 ACK,所以这是一种死锁。接收方卡住了,因为它正在等待更多的包裹,但发送方没有任何东西要发送。
我不想使用超时recv()
或在包头中插入一个特殊字符来标记它是最后一个。
我能做些什么?