select函数的一点体会

liuzu2016 2012-08-01 01:37:14
select函数返回值

The select function returns the total number of socket handles that are ready and contained in the fd_set structures, zero if the time limit expired, or SOCKET_ERROR if an error occurred. If the return value is SOCKET_ERROR, WSAGetLastError can be used to retrieve a specific error code.

这是英文



自己的体会:如有新的连接,和 有数据发送到服务器, select后>=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;
}
}




...全文
114 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
youngwolf 2012-08-02
  • 打赏
  • 举报
回复
有了新连接之后,不是有一句:
FD_SET(sNew, &fdSocket);

然后每次select之前,不是有一句:
fd_set fdRead = fdSocket;

我还是看不出来程序哪里出错了,只是有些小的效率上的问题和不规范,我这面说过了。
你自己也可以试一下,按照你的说法,将永远只select 监听套接字,那其它套接字不会收到数据了,你很容易试出来的。
liulin2019 2012-08-01
  • 打赏
  • 举报
回复

补充一下

FD_ISSET这个宏

套接字集合,只要有数据或者新连接,那么就为true, 进入if语句。

并非有的文章所说的,检测某个套接字,是否在该集合里。
按照文章的说法,非坏不可, 一个新的连接,那么套接字是不在集合里的。

呵呵,永远进不了,if语句。



select的神奇之处,

对于监听套接字,必须FD_SET(集合,监听套接字);

然后,当有新连接后, 调用select函数,此时FD_ISSET,就可以检测有新连接了。

本人菜鸟, 欢迎高手指点,谢谢






[Quote=引用 3 楼 yang79tao 的回复:]
当然,你得调试一下,看看对于在fdRead过程中,如果socket不可读,那么系统是把它从fd_array里面去掉呢,还是给它赋一个-1,我估计是置-1,去掉的话,会有内存拷贝。

如果是置-1,就要修改一下上面的代码:

C/C++ code


for(int i=0; i<(int)fdRead.fd_count; i++)
{
if (-1 == fdRead.f……
[/Quote]
youngwolf 2012-08-01
  • 打赏
  • 举报
回复
当然,你得调试一下,看看对于在fdRead过程中,如果socket不可读,那么系统是把它从fd_array里面去掉呢,还是给它赋一个-1,我估计是置-1,去掉的话,会有内存拷贝。

如果是置-1,就要修改一下上面的代码:

for(int i=0; i<(int)fdRead.fd_count; i++)
{
if (-1 == fdRead.fd_array[i])
continue;

if(fdRead.fd_array[i] == sListen)
...
else
::recv(fdRead.fd_array[i], ...);
}


另外,在遍历过程中,还可以进一步优化,就是利用select的返回值,它返回的是套接字数量,可以在for循环中,根据已经处理了的套接字数量与这个值比较,可以早点退出循环(除非数组最后一个套接字有效,那还是得遍历完)
youngwolf 2012-08-01
  • 打赏
  • 举报
回复
FD_ISSET那一行怎么写,都是一样的,你不觉得它是在求fdRead 与 fdSocket的交集吗?
求交集就与顺序无关了。

直接操作fd_set里面的成员这种小聪明,最好还是不要做,fdSocket.fd_count这个在linux下根本无法编译,因为没有这个成员。

要操作fd_set成员,那一定要有某种目的,比如去掉对FD_ISSET的调用(这个调用每次从次遍历,效率低),此时这样就可以了:

for(int i=0; i<(int)fdRead.fd_count; i++)
{
if(fdRead.fd_array[i] == sListen)
...
else
::recv(fdRead.fd_array[i], ...);
}
翅膀又硬了 2012-08-01
  • 打赏
  • 举报
回复
bbs里写博客?

16,465

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

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