多线程非阻塞模式实例

多线程非阻塞模式到现在算是告一段落吧 虽然还有一些小的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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章