简体   繁体   English

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

[英]Linux C socket UDP server. Nothing being received by select()

I am having issues with my UDP server accepting any input since I put in a select statement. 自从我输入select语句以来,我的UDP服务器接受任何输入时遇到问题。 The intention is to wait on packets from 2 different sockets (with differing ports). 目的是等待来自2个不同套接字(具有不同端口)的数据包。 At the same time I also want it to be able to tell when the server wants to send something to one of the ports being synchronously listened to. 同时,我还希望它能够告诉服务器何时要将某些内容发送到同步监听的端口之一。 In the following code the program runs until it gets to the select() statement, at which point if i attempt to send something to the server (on the local machine) nothing is accepted and the program hangs, waiting. 在下面的代码中,程序运行直至到达select()语句,此时,如果我尝试将某些内容发送到服务器(在本地计算机上),则不接受任何内容,程序挂起,等待。 I have also tried commenting out the writefds fd_set and its accompanying FD_ISSET but the same thing happens. 我也尝试注释掉writefds fd_set及其随附的FD_ISSET但是发生了相同的事情。 I'm burnt out trying to figure this stuff out so there are probably a ton of things that don't make sense, but I tried my best in my current state. 我已经精疲力尽了,想弄清楚这些东西,所以可能有很多事情是没有意义的,但是我在当前状态下尽了最大努力。 I appologize. 我道歉。

#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);
     }
  }

Run your program and press enter at the terminal after it has started. 运行程序,然后在终端启动后按Enter。 It'll probably return from the select. 它可能会从选择中返回。 Why? 为什么? Because the only thing you told select to listen to is fd 0, stdin! 因为您告诉选择要听的唯一东西是fd 0,所以stdin! rv , rrr and rrw are all just return values from getaddrinfo() and you're just ignoring the actual fd's returned by socket() . rvrrrrrw只是从getaddrinfo()返回的值,而您只是忽略了socket()返回的实际fd。 max_fd will also be a junk value since all the tested values are equal with each other. 由于所有测试值彼此相等,因此max_fd也将为垃圾值。 (If it happens to be zero, it won't even react to stdin) (如果碰巧为零,它甚至不会对标准输入做出反应)

Also, next time, please reduce the code to a minimal example . 另外,下次,请将代码简化为最小示例 If your problem is select not returning, then eg. 如果您的问题是选择不返回,则例如。 all the handling code is completely irrelevant, one socket would be enough and using getaddrinfo() is extra. 所有处理代码都是完全无关的,一个套接字就足够了,而使用getaddrinfo()则是多余的。 Also, you would possibly have found the error yourself when removing the getaddrinfo() stuff for the sake of a minimal example. 同样,出于最小的示例,您在删除getaddrinfo()时可能会自己发现错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM