网络编程学习记录
- 使用的语言为C/C++
- 源码支持的平台为:Windows / Linux
笔记一:建立基础TCP服务端/客户端 点我跳转
笔记二:网络数据报文的收发 点我跳转
笔记三:升级为select网络模型 点我跳转
笔记四:跨平台支持Windows、Linux系统 点我跳转
笔记五:源码的封装 点我跳转
笔记六:缓冲区溢出与粘包分包 点我跳转
笔记七:服务端多线程分离业务处理高负载 点我跳转
笔记八:对socket select网络模型的优化 点我跳转
笔记九:消息接收与发送分离 点我跳转
笔记十:项目化 (加入内存池静态库 / 报文动态库) 更多笔记请点我
- 东西不多,简单记录一下,今后可能会补充
零、思路与流程
select网络模型的大概流程如下:
1.获取一个至三个fd_set
集合,获取一个timeval
2.select
函数对fd_set
集合进行选择筛选
3.FD_ISSET
函数依据fd_set
集合遍历查找待处理事件
WINSOCK_API_LINKAGE int WSAAPI select(
int nfds,//是指待监听集合里的范围 即待监听数量最大值+1
fd_set *readfds,//待监听的可读文件集合
fd_set *writefds,//待监听的可写文件集合
fd_set *exceptfds,//待监听的异常文件集合
const PTIMEVAL timeout);//超时设置 传入NULL为阻塞模式 传入timeval结构体为非阻塞模式
返回值为满足条件的待监听socket数量和,如果出错返回-1,如果超时返回0。
一、对fd_set
的优化
首先,我们可以对fd_set
的相关操作进行优化。
之前,我们每进行一次select
操作,都要使用循环把所有的已连接socket放到fd_set
集合中,随后进行选择操作。但是当连接数很大、select操作频繁时,不断的新建fd_set
并用循环放入socket,很明显会大大增大系统的消耗。
由于fd_set
集合中一定存放的是当前所有的socket,由此,我们可以建立两个fd_set
集合与一个bool
变量。bool
变量用来表示socket的组成是否发生了变化,当有客户端加入或断开时,该变量为true,否则为false。
我们使用一个fd_set
集合储存"老的"socket集合,当socket集合没有发生变化时,我们另一个新fd_set
集合直接使用memcpy
函数复制老集合中的内容,从而避免从头循环放入。当socket集合发生变化时,新集合直接循环从头录入,随后老集合使用memcpy
函数把新集合内的内容复制过去,方便下一次使用。
这样,我们即可大大减少关于fd_set
集合初始化的消耗。
二、对select
函数的优化
当前我的代码只对read可读集合进行操作,并没有write可写集合与except异常集合的操作,所以我的select目前第三、第四个参数都传了空。这样可以增加一点select的效率。
select(_sock+1,&fdRead,0,0,&s_t);
其余因为select函数被封装了,目前就我的水平来言应该没法做进一步的优化,可能以后会有吧。
三、对FD_ISSET
的优化
这是select架构里吃资源的大头,当socket连接数很大时,显而易见的是这种O(N^2)的查询方法会极大的消耗资源。对此我们可以引入map加快查找操作。
std::map<socket,Client> _clients;
socket当键,客户端对象当值。根据select处理后的fd_set
集合内的socket进行查找。效率提高为O(lgN)。