组播通信中select()函数的问题

时间:2015-03-25 23:02:07

标签: c sockets

如果可能的话,我会尽可能详细地阐述我想要帮助的问题:

我正在编写一个与两个套接字通信的程序,我在多播套接字上监听,而我则委托给另一个套接字"单播"来自第一个套接字" Multicast"的通信数据产生的重要信息。

我认为有两个问题是相关的:

1-我在一个计算机中运行该程序" Linux"与另一个" Linux"进行通信,程序按预期执行。但是,当我把它带到另一台计算机并运行我的程序和其他程序时,所有这些都在一个主机中#34;使用类似的多播配置,我收到以下错误:

选择:中断的系统调用

这是一条perror消息,但我不确定是由于select()或我的多播配置中的错误。

2-由于第一个问题,我无法委托"单播"客户端套接字,但单播是有效的,因为在"单播客户端"之间存在一些定期检查。我的程序一直在运行。

我的代码如下:

struct ConfigStruct
{
 struct sockaddr_in  Hinfo1, Hinfo2; 
 struct sockaddr_in  Rinfo; 
 int sock1, sock2;
};

int main()
{
ConfigStruct StructArg;
int fd1, fd2;
int POS(1);  
/****************** Network parameters declaration *************************/
// Declaration for socket addresses      
struct sockaddr_in  Host_info1, Host_info2; 
struct sockaddr_in  Remote_info;

struct in_addr localInterface;
struct ip_mreq Group;

memset((char *)&Host_info1,0,sizeof(Host_info1));
memset((char *)&Host_info2,0,sizeof(Host_info2));
memset((char *)&Remote_info,0,sizeof(Remote_info));
memset((char *)&Group,0,sizeof(Group));


//**** Reads configuration file****************
cout<<"Reading configuration file..........."<<endl;
std::string input1 ="192.***.**.**"; 
std::string input2 = "8888"; 
std::string input3 ="192.***.**.**"; 
std::string input4 = "8889"; 

const char* addr_input = input1.data();
const char* port_input = input2.data();
const char* addr_input2 = input3.data();
const char* port_input2 = input4.data();

Remote_info.sin_addr.s_addr=inet_addr(addr_input);
Remote_info.sin_port = htons((uint16_t)stoi(port_input,nullptr,0));
Remote_info.sin_family=AF_INET;  
Host_info1.sin_addr.s_addr=inet_addr(addr_input2);//htonl(INADDR_ANY);
Host_info1.sin_port  = htons((uint16_t)stoi(port_input2,nullptr,0));
Host_info1.sin_family=AF_INET;


//***** First socket *******
fd1= socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
if (fd1 == -1)
    {
      std::cout<<"A problem occured"<<endl;
      cease("socket", wd) ;
    }
if (setsockopt(fd1,SOL_SOCKET,SO_REUSEADDR, &POS, sizeof(POS)) == -1) 
   {
   perror(" Error in setsockopt");
    exit(1);
   }

// **** I'M NOT SURE IF THIS NECESSARY **************
int opts;
opts = fcntl(fd1,F_GETFL);
if (opts < 0) 
{
    perror("fcntl(F_GETFL)");
    exit(EXIT_FAILURE);
}
opts = (opts | O_NONBLOCK);
if (fcntl(fd1,F_SETFL,opts) < 0) 
{
    perror("fcntl(F_SETFL)");
    exit(EXIT_FAILURE);
}
//*****************************************************

if (bind(fd1,(struct sockaddr *)&Host_info1,sizeof(Host_info1)) < 0)
    {
      cease("Bind",wd);
    }
  else
    {
      cout<<" Socket ID number "<<fd1<<endl;
      cout<<" Bound socket..."<<endl;
    } 


//********** The multicast network setup ***********************
std::string input5 ="230.*.**.**"; 
std::string input6 = "192.***.***";   // The same host IP address as above
std::string input7 = "1500" ;  // The port number to listen to for Multicast message 

const char* Group_Multi_Addr = input5.data();
const char* Group_Interface_Addr = input6.data();
const char* Host_port_input = input7.data();

Group.imr_multiaddr.s_addr = inet_addr(Group_Multi_Addr);
Group.imr_interface.s_addr = inet_addr(Group_Interface_Addr);
Host_info2.sin_family = AF_INET;
Host_info2.sin_addr.s_addr = INADDR_ANY;
Host_info2.sin_port = htons((uint16_t)stoi(Host_port_input,nullptr,0));

//***** The second socket *******

fd2 = socket(AF_INET, SOCK_DGRAM, 0);
if(fd2 < 0)
 {
  perror("Opening datagram socket error");
  exit(1);
 }
 else
    printf("Opening the datagram socket...OK.\n");

int reuse = 1;
if(setsockopt(fd2, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0)
 {
 close(fd2);
  cease("Setting SO_REUSEADDR error", wd);
 }
else
  printf("Setting SO_REUSEADDR...OK.\n");

if(bind(fd2, (struct sockaddr*)&Host_info2, sizeof(Host_info2)))
 {
 close(fd2);
 cease("Binding datagram socket error",wd);
 }
else
 printf("Binding datagram socket...OK.\n");

if(setsockopt(fd2, IPPROTO_IP, IP_ADD_MEMBERSHIP,(char *)&Group,sizeof(Group)) < 0)
 {
 perror("Adding multicast group error");
 close(fd2);
 exit(1);
 }
 else
 printf("Adding multicast group...OK.\n");

StructArg.Hinfo1= Host_info1;
StructArg.Hinfo2= Host_info2 ;
StructArg.Rinfo= Remote_info ;

StructArg.sock1=fd1;
StructArg.sock2=fd2;

fd_set readfds ,rd_fds;
struct timeval tv;
// clear the set ahead of time
FD_ZERO(&readfds);
// add our descriptors to the set
FD_SET(StructArg.sock1, &readfds);
FD_SET(StructArg.sock2, &readfds);

nls = StructArg.sock2 + 1;
tv.tv_sec = 0;
tv.tv_usec = 50;

char Recv_buffer[125];
char TX_buffer[125];

memset((char *)&Recv_buffer,'0',sizeof(Recv_buffer));
memset((char *)&TX_buffer,'0',sizeof(TX_buffer));

int lenremote(sizeof(StructArg.Rinfo));
ssize_t rs, rs2;
uint8_t MsgSize; 
uint8_t MsgID;


do
{
rd_fds=readfds;
if (select(nls, &rd_fds, NULL, NULL, &tv) < 0) 
{
    perror("select"); // error occurred in select()
} 
else 
{
// one or both of the descriptors have data
if (FD_ISSET(StructArg.sock1, &rd_fds)) 
 {
   rs =  recvfrom(StructArg.sock1,....,...,0,...,...)  ;
   if ( rs > 0 )
    {
     Do bunch of routines
    }
}

 if (FD_ISSET(StructArg.sock2, &rd_fds)) 
{
 rs2 = recv(StructArg.sock2,&Recv_buffer,sizeof(Recv_buffer),0);
    if ( rs2 > 0 )
    {
    send some data to  StructArg.sock1
    }
}
// I do some work here , i send somethings to Sock 1  (Is this appropriate ??)
}
while(1);
return 0;
}

所以最重要的是,为什么我在一台计算机上获得Select : System interrupt call而在另一台计算机上却没有?

2 个答案:

答案 0 :(得分:0)

  

我不确定是由于Select()或我的多播配置中的错误。

都不是。这是由于在系统调用期间捕获到信号。只需绕过这种情况,例如:

do
{
    // ...

    rc = select(nls, &rd_fds, NULL, NULL, &tv);
} while (rc == -1 && errno == EINTR);
if (rc == -1)
{
    perror("select");
}
else
{
    // ...
}
  

最重要的是,为什么我会选择:系统中断呼叫在一台计算机而不是另一台计算机

因为你在一台计算机上而不是另一台计算机上发出了信号。这并不重要。

答案 1 :(得分:0)

  

超时怎么样,因为man页面说超时   当出现错误时变得不确定,我应该把tv.sec和   循环中的tv.usec。

man 2 select

  

在Linux上, select()修改超时以反映不是时间   睡觉;大多数其他实现不会这样做。 (POSIX.1-2001   允许任何一种行为。)

在Linux上,问题中显示的代码可能不会按预期运行,因为超时仅在循环之前设置一次,如果到期则归零 - 从那时起,它保持为零。在这里,在主循环内设置所需的超时是合适的,但在建议的循环… while (rc == -1 && errno == EINTR)之外。

在没有相应更新超时的系统上,存在中断时没有这么简单的方法来维持正确的超时。