我正在创建一个简单的服务器/客户端UDP套接字程序,但我遇到了问题。
问题是recvfrom()函数继续重新读取最后发送的数据。
因此,如果我从客户端向服务器发送两个数据包,则recvfrom()将读取第一个数据包并打印其数据,然后它将不断地反复读取第二个数据包。
据我了解,一旦执行成功的读取操作,应该从套接字中删除数据包,但这似乎并没有发生。
我知道客户端不会重新发送数据,因为只要客户端发送数据就会写入控制台输出。
这里是发件人的功能
int sendPacket(int socketFd, int type, char *typeString, char *data, int seq, int windowSize, struct sockaddr_in serverName) {
struct packet *sendPacketPtr, sendPacket;
fd_set writeFdSet;
sendPacketPtr = &sendPacket;
sendPacket.flags = type;
sendPacket.windowsize = windowSize;
sendPacket.seq = seq;
sendPacket.id = getpid();
if (type == NORMAL)
strcpy(sendPacket.data, data);
FD_ZERO(&writeFdSet);
FD_SET(socketFd, &writeFdSet);
if(select(FD_SETSIZE, NULL, &writeFdSet, NULL, NULL) > 0) {
if(sendto(socketFd, sendPacketPtr, sizeof(sendPacket), 0, (struct sockaddr *)&serverName, sizeof(serverName)) < 0) {
printf("%s packet was not sent\n", typeString);
perror("Send error");
} else {
printf("%s packet was sent\n", typeString);
}
}
return 0;
}
使用此循环调用哪个循环对其给定值运行两次。
for (int i = seqBase; i <= seqMax && i < packetNum; i++) {
sendPacket(socketFd, NORMAL, "DATA", dataArray[i], i, 0, serverName);
}
接收功能
struct packet receivePacket (int socketFd, struct sockaddr_in *address, int timeout, int useTimeout) {
struct packet buffer;
fd_set readFdSet;
struct sockaddr_in dest_addr;
struct timeval selectTimeout;
selectTimeout.tv_usec = 0;
selectTimeout.tv_sec = timeout;
FD_ZERO(&readFdSet);
FD_SET(socketFd, &readFdSet);
socklen_t len = sizeof(dest_addr);
if(useTimeout == 0) {
if(select(FD_SETSIZE, &readFdSet, NULL, NULL, NULL) > 0) {
if(recvfrom(socketFd, &buffer, sizeof(buffer), 0, (struct sockaddr *)&dest_addr, &len) < 0) {
perror("Read error");
}else {
*address = dest_addr;
}
}
}else {
if(select(FD_SETSIZE, &readFdSet, NULL, NULL, &selectTimeout) > 0) {
if(recvfrom(socketFd, &buffer, sizeof(buffer), 0, (struct sockaddr *)&dest_addr, &len) < 0) {
perror("Read error");
}else {
*address = dest_addr;
}
}
}
return buffer;
}
使用此循环从服务器调用
receivedPacket = receivePacket(socketFd, &destAddress, 0, 0);
while (receivedPacket.flags == NORMAL) {
printf("Data received: \"%s\", sequence: %d\n", receivedPacket.data, receivedPacket.seq);
receivedPacket = receivePacket(socketFd, &destAddress, TIMEOUT, 1);
}
永远运行的输出(因为它不断重读最后一个数据包)是:
Data received: "Packet 0", sequence: 0
Data received: "Packet 1", sequence: 1
Data received: "Packet 1", sequence: 1
Data received: "Packet 1", sequence: 1
Data received: "Packet 1", sequence: 1
........
答案 0 :(得分:2)
在失败的情况下(即如果recvfrom或当select超时返回时),你也会返回未初始化的“缓冲区”,因此内容可以是预先存储的数据,但行为未定义。因此,最好在调用recvfrom之前将其初始化为0(memset(&amp; buffer,0,sizeof(struct packet)))
在你正在检查的while循环中(receivedPacket.flags == NORMAL),如果是正常的话 然后只有你打印缓冲区并再次调用该函数。
在“receivePacket”函数中选择超时或recvfrom failure(s)明确 将“receivedPacket.flags”更新为“正常”,这样你就可以进行while循环了 断裂。