2014-03-18 15 views
0

我正在创建一个简单的服务器/客户端UDP套接字程序,并且遇到了问题。recvfrom重新读取套接字上的数据

问题是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

在执行print()调用的任何其他系统调用(如write()之前,必须调用perror()。否则,错误值可能会更改,并且会显示误导性错误消息。 – EJP

回答

2
  1. 在故障情况下(即如果recvfrom的或者当超时select返回),你也正在返回“缓冲”未初始化,使得内容可以previsous数据,但该行为是不确定的。因此,最好在调用recvfrom之前将它初始化为0(memset(& buffer,0,sizeof(struct packet)))

  2. 在while循环中检查(receivedPacket.flags == NORMAL ),如果NORMAL
    那么只有你正在打印缓冲区并再次调用该函数。

    在上选择超时或recvfrom的失败(S)显式 更新“receivedPacket.flags”中的“receivePacket”功能otherthen师范大学让您while循环 休息。

+0

我试过第二个答案,但没有奏效。 'Memsetting'缓冲区设置为0,但确实有效,也消除了我遇到的一些其他问题。谢谢! – user3255596

+1

这不是第二个答案,你需要做接受者提及的两点(1和2) –

+0

好吧,会做。 – user3255596