select模型的几个小问题 ?

liuzu2016 2012-07-29 04:27:30

问题在代码注释中

2个线程函数,第一个是accept套接字

第二个是接受数据线程

unsigend int _stdcall AcceptThread(void*)
{

while(1)
{

select(0,只读套接字集合,NULL,NULL,NULL); //最后一个参数为NULL,表示阻塞
SOCKET newSocket;
socketaddr_in newAddrin; //新地址
int nAddLen=sizeof(newSocket);

newSocket=accept(sListen,(sockaddr*)&newAddrin,&nAddLen);


//添加到只读集合中
FD_SET(newAddrin,&newSocket);

}

return 0;

}




//接受线程
unsigned int _stdcall ReveiveThread(void*)
{

while(1)
{
//raii锁
select(NULL,&只读集合,NULL,NULL,NULL); //最后一一个参数不用NULL,改成timeval 结构体,设置时间

for(int i=0; i<只读集合体的个数;i++) //问题1:select后,集合的结构体成员个数是否是 在线的客户端的个数??
{
//由于调用selcet的时候,参数设置为只读套接字,所以只能接受数据


char buf[2000];
::ZeroMemory(buf,sizeof(buf);

int nRet=revc(套接字集合[ i],buf,sizeof(buf));

问题2:select后,说明剩下的套接字只有连接套接字和发送数据的客户端,其他套接字类型是没有的

在这里如何区别是哪一种套接字?

为什么有这个疑问,我想在这里接受数据,然后对数据解包,同时把 接受的套接字 和 数据包的某些内容组成一个

对象,放到map中管理.




}

}

return 0;

}




...全文
185 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
liuzu2016 2012-07-31
  • 打赏
  • 举报
回复
多谢,总结一下:

有新的连接,和 有数据发送到服务器

select后>=1,



附一段网上的代码,

这代码很多博客,文章都转载过,

我是菜鸟,觉得有些不对,高手莫笑,望指点





1.fdSocket是没select前的集合,代码没对fdSocket select,所所以其的套接字数目不变。

fdRead 则可能减少,也可能增多(比如:有新的连接)


所以for循环的执行次数,就不该用fdSocket ,而改用fdRead .


if(FD_ISSET(fdSocket.fd_array[i], &fdRead)) 这一句改成: if(FD_ISSET(fdRead.fd_array[i], &fdSocket))

if(fdSocket.fd_array[i] == sListen) // (1)监听套节字接收到新连接

这一句改成:

if(fdRead.fd_array[i] == sListen) // (1)监听套节字接收到新连接(fdRead是处理过剩下有连接或者有数据的套接字)



while(TRUE)
{
// 2)将fdSocket集合的一个拷贝fdRead传递给select函数,
// 当有事件发生时,select函数移除fdRead集合中没有未决I/O操作的套节字句柄,然后返回。
fd_set fdRead = fdSocket;
int nRet = ::select(0, &fdRead, NULL, NULL, NULL);
if(nRet > 0)
{
// 3)通过将原来fdSocket集合与select处理过的fdRead集合比较,
// 确定都有哪些套节字有未决I/O,并进一步处理这些I/O。
for(int i=0; i<(int)fdSocket.fd_count; i++)
{
if(FD_ISSET(fdSocket.fd_array[i], &fdRead))
{
if(fdSocket.fd_array[i] == sListen) // (1)监听套节字接收到新连接
{
if(fdSocket.fd_count < FD_SETSIZE)
{
sockaddr_in addrRemote;
int nAddrLen = sizeof(addrRemote);
SOCKET sNew = ::accept(sListen, (SOCKADDR*)&addrRemote, &nAddrLen);

FD_SET(sNew, &fdSocket);
printf("接收到连接(%s)\n", ::inet_ntoa(addrRemote.sin_addr));
}
else
{
printf(" Too much connections! \n");
continue;
}
}
else
{
char szText[256];
int nRecv = ::recv(fdSocket.fd_array[i], szText, strlen(szText), 0);
if(nRecv > 0) // (2)可读
{
szText[nRecv] = '\0';
printf("接收到数据:%s \n", szText);
}
else // (3)连接关闭、重启或者中断
{
::closesocket(fdSocket.fd_array[i]);

printf("关闭\n");
FD_CLR(fdSocket.fd_array[i], &fdSocket);
}
}
}
}
}
else
{
printf(" Failed select() \n");
break;
}
}





while(TRUE)
{
// 2)将fdSocket集合的一个拷贝fdRead传递给select函数,
// 当有事件发生时,select函数移除fdRead集合中没有未决I/O操作的套节字句柄,然后返回。
fd_set fdRead = fdSocket;
int nRet = ::select(0, &fdRead, NULL, NULL, NULL);
if(nRet > 0)
{
// 3)通过将原来fdSocket集合与select处理过的fdRead集合比较,
// 确定都有哪些套节字有未决I/O,并进一步处理这些I/O。
for(int i=0; i<(int)fdSocket.fd_count; i++)
{
if(FD_ISSET(fdSocket.fd_array[i], &fdRead))
{
if(fdSocket.fd_array[i] == sListen) // (1)监听套节字接收到新连接
{
if(fdSocket.fd_count < FD_SETSIZE)
{
sockaddr_in addrRemote;
int nAddrLen = sizeof(addrRemote);
SOCKET sNew = ::accept(sListen, (SOCKADDR*)&addrRemote, &nAddrLen);

FD_SET(sNew, &fdSocket);
printf("接收到连接(%s)\n", ::inet_ntoa(addrRemote.sin_addr));
}
else
{
printf(" Too much connections! \n");
continue;
}
}
else
{
char szText[256];
int nRecv = ::recv(fdSocket.fd_array[i], szText, strlen(szText), 0);
if(nRecv > 0) // (2)可读
{
szText[nRecv] = '\0';
printf("接收到数据:%s \n", szText);
}
else // (3)连接关闭、重启或者中断
{
::closesocket(fdSocket.fd_array[i]);

printf("关闭\n");
FD_CLR(fdSocket.fd_array[i], &fdSocket);
}
}
}
}
}
else
{
printf(" Failed select() \n");
break;
}
}






[Quote=引用 9 楼 的回复:]
不是掉线 是select的时候有数据过来了,被去掉的只不过没数据而已。
[/Quote]
hotpos 2012-07-31
  • 打赏
  • 举报
回复
不是掉线 是select的时候有数据过来了,被去掉的只不过没数据而已。
liuzu2016 2012-07-31
  • 打赏
  • 举报
回复

真的假的啊,

我以为它的作用是去掉断线的socket
照这样的话


加入服务器连接10个客户端,他们都没掉线

就一个客户端和服务器通信,其他一依然连接,

那9个客户端会被select去掉吗?



[Quote=引用 7 楼 的回复:]
selcet 是把有数据的socket留在set中,没有的从set中删掉。

select(.., &只读集合, ...)
for ()
{
if (FD_ISSET(socket, &只读集合))
{
//有数据
}
else
{
//没有数据
}
}
[/Quote]
hotpos 2012-07-31
  • 打赏
  • 举报
回复
selcet 是把有数据的socket留在set中,没有的从set中删掉。

select(.., &只读集合, ...)
for ()
{
if (FD_ISSET(socket, &只读集合))
{
//有数据
}
else
{
//没有数据
}
}
liuzu2016 2012-07-31
  • 打赏
  • 举报
回复



[Quote=引用 5 楼 的回复:]
这样做ok了吧

朋友

//接受线程
unsigned int _stdcall ReveiveThread(void*)
{

while(1)
{
//raii锁
select(NULL,&只读集合,NULL,NULL,时间); //剩下的套接字是在线的,和监听套接字


for(int i=0; i<只读集合体的个数;i++) //
{


……
[/Quote]
liuzu2016 2012-07-29
  • 打赏
  • 举报
回复
这样做ok了吧

朋友

//接受线程
unsigned int _stdcall ReveiveThread(void*)
{

while(1)
{
//raii锁
select(NULL,&只读集合,NULL,NULL,时间); //剩下的套接字是在线的,和监听套接字


for(int i=0; i<只读集合体的个数;i++) //
{


if(套接字==监听套接字)
continue;


char buf[2000];
::ZeroMemory(buf,sizeof(buf);


//只能通过轮训的方式,去查找哪一个套接字接受了数据
int nRet=revc(套接字集合[ i],buf,sizeof(buf)); //已经变成了非堵塞

if(nRet!=0) //说明该套接字收到了客户端的数据
{

//解包
并且去map中查找该套接字,查找后,更新map中的该套接字的最新会话时间

}


} //end for

} //end while

}





[Quote=引用 4 楼 的回复:]

刚收到你的私信,我看了你的代码。

首先,你不太了解select模型呀。建议多看看模型原理
不懂原理直接干活会头疼的

select都不做返回直判断,你怎么判断套接字到底可不可用。

问题点太多,很多知识需要补。
http://blog.csdn.net/yanheifeng715000/article/details/6592447
[/Quote]
傻X 2012-07-29
  • 打赏
  • 举报
回复
刚收到你的私信,我看了你的代码。

首先,你不太了解select模型呀。建议多看看模型原理
不懂原理直接干活会头疼的

select都不做返回直判断,你怎么判断套接字到底可不可用。

问题点太多,很多知识需要补。
http://blog.csdn.net/yanheifeng715000/article/details/6592447
liuzu2016 2012-07-29
  • 打赏
  • 举报
回复
不管如何,多谢你了啊 ,呵呵,
  • 打赏
  • 举报
回复
对网络编程不是很在行
就从我对代码的理解角度分析下吧
问题1:
如果你的只读套接字set只被AcceptThread线程中的FD_SET(newAddrin,&newSocket)访问
且你的在线客户端都是通过这个FD_SET来添加的话,那集合的结构体成员个数是在线的客户端的个数
问题2:
这个得等专家来解释了,不敢乱讲
liuzu2016 2012-07-29
  • 打赏
  • 举报
回复
555


沉了 顶起来

18,355

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧