int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout);

参数列表:

int maxfdp,是指集合中所有文件描述符的范围,即所有文件描述符的最大值加1,在Windows中这个参数的值无所谓。   

fd_set *readfds是指向fd_set结构的指针,这个集合中应该包括文件描述符,我们是要监视这些文件描述符的读变化的,即我们关心是否可以从这些文件中读取数据了,如果这个集合中有一个文件可读,select就会返回一个大于0的值,表示有文件可读,如果没有可读的文件,则根据timeout参数再判断是否超时,若超出timeout的时间,select返回0,若发生错误返回负值。可以传入NULL值,表示不关心任何文件的读变化。   

fd_set *writefds是指向fd_set结构的指针,这个集合中应该包括文件描述符,我们是要监视这些文件描述符的写变化的,即我们关心是否可以向这些文件中写入数据了,如果这个集合中有一个文件可写,select就会返回一个大于0的值,表示有文件可写,如果没有可写的文件,则根据timeout参数再判断是否超时,若超出timeout的时间,select返回0,若发生错误返回负值。可以传入NULL值,表示不关心任何文件的写变化。   

fd_set *errorfds同上面两个参数的意图,用来监视文件错误异常。

struct timeval* timeout是select的超时时间,这个参数至关重要,它可以使select处于三种状态:

第一,若将NULL以形参传入,即不传入时间结构,就是将select置于阻塞状态,一定等到监视文件描述符集合中某个文件描述符发生变化为止;

第二,若将时间值设为0秒0毫秒,就变成一个纯粹的非阻塞函数,不管文件描述符是否有变化,都立刻返回继续执行,文件无变化返回0,有变化返回一个正值;

第三,timeout的值大于0,这就是等待的超时时间,即 select在timeout时间内阻塞,超时时间之内有事件到来就返回了,否则在超时后不管怎样一定返回,返回值同上述。

返回值:

负值:select错误

正值:某些文件可读写或出错

0:等待超时,没有可读写或错误的文件

readfds:

If listen has been called and a connection is pending, accept will succeed.

Data is available for reading (includes OOB data if SO_OOBINLINE is enabled).

Connection has been closed/reset/terminated.

writefds:

If processing a connect call (nonblocking), connection has succeeded.

Data can be sent.

exceptfds:

If processing a connect call (nonblocking), connection attempt failed.

OOB data is available for reading (only if SO_OOBINLINE is disabled).

FD_CLR(s, *set):从set中删除套接字s。

FD_ISSET(s, *set):检查s是否set集合的一名成员;如答案是肯定的是,则返回TRUE。

FD_SET(s, *set):将套接字s加入集合set。

FD_ZERO( * set):将set初始化成空集合。

在大规模的网络连接方面,还是推荐使用IOCP或EPOLL模型.但是Select模型可以使用在诸如对战类游戏上,比如类似星际这种,因为它小巧易于实现,且对战类游戏的网络连接量并不大. 对于Select模型想要突破Windows 64个限制的话,可以采取分段轮询,一次轮询64个.例如套接字列表为128个,在第一次轮询时,将前64个放入队列中用Select进行状态查询, 待本次操作全部结束后.将后64个再加入轮询队列中进行轮询处理.这样处理需要在非阻塞式下工作.以此类推,Select也能支持无限多个。

简单例子:


#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <WinSock2.h>
#include <iostream>
#include<Windows.h>
#pragma comment(lib, "ws2_32.lib") using namespace std; SOCKET server, clientSet[FD_SETSIZE];
int serverAddLen;//服务器地址长度
sockaddr_in serverAdd;//服务器地址
int clientCount = 0;//记录接入客户端的数量 DWORD WINAPI WorkerThread(LPVOID lpParam); int main()
{ WSADATA wsaData;
SOCKET client;
sockaddr_in clientAdd;
int clientAddLen = sizeof(clientAdd);
DWORD dwThreadId; DWORD ret = MAKEWORD(2, 2);
if (ret == WSAStartup(0x0202, &wsaData))
{
cerr << "初始化失败!" << endl;
} serverAdd.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
serverAdd.sin_family = AF_INET;
serverAdd.sin_port = htons(5000);
serverAddLen = sizeof(serverAdd);
server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); bind(server, (struct sockaddr*)&serverAdd, serverAddLen);
listen(server, SOMAXCONN);
CreateThread(NULL, 0, WorkerThread, NULL, 0, &dwThreadId); while (clientCount < FD_SETSIZE)
{
client = accept(server, (struct sockaddr *)&clientAdd, &clientAddLen);
cout << "Accepted client:" << inet_ntoa(clientAdd.sin_addr) << ":" << ntohs(clientAdd.sin_port);
clientSet[clientCount++] = client;
} WSACleanup();
system("pause");
return 1; } DWORD WINAPI WorkerThread(LPVOID lpParam)
{
fd_set fdread;
int ret;
char szMesage[8192]; while (1)
{
int i;
FD_ZERO(&fdread);
for (i = 0; i < clientCount; ++i)
{
if (clientSet[i] != NULL)
FD_SET(clientSet[i], &fdread);
}
timeval timeout = { 3,0 };
ret = select(i + 1, &fdread, NULL, NULL, &timeout);
if (ret == 0) //超时
{
continue;
}
for (i = 0; i < clientCount; ++i)
{
if (FD_ISSET(clientSet[i], &fdread))
{
ret = recv(clientSet[i], szMesage, sizeof(szMesage), 0);
if (ret == 0 || ret == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET)
{
cerr << "client socket closed" << endl;
FD_CLR(clientSet[i], &fdread);
closesocket(clientSet[i]);
clientSet[i] = NULL;
}
else
{
szMesage[ret] = '\0';
cout << szMesage << endl;
}
}
}
}
return 0;
}

改进:


#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <WinSock2.h>
#include <iostream>
#include<Windows.h>
#pragma comment(lib, "ws2_32.lib") using namespace std; SOCKET server, clientSet[FD_SETSIZE];
int serverAddLen;//服务器地址长度
sockaddr_in serverAdd;//服务器地址
int clientCount = 0;//记录接入客户端的数量 void WorkerThread(); int main()
{ WSADATA wsaData;
DWORD dwThreadId; DWORD ret = MAKEWORD(2, 2);
if (ret == WSAStartup(0x0202, &wsaData))
{
cerr << "初始化失败!" << endl;
} serverAdd.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
serverAdd.sin_family = AF_INET;
serverAdd.sin_port = htons(5000);
serverAddLen = sizeof(serverAdd);
server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); bind(server, (struct sockaddr*)&serverAdd, serverAddLen);
listen(server, SOMAXCONN);
WorkerThread(); /*while (clientCount < FD_SETSIZE)
{
client = accept(server, (struct sockaddr *)&clientAdd, &clientAddLen);
cout << "Accepted client:" << inet_ntoa(clientAdd.sin_addr) << ":" << ntohs(clientAdd.sin_port)<<endl;
clientSet[clientCount++] = client;
}*/ WSACleanup();
system("pause");
return 1; } void WorkerThread()
{
fd_set fdread;
int ret;
char szMesage[8192]; SOCKET client;
sockaddr_in clientAdd;
int clientAddLen = sizeof(clientAdd); while (1)
{
int i;
FD_ZERO(&fdread);
FD_SET(server, &fdread);
for (i = 0; i < clientCount; ++i)
{
if (clientSet[i] != NULL)
FD_SET(clientSet[i], &fdread);
}
timeval timeout = { 3,0 };
ret = select(i + 1, &fdread, NULL, NULL, &timeout);
if (ret == 0) //超时
{
continue;
}
else if(ret== SOCKET_ERROR&&GetLastError()!= WSAEINVAL)//WSAEINVAL参数全为空错误
{
cerr << "select error!" <<GetLastError()<< endl;
break;
} if (FD_ISSET(server, &fdread))
{
if (clientCount < FD_SETSIZE)
{
cout << "有新的连接请求!" << endl;
client = accept(server, (sockaddr*)&clientAdd, &clientAddLen);
if (client == INVALID_SOCKET)
{
cerr << "无法接受请求" << endl;
}
else
{
cout << "Accepted client:" << inet_ntoa(clientAdd.sin_addr) << ":" << ntohs(clientAdd.sin_port) << endl;
clientSet[clientCount++] = client;
}
}
else
{
cerr << "达到上限无法接受请求!" << endl;
} } for (i = 0; i < clientCount; ++i)
{
if (FD_ISSET(clientSet[i], &fdread))
{
ret = recv(clientSet[i], szMesage, sizeof(szMesage), 0);
if (ret == 0 || ret == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET)
{
cerr << "client socket closed" << endl;
FD_CLR(clientSet[i], &fdread);
closesocket(clientSet[i]);
clientSet[i] = NULL;
}
else
{
szMesage[ret] = '\0';
cout << szMesage << endl;
}
}
}
} }

socket编程之select()的更多相关文章

  1. socket编程之 select、poll、kqueue、epoll

    原生API select int select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct tim ...

  2. 详述socket编程之select()和poll()函数

    转自:http://www.cppblog.com/myjfm/archive/2011/10/26/159093.aspx select()函数和poll()函数均是主要用来处理多路I/O复用的情况 ...

  3. socket编程之select相关

    FD_ZERO,FD_ISSET这些都是套节字结合操作宏 看看MSDN上的select函数, 这是在select   io   模型中的核心,用来管理套节字IO的,避免出现无辜锁定. int   se ...

  4. socket编程之select(),poll(),epoll()

    socket编程,通信 client端  socket() ----->connect() ------->recv() -----> close(); server端 socket ...

  5. PHP Socket 编程之9个主要函数的使用之测试案例

    php的socket编程算是比较难以理解的东西吧,不过,我们只要理解socket几个函数之间的关系,以及它们所扮演的角色,那么理解起来应该不是很难了,在笔者看来,socket编程,其实就是建立一个网络 ...

  6. [深入浅出WP8.1(Runtime)]Socket编程之UDP协议

    13.3 Socket编程之UDP协议 UDP协议和TCP协议都是Socket编程的协议,但是与TCP协议不同,UDP协议并不提供超时重传,出错重传等功能,也就是说其是不可靠的协议.UDP适用于一次只 ...

  7. iPhone socket 编程之BSD Socket篇

    iPhone socket 编程之BSD Socket篇 收藏在进行iPhone网络通讯程序的开发中,不可避免的要利用Socket套接字.iPhone提供了Socket网络编程的接口CFSocket, ...

  8. 老雷socket编程之websocket实现

    老雷socket编程之websocket实现 我们主要实现私聊和群聊两个功能,要在web端实现想微信QQ那样的即时通讯的功能,我们需要了解一下websocket.websocket是一种可以双向通讯的 ...

  9. 老雷socket编程之PHP利用socket扩展实现聊天服务

    老雷socket编程之PHP利用socket扩展实现聊天服务 socket聊天服务原理 PHP有两个socket的扩展 sockets和streamssockets socket_create(AF_ ...

随机推荐

  1. LINUX中的DNS服务---DNS集群

    一.DNS集群的理解 在使用DNS的时候,为了缓解服务器的压力,会使用多个辅助DNS服务器来分担主DNS的工作.这些DNS就叫做DNS集群. 二.配置过程 1)在辅DNS中操作如下:(主机号为172. ...

  2. iOS系统知识架构(转)

    转载的,哪些所谓的资深开发,谁敢说自己没有知识盲区?http://ios.skyfox.org/route.html

  3. linux:系统启动流程

    系统启动流程 本文基于CentOS6 版本 黑色部分为主流程分支,蓝色部分为详细流程分支,绿色部分是注释部分 第一步--加载BIOS打开计算机电源,计算机会首先加载BIOS信息,主要负责检测系统外围关 ...

  4. 我也说说Emacs吧(5) - 基本编辑操作

    基本编辑操作 进入编辑模式 标准的emacs用户是遇不到这一节的,因为默认就可以编辑.但是spacemacs用户需要先学习一下强大的vi的模式切换功能了. vi的一个重要特点就是命令特别多,所以一旦学 ...

  5. 4. 什么是应用服务器? - JavaEE基础系列

    本文是JavaEE基础系列的第四节. Java EE简介 - JavaEE基础系列 JSR简介 - JavaEE基础系列 什么是JSR参考实现? - JavaEE基础系列 上一节介绍了什么是JSR参考 ...

  6. HDU 数位dp

    模板http://www.cnblogs.com/jffifa/archive/2012/08/17/2644847.html 完全理解以后,我发现这种写法实在是太厉害了,简洁,优美,可以回避很多细节 ...

  7. 使用vue

    使用bootstrap npm install bootstrap@3 --save 使用jQuery npm install jQuery --save ---------------- 搭建vue ...

  8. JAVA多线程----用--进阶--》网络编程1

    http://www.cnblogs.com/springcsc/archive/2009/12/03/1616413.html 一个服务器端一般都需要同时为多个客户端提供通讯,如果需要同时支持多个客 ...

  9. ExpressCache

    ExpressCache 非联想.等品牌电脑使用的ExpressCache(带破解文件). (原始安装文件+patch+说明).注意,执行eccmd命令时,需要管理员权限.否则报错. http://a ...

  10. XML 的 XPath 语法

    XPath 是 XML 路径语言(XML Path Language),用来确定XML文档中某部分位置的语言.无论是什么语言什么框架,几乎都可以使用 XPath 来高效查询 XML 文件. 本文将介绍 ...