退出服务器
多线程非阻塞模式实例
多线程非阻塞模式到现在算是告一段落吧 虽然还有一些小的bug需要修正 总结一下 准备向后面进发
实现功能: 本程序主要实现远程计算的功能 通过非阻塞套接字和多线程的结合 让通信变得高效 服务器通过维护一个客户端链表来实现对多个客户响应 客户端自身验证表达式的正确性 当输入Byebye时 服务器回复OK 此时客户端断开连接退出
主要模块和线程管理
服务器:
主线程:初始化服务器
运行服务器
监听线程:
接收客户端连接请求
创建客户端节点
启动对客户端节点的服务
清理线程:
当服务器运行时:
定期检查清理已退出的客户节点
当服务器断开时
断开所有对客户端的连接
清理客户节点知道客户端链表为空
客户端类:接收线程:
接收客户端的数据 并且处理
发送线程:
发送已经处理后的数据
客户端:
主线程:
初始化客户端
连接服务器
执行处理输入输出
退出客户端
接收数据线程:
接收服务器数据 并且通知主线程显示
发送数据线程:
发送主线程处理好的数据
关于线程同步:
从客户端说起:
各个线程维持一个运行状态变量bConning 用于线程循环外侧检测退
主线程在成功连接至服务器后 bConning = TRUE 创建接收和发送线程
这三个线程之间的交互:
一。正常交互
1.主线程在执行输入处理完数据后放入SendBuf 通过hEventSendData来通知发送线程(对SendBuf互斥访问)
2.接收线程在将接收数据拷贝到RecvBuf后 通过hEventShowData来通知主线程显示数据(对RecvBuf互斥访问)
二。退出交互
1.接收线程先退出 设置bConning为FALSE 并SetEvent(hEventShowData)
对于发送线程 检测到bConning==FALSE 立即退出
对于主线程 在显示数据前检测bConning==FALSE 直接跳出 之后调用WaitForMutiObjects等 待发送线程和接收线程均退出
2.发送线程先退出 设置bConning为FALSE 并SetEvent(hEventShowData) 如果不调用这条 主线程有可能无限等待显示数据
对于接收线程 检测到bConning为FALSE 退出循环
对于主线程 在显示数据前检测bConning==FALSE 跳出 等待接收和发送均退出
3.主线程退出 当服务器回复"OK" 表示用户输入Byebye 此时断开连接 等待接收和发送退出
发送和接收线程均检测到bConning为FALSE 跳出循环
服务器:
服务器的客户端类:
一。正常交互:
1.接收线程接收到数据后进行处理后 将数据拷贝到数据缓冲 用hEvent通知发送线程发送(对数据缓冲互斥访问)
2.发送线程发送数据 并且恢复hEvent为无信号
二。退出交互:这里的发送线程在退出循环后通过WaitForSingleObject(hThreadRecv)来设置整个客户端的m_exit状态
1.接收线程先退出 设置bConning为FALSE SetEvent(hEvent)
发送线程在等待到hEvent时 先判断bConning==FALSE时 退出循环
2.发送线程先退出:设置bConning为FALSE 在跳出循环后 等待接收线程退出 设置m_exit=TRUE 用于清理线程清理节点 接收线程检测到bConning=FALSE 跳出循环 退出
服务器三个总维护线程:
一。正常交互: 类似前面 三个线程维护同一个状态变量bServerRunning
1.服务器主线程 初始化服务器 并且根据用户输入打开和断开服务器
在打开服务器时 设置bServerRunning = TRUE创建监听和清理线程
在断开服务器时 设置bServerRunning=FALSE 并且通过清理线程结束的信号量hServerEvent退出服务器
2.服务器监听线程 不断监听来自客服端的连接请求 添加新的客户端节点到客户端链表 并交由清理线程维护
3.客户端清理线程 测各个节点是否退出(m_Exit==TRUE) 并且移除链表 清理节点内存 当服务器退出时 断开所有客户端连接 确保所有的客户节点均已退出(cClientList.size() == 0)
二。退出交互: 1.服务器主线程先退出:服务器主线程不会先退出 在接收到断开服务器请求时 只是bServerRunning=FALSE
之后监听线程停止 服务器等待清理线程结束事hServerEvent后 退出
2.监听线程先退出: 设置bServerRunning为FALSE 并退出
之后清理线程开始断开所有客户端连接 清理完成后SetEvent(hServerEvent)
而服务器界面仍在等待输入是否退出服务器 一旦用户输入后(即使不是退出命令) 服务器也将立即跳出循环 根据hServerEvent状态退出(bug之一)
3.清理线程不会主动退出(除非遇到内存引用错误)
总的三个模块交互:
客户端退出 那么服务器客户端类的SendThread或RecvThread先后遇到错误退出 导致节点m_Exit==TRUE 被清理 服务器退出 那么客户端的发送和接收将失败 也将导致退出
服务器通过清理线程来同时断开所有客户连接
服务器客户端类通过m_Exit来告诉清理线程可以清理该节点
客户端通过回复内容为OK来得知用户输入了Byebye 并且开始退出自身
总结:
不管用何种方式通信 相关联的几个线程总会用一个变量来控制所有的其他线程
对于非阻塞套接字 Recv Send Connect Accept等都需要套上一个基于共同控制变量或者永真的循环来实现对WSAEWOULDBLOCK的返回重试
对于通过事件信号量来通知的两个线程 例如生产者 消费者(生产者生产好了通过hEvent通知消费者) 当生产者退出时 一定要通过该信号量来通知消费者 以免消费者阻塞于WaitForSingleObject 而消费者在等到信号量时 也一定要检测生产者是否已经退出(或者是说在这里的断开了连接) 以免发送或接收未知的数据
对于有信号量控制的两个同步线程 要注意是否有共同访问的数据 要时刻记得对数据进行互斥访问
代码地址:
http://download.csdn.net/detail/wudaijun/4709715
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.