rpc-client端连接池实现
(一)功能
使用已存在的连接与rpc-server端通信,发送请求
- 连接复用
- 并发请求
(二)设计思路
对每个要通信的server端维持一个连接池,存放已经建立的连接,需要与server通信时直接从连接池取连接,不用重新创建
- 动态连接池
连接池中连接的数量是动态变化的,如果上一时刻请求多,现在请求少,则连接池中可用连接多;相反,如果上一时刻请求少,现在请求多,则连接池中可用连接少
- 使用epoll监听连接池中连接
当连接被放入连接池后,使用epoll清理该连接现在到来的数据,因为这些数据是无效数据
(三)数据结构
- con_pool连接池
序号 | 成员 | 类型 | 含义 |
1 | mutexLock | pthread_mutex_t | |
2 | client | xxClient*[POOL_SIZE] | 客户端维持的对象池 |
3 | socket | int[POOL_SIZE] | 客户端维持的连接池 |
4 | epfd | int | 用来监控client端连接池中可用连接的epoll fd |
5 | isPurge | int | 标记位,当前连接池是否正在对连接做检测操作 |
6 | nEvent | int | epoll中监听fd数量 |
7 | nConn | int | 连接池中可用连接数量 |
8 | nMaxConn | int | 连接池中最大可用连接数量 |
9 | host | int | server端ip |
10 | port | int | server端port |
(四)实现
- con_pool* init_con_pool(host, port)
=> 初始化连接池,分配空间+初始化变量
- int con_purge_data(*pool)
=> 监听&管理连接池中可用连接,清理错误or无效连接
1)可读事件,read出错or未读到数据,则从epoll监听中删除fd且关闭连接;read未读完,继续加入监听
2)EPOLLHUP,对方关闭连接,则从epoll监听中删除fd且关闭连接
3)EPOLLERR,连接出错,则从epoll监听中删除fd且关闭连接
- int get_from_con_pool(*pool, &fd, **client)
=> 从连接池获取有效连接
遍历连接池,找到第一个有效连接fd和client,取出(socket置-1,从epoll中删除监听);
如果连接池中没有可用连接,新建连接
- bool put_to_con_pool(*pool, fd, *client)
=> 将连接放回连接池
在client和socket数组中找到第一个可用空位,将fd,*client放入,并将fd加入epoll监听
如果没有空位,连接池满,直接关闭连接
(五)使用
- 取连接
1)con_purge_data,先保证连接池中连接有效
2)get_from_con_pool,再从连接池取出第一个有效连接
- 放回连接
put_to_con_pool,直接放回连接池
(六)问题
- con_purge_data中有EPOLLIN事件且read返回0时,为什么要关闭连接?
此时client端为tcp被动关闭端,如果不调用close,连接池中会有大量socket处于close_wait状态,占用socket资源导致打开socket过多,最后崩溃