您好我正在为一个网络类工作,我们在网络中创建节点,通过udp从控制应用程序接收消息,然后与其他节点创建tcp连接。基本顺序为:1)控制管理器向节点A发送udp消息,告知它与节点B连接2)节点A接收udp消息并将udp消息转发给节点B 3)节点B接收udp消息,随机选择一个端口number,在该端口上打开一个侦听tcp套接字,并使用端口号将udp消息发送回A)节点A接收udp消息并在该tcp端口上打开到节点B的连接。
基本上,我想循环接收的udp消息并跳转到我的消息解析功能,同时循环tcp连接。这部分看起来很简单,但我真的不明白如何将监听套接字添加到文件描述符列表中。以下代码是我放在一起,我想知道基本结构是否正确?我真的不明白如何创建监听tcp套接字并将其添加到fd列表中?
SOCKET udpsock;
udpsock = initudp(port); //setup udp socket
SOCKET tcpsock;
FD_ZERO(&rdsocks);
max = udpsock + 1;
while(1)
{
SOCKET temp;
FD_SET(udpsock,&rdsocks);//setup udp macros
FD_SET(tcpsock,&rdsocks);
if( select(max,&rdsocks,NULL,NULL,NULL) == SOCKET_ERROR )
{
perror("Select error");
WSACleanup();
return 1;
}
for(temp = 0; temp<=max;temp++) // loop on TCP sockets
{
if(FD_ISSET(temp,&rdsocks))
{
printf("Socket %d is ready \n",temp);
// process tcp messages
}
}
if(FD_ISSET(udpsock,&rdsocks)) // udp connection, parse control message
{
int ret = 0;
res = recvfrom(udpsock, buff,sizeof(buff),0,(struct sockaddr*)&udpclient,lenaddr);
//process udp message, setup tcp connection here if requested and add to file descriptor list?
}
}
答案 0 :(得分:2)
创建侦听TCP套接字(socket(2)
,bind(2)
,listen(2)
)后,使用setsockopt(2)
将其标记为非阻塞,并将其添加到读取集中select(2)
当它变为“可读”时,表示您有待连接的客户端连接,请致电accept(2)
。将新连接的套接字也添加到读取集中。
您可能希望保留列表/哈希/这些客户端套接字中的任何一个,因为在每次调用select(2)
之前必须重新初始化read-set并计算其第一个参数(max fd)。
注0:我在这里引用Linux手册页,但逻辑几乎是跨平台的。您可以在MSDN上找到Windows引用。
注1:Windows select()
IGNORES是其第一个参数。
答案 1 :(得分:1)
在调用FD_ZERO()
和FD_SET()
之前,您需要在每次循环迭代时调用select()
。此外,在尝试首先连接之前,请不要向fd_set
添加TCP套接字。保留您创建的TCP套接字列表,以便在每次循环迭代时将它们重新添加到fd_set
。
尝试这样的事情:
udpsock = initudp(port); //setup udp socket
std::vector<SOCKET> tcpsocks;
SOCKET tcpsock;
while(1)
{
FD_ZERO(&rdsocks);
FD_SET(udpsock, &rdsocks);
max = udpsock;
for(size_t i = 0; i < tcpsocks.size(); ++i)
{
tcpsock = tcpsocks[i];
FD_SET(tcpsock, &rdsocks);
if( tcpsock > udpsock )
max = tcpsock;
}
if( select(max+1, &rdsocks, NULL, NULL, NULL) == SOCKET_ERROR )
{
perror("Select error");
WSACleanup();
return 1;
}
for(size_t i = 0; i < tcpsocks.size(); ++i) // loop on TCP sockets
{
tcpsock = tcpsocks[i];
if( FD_ISSET(tcpsock, &rdsocks) )
{
printf("Socket %d is ready \n", tcpsock);
// process tcp message
}
}
if( FD_ISSET(udpsock, &rdsocks) )
{
int ret = 0;
res = recvfrom(udpsock, buff, sizeof(buff), 0, (struct sockaddr*)&udpclient, lenaddr);
// process udp message...
if( setup tcp connection is requested )
{
tcpsock = ...;
if( tcpsock != INVALID_SOCKET )
tcpsocks.push_back(tcpsock);
}
}
}