MFC基于select模型的套接字类之服务器(6)
来源:互联网 发布:企业网络规划方案 编辑:程序博客网 时间:2024/05/16 14:53
(2)套接字的Select模型
Select模型是套接字中最常见的模型。它的核心是利用select()函数实现套接字的输入输出管理。利用select()函数,应用程序可以判断指定套接字上是否存在数据,如果套接字上存在数据,则调用recv()函数进行接收;还可以通过该函数判断能否向指定套接字上发送数据,即指定套接字是否已经准备好接收数据,如果已经准备好,则调用send()函数发送数据。
在使用Select模型时,需要用到fd_set结构以及FD_ZERO、FD_SET等宏。
fd_set是一个管理多个套接字的结构体。该结构体的定义为
typedef struct fd_set{ u_int fd_count; SOCKET fd_array[FD_SETSIZE];}fd_set;其中,fd_count表示管理的套接字数量;fd_array是SOCKET类型的数组,其元素是管理的套接字,FD_SETSIZE的值是64,也就是说最多可以管理64个套接字。在前文提到的select()函数就是对fd_set类型的变量进行管理。
FD_ZERO宏:该宏的作用是初始化fd_set结构的对象;
FD_SET宏:该宏的作用是将指定的套接字加入到fd_set结构的对象中;
(2)Select模型的实现
在ThreadFunc_RecvData()函数中,首先定义fd_set结构的对象,用来保存要管理的套接字:
fd_set socket_fs;
接下来通过while()语句,循环接收来自客户端的数据。
int socketindex = pServer->m_client_currentindex;while (pServer->m_clientconnectflag_array[socketindex]){ ........}其中,pServer是ThreadFunc_RecvData()函数的参数,使用方法在“2.3.3定义线程函数”中已介绍。通过pServer可以在CTCPSocket_Server类的静态函数中调用该类的普通成员。m_client_currentindex是套接字在“套接字池”中的索引,该索引值在“2.3.2指定回调函数”提到的代码中获取。将m_client_currentindex保存在变量socketindex中的原因是,在接受客户端连接的线程ThreadFunc_StartServer中,如果有新的客户端连入服务端,m_client_currentindex值会发生改变。如果不将该值保存在临时变量中,在接收客户端数据时可能会发生错误。
while()的循环语句是数组pServer->m_clientconnectflag_array中的元素。在“2.3.3定义线程函数”中提到,该数组中包含的是“套接字池”中的套接字是否可用的标志。也就是说,当指定的套接字可用时,while()循环的语句才被执行。当将相应的元素值设置为false时,将结束接收数据的线程。
在while()循环中,首先调用FD_ZERO宏清空套接字集合socket_fs,之后将与客户端通信的套接字添加到该集合中。
FD_ZERO(&socket_fs);FD_SET(pServer->m_clientsocket_array[socketindex], &socket_fs);FD_SET()宏的第一个参数是要加入集合的套接字,第二个参数是套接字集合的指针。之后,利用select()函数判断套接字集合中的套接字是否可读、可写。select()函数的格式为
int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, const struct timeval* timeout);
其中,参数nfds为保留参数,可以将其设置为0;readfds是具有可读性套接字集合的指针,如果要判断套接字集合中的套接字中是否有数据,则要设置该参数;writefds是具有可写性套接字集合的指针,如果要判断套接字集合中的套接字是否已经准备好接收数据,则要设置该参数;exceptfds是检查错误套接字集合的指针,如果要检查套接字集合中的套接字是否发生错误,则要设置该参数;timeout用于设置调用select()函数时的等待时间,其类型是timeval结构,该结构主要指定时间,其格式为
typedef struct timeval{long tv_sec;long tv_usec;}timeval;tv_sec表示秒,tv_usec表示毫秒,在使用时指定两个成员变量中的一个即可。select()函数的返回值是套接字集合中发生可读、可写或者异常的套接字数量,如果是0则表示已经过了等待时间还没有发生可读、可写或者异常。
if (select(0, &socket_fs, NULL, NULL, &time_selectwait) == 1){value_recvretrun = recv(pServer->m_clientsocket_array[socketindex], buf, LENGTH_RECVDATA, 0);if (pServer->m_receiveclientdata_proc != NULL){pServer->m_receiveclientdata_proc(buf, LENGTH_RECVDATA, socketindex);}}其中,time_selectwait是timeval结构的对象,其定义为
timeval time_selectwait = { 0, 5000 };即select()函数等待5秒钟后,如果在套接字集socket_fs中没有套接字变为可读,则函数返回0,此时通过while()语句,继续调用select()函数等待套接字变为可读,即select()函数返回值是1。当套接字变为可读,则说明套接字中有数据等待读取,此时调用recv()函数接收数据。
(3)接收数据
服务端通过recv()函数,通过套接字接收来自客户端的数据。该函数的格式是
int recv(SOCKET s, char* buf, int len, int flags);其中,参数s表示指定的套接字;buf指定了保存数据的缓冲区;len表示缓冲区buf的长度;flags参数会影响recv()函数的行为,如果将该参数设置为0,则表示没有特殊行为。如果成功接收到了来自客户端的数据,则recv()函数的返回值为接收到数据的大小。
在接收到了客户端数据之后,调用“2.3.2指定回调函数”中提到的回调函数m_receiveclientdata_proc,将接收到的数据交给主窗口来处理。
(4)更新“套接字池”
当客户端退出时,需要对服务端的“套接字池”进行更新。客户端的退出分为两种情况:“优雅”退出和“强行”退出。“优雅”退出指的是客户端调用了closesocket()函数关闭套接字,“强行”退出指的是直接关闭了客户端程序。recv()函数通过不同的返回值来反映这两种退出。当客户端“优雅”退出时,recv()函数的返回值是0;当客户端“强行”退出时,recv()函数的返回值是-1,即SOCKET_ERROR。所以,在“(3)Select模型的实现”中提到的while()循环的执行代码中,还需添加对recv()函数返回值的判断:
if (SOCKET_ERROR == value_recvretrun || 0 == value_recvretrun){closesocket(pServer->m_clientsocket_array[socketindex]);pServer->m_clientconnectflag_array[socketindex] = false;}当客户端退出时,服务端通过closesocket()函数关闭与客户端通信的套接字,并且把“套接字池”的客户端套机字是否合法的数组进行更新,将该数组的相应元素设置为false。此时,while()循环会退出。在循环退出之后,对“套接字池”的客户端当前索引值进行更新
pServer->m_client_currentindex--;
- MFC基于select模型的套接字类之服务器(6)
- MFC基于select模型的套接字类之服务器(1)
- MFC基于select模型的套接字类之服务器(2)
- MFC基于select模型的套接字类之服务器(3)
- MFC基于select模型的套接字类之服务器(4)
- MFC基于select模型的套接字类之服务器(5)
- MFC基于select模型的套接字类之服务器(7)
- MFC基于select模型的套接字类之服务器(8)
- 套接字的select模型
- 异步套接字编程之select模型
- 套接字select模型
- 套接字select模型
- 套接字select模型
- C# 套接字的select选择模型
- 套接字的select、WsaAsyncSelect、WsaEventSelect模型
- 套接字的select、WsaAsyncSelect、WsaEventSelect模型
- .基于事件套接字集合的select模型
- 基于事件套接字集合的select 模型
- 设计模式(2)-抽象工厂模式(Abstract Factory)与生成器模式(Builder)模式
- HDOJ 1334 Perfect Cubes
- tensorflow GPU显存控制
- 线性代数之四:线性变换
- Spring定义bean的三种方式和自动注入
- MFC基于select模型的套接字类之服务器(6)
- windows核心编程之纤程
- [动态规划] 特别的教程
- Android(II)Androidstudio 一直卡在Building "xxx" gradle project info的解决办法
- 【NOIP2017提高A组冲刺11.6】总结
- 深搜 newoj 2015邮票
- LibreOJ NOIP Round #1
- runtime序列化&反序列化
- 多态