利用select异步I/O模型实现群聊

之前所有写的socket程序都是“同步阻塞”的,这里的“同步”是指,应用中的函数调用与相应的操作系统内核中的函数是同步的,“阻塞”指的是当accept,recv,send等函数还没有确认/接收/发送时,相应的线程处于等待状态,无法继续往下执行。

“同步阻塞”虽然易于理解与实现,但是是一种效率很低的模式,因为当阻塞的时候,这个线程是不能干任何事情的,因此,“异步非阻塞”是一种效率更高的方式。

利用

int iMode = 1;
retVal = ioctlsocket(sHost, FIONBIO, (u_long FAR*) &iMode);可以将sHost这个套接字设置成非阻塞模式。

设置成非阻塞模式以后,需要将accept等阻塞函数放在一个死循环里面,因为非阻塞状态下这些函数一旦执行,不管成功与否都会接着往下执行,如果还没有到相应的条件(如recv函数的条件是收到了字符串)就会返回一个错误值WSAWOULDBLOCK,如果返回的是这个错误值的话,说明函数本没有出错,只是依然“被阻塞”,条件还没到达而已,所以需要继续执行循环,如果返回了错误,而且不是WSAWOULDBLOCK,则说明是真的出错了。

select模型是一种异步I/O模型,使用fd_set来管理套接字池。

typedef struct fd_set {
  		u_int fd_count; 
  		SOCKET fd_array[FD_SETSIZE]; 
} fd_set;
select函数可以将指定的fd_set中处于就绪状态的套接字筛选出来。

int select(	int nfds, 
     		fd_set* readfds, 
     		fd_set* writefds, 
     		fd_set* exceptfds, 
     		const struct timeval* timeout ); 

参数说明如下:
nfds,只为与Berkeley套接字相兼容而保留此参数,在执行函数时会被忽略。
readfds,用于检测可读性的套接字集合。返回的fd_set已经是经过筛选的就绪套接字了
writefds,用于检测可写性的套接字集合。同上
exceptfds,用于检测存在错误的套接字集合。同上
timeout,select()函数等待的最长时间。如果是阻塞模式的操作,则将此参数设置为null,表示永不超时。

返回值是就绪套接字数目的总和,返回处于就绪状态并且已经包含在fd_set结构中的描述字总数;如果超时则返回0;否则的话,返回SOCKET_ERROR错误。

套接字集合操作宏:
FD_CLR(s, *set):从集合中删除指定的套接字。
FD_ISSET(s, *set):如果参数s是集合中的成员,则返回非0值,否则返回0。
FD_SET(s, *set):向集合中添加套接字。
FD_ZERO(s, *set):将集合初始化为空集合。

基于此模型,可以简单实现一个多人群聊
不断将所有套接字放进读就绪套接字集合和写就绪套接字集合中,然后一次select筛选出真正就绪的套接字,如果是读套接字的话,判断是不是监听套接字(监听套接字只需要 一个),如果是的话说明有连接请求,accept就行了,如果不是监听套接字说明是有数据可读,读出来,更新这个套接字的DataBuf和Buffer即可。如果是写套接字,则查看DataBuf和Buffer是否为空,不为空则需要发送数据,为空则略过。
使用SOCKET_INFORMATION保存套接字信息,接收到字符串以后存在Buffer和DataBuf中,如果DataBuf.len>0的话,说明接收到了字符串,需要转发给其它除了监听socket 和本socket以外的所有已连接的socket。发送完毕以后Buffer和DataBuf清零,表示这个socket没有数据需要发送了。
服务器端代码如下:
// select_test.cpp : 定义控制台应用程序的入口点。
//

#include "std
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值