四、客户端
- 现在的程序还不够健全,比如——
- 服务器
正常断开
后,客户端还是正常的状态
所以需要一个
断开的链接信号
——
- 服务器断开会有一个
信号
- 服务器
网络异常(网络断开)
的情况——
但是网断开后,已经接收不到数据了,但是
服务器并没有退出
,客户端也没有任何改变
- 解决方法:定时,
如果某一段时间之内没收到数据,就关掉客户端
设置一个心跳包
(服务器和客户端隔一段时间就通信一次,证明还存活着),如果心跳包
好几秒没收到,那么server对应的套接字就可以关闭了。
因为现在已经有了一个定时器
,所以我们可以定义一个变量来表示多少次没有发送心跳包
了,再定义一个宏
(5次没有心跳包就关闭)
- 定时器对应的是更新在线用户列表,所以我们可以将
心跳包
和在线用户列表
相关联(每发一次用户列表就加1)——
心跳包重置为0的时机——
当收到
服务器心跳包的应答
的时候——
四、服务器
- 服务器的心跳包如何设置,从而在断网后可以
关闭服务器
- 难点之一——
服务器如何定时呢? -
alarm()
只能一个时刻产生一个定时器,用一个定时器不能处理多个客户端的网络状况的。
所以最好的
一个客户端对应一个定时器
,这样当产生了问题的时候,就可以把套接字
关掉了。
- 所以这里使用
多路IO复用的超时
一个客户端对应一个fd,对应一个反应堆,从而对应一个
超时时间
超时的地方一般是阻塞在read()那里,因为没有数据读
,所以可以用poll对read()进行封装。
用
poll
作为单个套接字的反应堆
——
如果超时
了,就让ret为0
,从而可以让服务器关闭套接字
- 服务器加锁
大部分客户端都在读(获取在线用户列表),只有登录(添加)和删除(退出 )的时候才是写——
读写锁
定义成全局变量 - 删除的时候要加锁,这个时候是
写锁定
——
- 插入的时候也要加锁,登录的时候也是
写锁定
——
- 读取链表的时候也要加锁,不过是
读锁定
——
- 考虑一下
管道破裂
的情况—— - 第一次写是不会破裂的,只有第二次写的时候会破裂
这里只写一次数据
write
,就算正在写的时候读端
关闭了,还是照常写,只不过是收到一个RST
。