套接字I/O模型-select
共有6种类型套接字I/O模型。blocking(阻塞),select(选择),WSAAsyncSelect(异步选择),WSAEventSelect(事件选择),overlapped(重叠),completionport(完成端口)。
.select
之所以称select模型,是因为工作原理是利用select函数实现对I/O的管理。
select可用于判断套接字上是否存在数据,或者能否向一个套接字写入数据,之所以要设计这个函数,其目的是防止应用程序在套接字处于阻塞模式时,在I/O绑定调用(如send或recv)过程中进入阻塞状态;同时也放在套接字处于非阻塞模式中时,产生WSAEWOULDBLOCK错误,除非满足事先用参数规定的条件,否则select函数在进行I/O操作时会阻塞。
int select(
int nfds,
fd_set FAR* readfds,
fd_set FAR* writefds,
fd_set FAR* exceptfds,
const struct timeval FAR* timeout
);
nfds会被忽略,之所以保留是为了与早期套接字兼容
3个fd_sed,readfds用于检测可读性,writefds用于检测可写性,exceptfds用于外地数据,从根本上讲,fd_set数据类型代表着一系列特定套接字结合。
readfds集合包括符合下述任何一个条件的套接字:
.有数据可以读入
.连接已经被关闭,终止或重启
.假如已调用了listen,而且有一个连接正处于搁置状态,那么accept调用会成功
writefds集合包括符合下述任何一个条件的套接字:
.有数据可以发出
.如果正在对一个非阻塞连接调用进行处理,则连接就成功
exceptfds集合包括符合下述任何一个条件的套接字:
.如果正在对一个非阻塞连接调用进行处理,连接尝试将会失败
.有OOB(out-of-band,外地)数据可供读写
假设我们想测试一个套接字是否可读,必须将套接字添加到readfds集合中,在等待select函数完成。当select调用完成后,必须判断这个套接字是否仍为readfds中的一部分。若是,则表明该套接字可读,可立即进行读取数据。在3个参数中,任何两个都可以是NULL,但至少有一个不能为NULL,在任何不为空的集合中,必须包含至少一个套接字句柄,否则select没有任何东西可以等待。timeout对应的是一个指针,指向一个timeval结构,用于决定select等待I/O操作完成时,最多等待多长时间。如果timeout是一个空指针,那么select调用会无限期处于阻塞状态,直到至少有一个描述符与指定条件相符才结束。
struct timeval
{
long tv_sec;//秒为单位指定等待时间
long tv_usec;//以毫秒为单位指定等待时间
};
//若将时间设置为{0,0}表明select会立即返回。处于对性能考虑,应避免这么设置
对fd_set集合进行处理与检查:
FD_ZERO(*set);//将set初始化为空集合,集合在使用前都要清空
FD_CLR(s, *set);//从set中删除套接字s
FD_ISSET(s, *set);//检测s是否是set中的一个成员,如果是,返回TRUE
FD_SET(s, *set);//将套接字s加入到set中
采用以下步骤便可完成select操作一个或多个套接字句柄的全过程:
.使用FD_ZERO初始化自己感兴趣的每个fd_set
.使用FD_SET将套接字句柄分配给自己感兴趣的fd_set
.调用select函数,然后等待直到I/O活动在在指定的fd_set集合中设置好了一个或多个套接字句柄。select完成后,会返回在所有fd_set集合中设置的套接字句柄总数,并对每个集合进行相应的更新
.根据select的返回值,应用程序便可判断哪些套接字存在着被搁置的I/O操作--具体的方法是使用FD_ISSET宏,对每个fd_set进行检查
.知道了每个集合中被挂起的I/O操作之后,对I/O进行处理,然后返回步骤1,继续处理select
select返回后,它会修改每个fd_set结构。删除那些不存在被挂起的I/O操作的套接字句柄。
示例代码
SOCKET s;
fd_set fdread;
int ret; //创建套接字,接受连接 //在套接字上管理I/O
while(true)
{
//在调用select前,清楚读出集
FD_ZERO(&fdread);
//将s添加到读出集
FD_SET(s, &fdread);
if((ret=select(, &fdread, NULL, NULL, NULL))==SOCKET_ERROR)
{
//条件出错
} if(ret>)
{
//
//
if(FD_ISSET(s, &fdread))
{
//套接字s上已发生了一个事件
}
}
}
使用select的优势是能够从当个线程的多个套接字上进行多重连接及I/O。 =======================================================================
客户端代码:
这是一个最简单的客户端代码,负责发送数据,然后接受返回。
#include<stdio.h>
#include<winsock2.h>
#pragma comment(lib, "ws2_32.lib") #define SERVER_IP "192.168.1.222"
#define PORT 5150
#define MSGSIZE 1024 int main()
{
WSADATA wsaData;
SOCKET sClient;
SOCKADDR_IN server;
char szMessage[MSGSIZE];
int ret; WSAStartup(MAKEWORD(,), &wsaData);
sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
memset(&server, , sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(PORT);
server.sin_addr.s_addr = inet_addr(SERVER_IP); connect(sClient, (sockaddr*)&server, sizeof(SOCKADDR_IN));
while(TRUE)
{
printf("Send:");
gets(szMessage);
send(sClient, szMessage, strlen(szMessage), );
ret = recv(sClient, szMessage, MSGSIZE, );
szMessage[ret] = '\0';
printf("Received [%d bytes]: '%s'\n", ret, szMessage);
}
closesocket(sClient);
WSACleanup(); //system("pause");
return ;
} 服务端代码:
这是异步模型中最简单的一种,服务器端的几个主要流程如下:
.创建监听套接字,绑定,监听;
.创建工作者线程;
.创建一个套接字数组,用来存放当前所有活动的客户端套接字,每accept一个连接就更新一次数组;
.接受客户端的连接。
#include<stdio.h>
#include<winsock2.h>
#pragma comment(lib, "ws2_32.lib") #define PORT 5150
#define MSGSIZE 1024 int g_iTotalConn = ;
SOCKET g_CliSocketArr[FD_SETSIZE];
DWORD WINAPI WorkerThread(LPVOID lpParam); int main()
{
WSADATA wsaData;
SOCKET sListen, sClient;
SOCKADDR_IN local, client;
int iAddrSize = sizeof(SOCKADDR_IN);
DWORD dwThreadId; WSAStartup(MAKEWORD(,), &wsaData);
sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
memset(&local, , sizeof(SOCKADDR_IN));
local.sin_family = AF_INET;
local.sin_port = htons(PORT);
local.sin_addr.s_addr = htonl(INADDR_ANY); bind(sListen, (sockaddr*)&local, sizeof(SOCKADDR_IN));
listen(sListen, ); CreateThread(NULL, , WorkerThread, NULL, , &dwThreadId); while(TRUE)
{
sClient = accept(sListen, (sockaddr*)&client, &iAddrSize);
printf("Accepted client:%s:%d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));
g_CliSocketArr[g_iTotalConn++] = sClient;
} return ;
} DWORD WINAPI WorkerThread(LPVOID lpParam)
{
fd_set fdread;
int ret;
int i;
struct timeval tv = {,};
char szMessage[MSGSIZE];
while(TRUE)
{
FD_ZERO(&fdread);
for(i=; i<g_iTotalConn; ++i)
{
FD_SET(g_CliSocketArr[i], &fdread);
}
ret = select(, &fdread, NULL, NULL, NULL);
if( == ret)
{
continue;
}
for(i=; i<g_iTotalConn; ++i)
{
if(FD_ISSET(g_CliSocketArr[i], &fdread))
{
ret = recv(g_CliSocketArr[i], szMessage, MSGSIZE, );
if( == ret || (ret==SOCKET_ERROR && WSAGetLastError()==WSAECONNRESET))
{
printf("Client socket %d closed.\n", g_CliSocketArr[i]);
closesocket(g_CliSocketArr[i]);
if(i<g_iTotalConn-)
{
g_CliSocketArr[i--] = g_CliSocketArr[--g_iTotalConn];
}
}
else
{
szMessage[ret] = '\0';
send(g_CliSocketArr[i], szMessage, strlen(szMessage), );
}
}
}
}
}
套接字I/O模型-select的更多相关文章
- 套接字I/O模型之WSAEventSelect
今天我又学习了一种新的套接字I/O模型------WSAEventSelect,他与WSAAsyncSelect一样也是一种异步事件通知模型,不同的是WSAAsyncSelect是与窗口句柄关联在一起 ...
- 套接字I/O模型-WSAAsyncSelect
利用这个异步I/O模型,应用程序可在一个套接字上接收以Windows消息为基础的网络事件通知.WSAAsyncSelect和WSAEventSelect提供读写数据能力的异步通知,但它们不提供异步数据 ...
- Linux下套接字具体解释(三)----几种套接字I/O模型
參考: 网络编程–IO模型演示样例 几种server端IO模型的简介及实现 背景知识 堵塞和非堵塞 对于一个套接字的 I/O通信,它会涉及到两个系统对象.一个是调用这个IO的进程或者线程,还有一个就是 ...
- Windsock套接字I/O模型学习 --- 第二章
1. select模型 select模型主要借助于apiselect来实现,所以先介绍一下select函数 int select( int nfds, // 忽略,仅是为了与 Berkeley 套接字 ...
- Windsock套接字I/O模型学习 --- 第一章
1. I/O模型共有以下几种: 阻塞(blocking)模型 选择(select)模型 WSAAsyncSelect模型 WSAEventSelect模型 重叠(overlapped)模型 完成端口( ...
- 套接字I/O模型-重叠I/O
重叠模型的基本设计原理是让应用程序使用重叠的数据结构,一次投递一个或多个WinsockI/O请求.针对那些提交的请求,在它们完成之后,应用程序可为它们提供服务.模型的总体设计以Windows重叠I/O ...
- 套接字I/O模型-完成端口IOCP
“完成端口”模型是迄今为止最为复杂的一种I/O模型.然而,假若一个应用程序同时需要管理为数众多的套接字,那么采用这种模型,往往可以达到最佳的系统性能!但不幸的是,该模型只适用于Windows NT和W ...
- 套接字I/O模型-WSAEventSelect(转载)
和WSAAsyncSelect类似,它也允许应用程序在一个或多个套接字上,接收以事件为基础的网络事件通知. 该模型最主要的区别是在于网络事件是由对象句柄完成的,而不是通过窗口例程完成. 事件通知 事件 ...
- Windsock套接字I/O模型学习 --- 第三章
1. WSAAsyncSelect 模型 WSAAsyncSelect 模型比较简单,是为了适应Windows的消息驱动环境而设置的,WSAAsyncSelect 函数自动把套接字设为非阻塞模式.MF ...
随机推荐
- 谈谈你对http的理解
一.先看一张图: 二.要client与sever能沟通 1.需要一样的规则,遵循一定的规范-----------协议 好比:不同国家的人,需要一门通用的语言. 2.谈到协议------http---- ...
- javascript笔记5-BOM
Javascript应用的平台很多,不仅仅针对Web.在Web中使用Javascript,BOM(browser object model,浏览器对象模型)是核心. BOM提供了很多对象,用于访问浏览 ...
- php大力力 [007节]php静态表量
2015-08-23 php大力力007. php静态表量 这里看一下高老师的视频讲解: 转帖: php中static静态类与static 静态变量用法区别 php中的静态变量的基本用法 转载 时间: ...
- Python入门(三,初级)
一,函数调用 定义一个函数只给了函数一个名称,指定了函数里包含的参数,和代码块结构. 这个函数的基本结构完成以后,你可以通过另一个函数调用执行,也可以直接从Python提示符执行. 如下实例调用了pr ...
- HTML的表单
HTML表单 <!-- <form></form>标签对用来创建一个表单,即定义表单的开始和结束位置,<form>表单具有下面等属性 1.action属性用来 ...
- Generic method return type
Here's the Animal class: public class Animal{ private Map<String,Animal> friends =new HashMap& ...
- JS实现Tab选项卡
http://www.jb51.net/article/24694.htm http://www.sunsean.com/idTabs/#t1 http://www.cnblogs.com/sskse ...
- Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面
Android应用的开发过程中需要把繁重的任务(IO,网络连接等)放到其他线程中异步执行,达到不阻塞UI的效果. 下面将由浅入深介绍Android进行异步处理的实现方法和系统底层的实现原理. 本文介绍 ...
- iOS页面间传值的方式(NSUserDefault/Delegate/NSNotification/Block/单例)
iOS页面间传值的方式(NSUserDefault/Delegate/NSNotification/Block/单例) 实现了以下iOS页面间传值:1.委托delegate方式:2.通知notific ...
- Linux关机命令
1.halt :关机 init 0 : 关机 shutdown -h now (立刻关机) -h 指的是 halt 2.reboot 重启 init 0 重启 shutdown -r no ...