Linux C 套接字 UDP 服务器。 select() 没有收到任何内容

问题描述 投票:0回答:1

自从我放入 select 语句后,我的 UDP 服务器在接受任何输入时遇到问题。目的是等待来自 2 个不同套接字(具有不同端口)的数据包。同时我也希望它能够告诉服务器何时想要向同步侦听的端口之一发送某些内容。在下面的代码中,程序运行直到到达

select()
语句,此时如果我尝试向服务器(在本地计算机上)发送某些内容,则不会接受任何内容,并且程序会挂起,等待。我也尝试注释掉
writefds
fd_set 及其附带的
FD_ISSET
但同样的事情发生了。我已经精疲力竭地试图解决这些问题,所以可能有很多事情没有意义,但我在目前的状态下尽了最大努力。我道歉。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

#define MYPORT "20444"  // the port users will be connecting to
#define MAXBUFLEN 1024 //maximum packet length
#define SERVER_R 142.66.140.13 //Server to the "right" of current
#define RTEX_R_PORT "20445" //Port for routing table exchange

typedef enum {false, true} bool;

/*struct to store packet fields into
  seq: sequence number;
  type: message type; send get ACK
  src: client's unique 10 digit number
  dst: destination's unique 10 digit number
  payload: the message being transferred, if there is any
*/
struct packet
{
   char seq[4];
   char type[5];
   char src[11];
   char dst[11];
   char payload[MAXBUFLEN];
};

// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
    if (sa->sa_family == AF_INET) {
        return &(((struct sockaddr_in*)sa)->sin_addr);
    }

    return &(((struct sockaddr_in6*)sa)->sin6_addr);
}

int main(void)
{
   //rr: reading from server to the "right"
   //rw: writing to the server to the "right"
   int sockfd, rtex_rr_sockfd, rtex_rw_sockfd, rv, rrr, rrw, numbytes, i, j, first, max_fd;
   struct addrinfo hints, *servinfo, *p, *p2, *p3;
   struct sockaddr_storage their_addr, right_addr;
   fd_set readfds, writefds;
   char buf[MAXBUFLEN];
   char temp_buf[MAXBUFLEN];
   char d_to_s[MAXBUFLEN];
   char *field;
   socklen_t addr_len;
   char s[INET6_ADDRSTRLEN];
   FILE *m_storage;
   struct packet inet_packet;
   static const struct packet EmptyPacket;
   static int rt[51][4];
   bool re_exists=false;
   bool rt_empty=true;
   struct timeval tv;

   memset(&hints, 0, sizeof hints);//"zero out" the hints struct
   hints.ai_family = AF_UNSPEC; // set to AF_INET to force IPv4
   hints.ai_socktype = SOCK_DGRAM;
   hints.ai_flags = AI_PASSIVE; // use my IP

   //prepare socket address structures and store them in servinfo and store in linked list
   if ((rv = getaddrinfo(NULL, MYPORT, &hints, &servinfo)) != 0) {
      fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
      return 1;
   }

   // loop through all the results and bind to the first we can
   for(p = servinfo; p != NULL; p = p->ai_next) {
      if ((sockfd = socket(p->ai_family, p->ai_socktype,
               p->ai_protocol)) == -1) {
     perror("listener: socket");
     continue;
      }

      if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
     close(sockfd);
     perror("listener: bind");
     continue;
      }

      break;
   }

   if (p == NULL) {
      fprintf(stderr, "listener: failed to bind socket\n");
      return 2;
   }

   if ((rrr = getaddrinfo(NULL, RTEX_R_PORT, &hints, &servinfo)) != 0) {
      fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rrr));
      return 1;
   }

   for(p2 = servinfo; p2 != NULL; p2 = p2->ai_next) {
      if ((rtex_rr_sockfd = socket(p2->ai_family, p2->ai_socktype,
               p2->ai_protocol)) == -1) {
     perror("listener: socket");
     continue;
      }

      if (bind(rtex_rr_sockfd, p2->ai_addr, p2->ai_addrlen) == -1) {
     close(rtex_rr_sockfd);
     perror("listener: bind");
     continue;
      }
      break;
   }

   if (p2 == NULL) {
      fprintf(stderr, "listener: failed to bind socket\n");
      return 2;
   }

   if((rrw = getaddrinfo(NULL, RTEX_R_PORT, &hints, &servinfo)) != 0) {
      fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rrw));
      return 1;
   }

   for(p3 = servinfo; p3 != NULL; p3 = p3->ai_next) {
      if((rtex_rw_sockfd = socket(p3->ai_family, p3->ai_socktype,
                  p3->ai_protocol)) == -1) {
     perror("server: socket");
     continue;
      }
      break;
   }

   if (p3 == NULL) {
      fprintf(stderr, "listener: failed to bind socket\n");
      return 2;
   }

   //free up memory no longer needed after binding has completed
   freeaddrinfo(servinfo);

   FD_ZERO(&readfds);
   FD_ZERO(&writefds);
   FD_SET(rv, &readfds);
   FD_SET(rrr, &readfds);
   FD_SET(rrw, &writefds);

   printf("Listen Mode\n");

   //main while loop, listens for packets.
   //Upon receipt of packet, information is stored in a struct for processing.
   first=0;
   while(1)
   {
      i=0;
      inet_packet = EmptyPacket;
      rt_empty=true;
      tv.tv_sec = 50;
if(rv > rrr && rv > rrw)
     max_fd = (rv + 1);
      else if(rrr > rv && rrr > rrw)
     max_fd = (rrr + 1);
      else if(rrw > rv && rrw > rrr)
     max_fd = (rrw + 1);

      printf("before select...\n");
      select(max_fd, &readfds, &writefds, NULL, NULL);
      printf("after select...\n");
      addr_len = sizeof their_addr;

      if(FD_ISSET(rv, &readfds))
      {
     printf("rv is set...\n");
     if((numbytes = recvfrom(sockfd, buf, sizeof(buf), 0,
                 (struct sockaddr *)&their_addr, &addr_len)) == -1) {
        perror("recvfrom");
        exit(1);
     }
      } else if(FD_ISSET(rrr, &readfds))
      {
     printf("rr read is set...\n");
     if((numbytes = recvfrom(rtex_rr_sockfd, buf, sizeof(buf), 0,
                  (struct sockaddr *)&right_addr, &addr_len)) == -1) {
        perror("recvfrom");
        exit(1);
     }
      } else if(FD_ISSET(rrw, &writefds))
      {
     printf("rr write is set...\n");
     if((numbytes = sendto(rtex_rw_sockfd, inet_packet.payload, sizeof(inet_packet.payload),
                   0, p3->ai_addr, p3->ai_addrlen)) == -1) {
        perror("sendto rr");
        exit(1);
     }
  }
c linux sockets posix-select
1个回答
1
投票

运行您的程序并在启动后在终端按 Enter 键。它可能会从选择中返回。为什么?因为你唯一告诉 select 听的是 fd 0, stdin!

rv
rrr
rrw
都只是
getaddrinfo()
的返回值,而您只是忽略了
socket()
返回的实际 fd。
max_fd
也将是一个垃圾值,因为所有测试值都彼此相等。 (如果它恰好为零,它甚至不会对标准输入做出反应)

另外,下次请将代码简化为最小示例。如果您的问题是选择不返回,那么例如。所有处理代码完全无关,一个套接字就足够了,使用

getaddrinfo()
是额外的。另外,为了一个最小的例子,您可能在删除
getaddrinfo()
内容时自己发现了错误。

© www.soinside.com 2019 - 2024. All rights reserved.