使用select()的UDP套接字在第一次迭代和数据不等后停止接收

时间:2014-11-23 15:10:25

标签: sockets select networking udp server

我的目标是接收客户端(server_address_ob)每10毫秒连续发送的数据报,并使用UDP套接字将此接收的数据报发送到另一台服务器(server_address_hm)。这应该是连续完成的,因为我的程序应该像server_Address_ob和server_address_hm之间的中间人一样。我在C中编写了这段代码(下面),其中一些使用select()

来自互联网

代码问题:

1)收到的数据和发送的数据不相同

bsnayak@ubuntu:~/Desktop/learn$ ./ar4

Main server waiting for client to respond...

(192.168.37.1 , 1901) rcvd: 0x1ae50990

(0.0.0.0 , 0) sent: 0x1ae69030

2)为什么地址为0.0.0.0,0,尽管这里使用以下定义创建套接字

 server_address_hmi.sin_port = htons(1902);
 server_address_hmi.sin_addr.s_addr = inet_addr("192.168.37.134");

3)虽然程序运行但是在接收和发送一次之后,程序不再接收任何数据包或发送它们。

    //Main SERVER
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <sys/select.h>//use select() for multiplexing
#include <sys/fcntl.h> // for non-blocking

#define MAX_LENGTH 100000
#define PORT 1901

/* Select() params
 * int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
 * FD_SET(int fd, fd_set *set);
 * FD_CLR(int fd, fd_set *set);
 * FD_ISSET(int fd, fd_set *set);
 * FD_ZERO(fd_set *set);
*/

void error(char *message)
{
    perror(message);
    exit(1);
}

int main()
{

  // select parameters declared
  fd_set original_socket;
  fd_set original_stdin;
  fd_set readfds;
  fd_set writefds;
  struct timeval tv;
  int numfd, numfd2;

  // socket parameters declared
  int socket_fd_ob, socket_fd_hm;
  int bytes_read, bytes_sent;
  char address_length, address_length2;
  char recieve_data[MAX_LENGTH];
  char send_data[MAX_LENGTH];
  struct sockaddr_in server_address_ob, server_address_hm, client_address;
  int z = 0;

  //Socket creation done separately for both OB and HM communications
  if ((socket_fd_ob = socket(AF_INET, SOCK_DGRAM, 0)) == -1) 
  {
      error("socket()");
  }
  if ((socket_fd_hm = socket(AF_INET, SOCK_DGRAM, 0)) == -1) 
  {
      error("socket()");
  }


  fcntl(socket_fd_ob, F_SETFL, O_NONBLOCK); //set socket to non-blocking
  fcntl(socket_fd_hm, F_SETFL, O_NONBLOCK); //set socket to non-blocking

  // clear the set ahead of time
  FD_ZERO(&original_socket);
  FD_ZERO(&original_stdin);
  FD_ZERO(&readfds);
  FD_ZERO(&writefds);

  // add our descriptors to the set (0 - stands for STDIN)
  FD_SET(socket_fd_ob, &original_socket);//instead of 0 put socket_fd_ob
  FD_SET(socket_fd_ob, &readfds);
  FD_SET(0,&original_stdin);
  FD_SET(0, &writefds);

  // since we got s2 second, it's the "greater", so we use that for
  // the n param in select()
  numfd  = socket_fd_ob + 1;
  numfd2 = socket_fd_hm + 1;


  // wait until either socket has data ready to be recv()d (timeout 10.5 secs)
  tv.tv_sec = 1;
  tv.tv_usec = 500000;

  server_address_ob.sin_family = AF_INET;
  server_address_ob.sin_port = htons(1901);
  server_address_ob.sin_addr.s_addr = inet_addr("192.168.37.1");
  bzero(&(server_address_ob.sin_zero),sizeof(server_address_ob));

  server_address_hm.sin_family = AF_INET;
  server_address_hm.sin_port = htons(1902);
  server_address_hm.sin_addr.s_addr = inet_addr("192.168.37.134");
  bzero(&(server_address_ob.sin_zero),sizeof(server_address_hm));

  // Bind socket to the particular addresses

  if (bind(socket_fd_ob,(struct sockaddr *)&server_address_ob, sizeof(struct sockaddr)) == -1)
  {
      error("bind()");
  }

  if (bind(socket_fd_hm,(struct sockaddr *)&server_address_hm, sizeof(struct sockaddr)) == -1)
  {
      error("bind()");
  }

  address_length  = sizeof(struct sockaddr);
  address_length2 = sizeof(struct sockaddr);

  printf("\nMain server waiting for client to respond...\n");
  fflush(stdout);

  while (1)
  {
    readfds = original_socket;
    writefds = original_stdin;//problem
    int recieve = select(numfd, &readfds, &writefds,/*NULL,*/ NULL, &tv);
    int sent    = select(numfd2, &readfds, &writefds,/*NULL,*/ NULL, &tv);

    if (recieve == -1 || sent == -1) 
    {
      perror("select"); // error occurred in select()
    } 
    else if (recieve == 0 || sent == 0) 
    {
      printf("Timeout occurred!  No data after 1.5 seconds.\n");
    } 
    else 
    {
        // one or both of the descriptors have data
        if (FD_ISSET(socket_fd_ob, &readfds)) //if set to read
        { 
          FD_CLR(socket_fd_ob, &readfds);
          bytes_read = recvfrom(socket_fd_ob,recieve_data,MAX_LENGTH,0,(struct sockaddr *)&client_address, &address_length); 

     for (z = 0; z < bytes_read; ++z) {
     FD_ISSET(socket_fd_hm, &writefds);
          FD_CLR(socket_fd_hm, &writefds);
          //recvfrom speech recognition client and decide what to send to HM accordingly..
          send_data[bytes_read] = recieve_data[bytes_read];
          //block call, will wait till client enters something, before proceeding
          //send the corresponding to HM
          bytes_sent = sendto(socket_fd_hm,send_data,strlen(send_data)+1,0,(struct sockaddr *)&server_address_hm, &address_length2); 
          fflush(stdout);
          }                  
          recieve_data[bytes_read] = '\0'; //add null to the end of the buffer
          send_data[bytes_read] = '\0'; //add null to the end of the buffer

          printf("\n(%s , %d) rcvd: %02x\n",inet_ntoa(client_address.sin_addr),ntohs(client_address.sin_port),recieve_data);
          printf("\n(%s , %d) sent: %02x\n",inet_ntoa(server_address_hm.sin_addr),ntohs(server_address_hm.sin_port),send_data);
        }




    } //end else
  }//end while

  close (socket_fd_ob);
  return 0;
}

希望能够解决我的问题。感谢您提前帮助。

1 个答案:

答案 0 :(得分:0)

您没有正确测试select()中的错误。您可以在其中一个中收到错误。测试应该是recieve == -1 || sent == -1,但我无法想象你为什么要两次调用select(),或者甚至为什么要使用两个套接字。您只需需要一个选择。试试这种方式,你可能会搞出其他一些错误。

注意:由于您创建套接字的顺序,您不能依赖第二个套接字描述符大于第一个套接字描述符。您必须测试或使用max()