【问题标题】:recvfrom re-reading data on socketrecvfrom 重新读取套接字上的数据
【发布时间】:2014-03-18 17:47:46
【问题描述】:

我正在创建一个简单的服务器/客户端 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
........

【问题讨论】:

  • 您必须在执行任何其他系统调用(例如由 printf() 调用的 write() 之前)调用 perror()。否则 errno 值可能会发生变化,并且您会打印出误导性的错误消息。

标签: sockets unix udp recvfrom


【解决方案1】:
    1234563所以最好在调用 recvfrom 之前将其初始化为 0 (memset(&buffer,0,sizeof(struct packet)))
  1. 在 while 循环中,您正在检查 (receivedPacket.flags == NORMAL) ,如果 NORMAL
    那么只有你在打印缓冲区并再次调用该函数。

    在“receivePacket”函数中明确选择超时或recvfrom failure(s) 将“receivedPacket.flags”更新为其他 NORMAL 以便您处于 while 循环 休息。

【讨论】:

  • 我尝试了第二个答案,但没有奏效。 'Memsetting' 缓冲区为 0 确实有效,并且还消除了我遇到的其他一些问题。谢谢!
  • 这不是第二个答案,您需要注意提到的两点(1和2)
猜你喜欢
  • 2015-01-09
  • 2022-11-24
  • 1970-01-01
  • 1970-01-01
  • 2020-09-08
  • 2023-03-04
  • 1970-01-01
  • 2014-06-07
相关资源
最近更新 更多