一个非常有趣的QTcpServer多线程编程问题
来源:互联网 发布:中文域名安全性 编辑:程序博客网 时间:2024/05/18 02:08
Qt 4.6自带的threaddedfortuneserver是个简单明了的 Qt C/S网络编程server端程序的例子, 该例子演示了 QTcpServer与QThread配合的方法。 代码不多, 但包含了Qt网络编程的几个关键点。
- FortuneServer类从QTcpServer派生, 调用QTcpServer::listen() 监听端口等待client连接
- FortuneServer重写了虚函数 incomingConnection()去接受client连接, 并创建线程处理该连接
- FortuneThread是处理client连接的子线程, 在该线程里向client端写入数据
结构非常简单。 笔者本来想照着这个架构写个接收client数据的小server, 在写的过程中发现了一个很有意思的问题, 且听我慢慢道来。
不知道大家有没有发现, 其实FortuneServer这个类看起来是QTcpServer类的简单包装, 并没有加入新的东西, 笔者就尝试去掉此子类直接使用QTcpServer。设想的程序架构是这样的:
- 使用QTcpServer监听端口等待client连接
- 在收到QTcpServer::newConnection信号时调用 nextPendingConnection获得socket 连接, 将socket 连接的fd传送给子线程
- FortuneThread是处理client连接的子线程, 得到连接的fd后创建一个QTcpSocket并用QTcpSocket::setSocketDescriptor, 这样就可以用QTcpSocket的方法来监控fd的动向了。
这里我们用QTcpSocket::waitForReadyRead等待client端发来的数据
为了得到与client的连接的socket fd, 调用了 QTcpServer::nextPendingConnection()方法获得一个QTcpSocket指针, 从该指针得到连接的fd, 再将该fd传送给子线程去处理。 看上去与原来的程序没什么区别, 但运行起来却发生了奇怪的问题, 那就是有时server的waitForReadyRead返回true时却读不到数据(bytesAvailable() = 0)似乎client发来的数据丢了一样。 真是让人百思不得其解。
说到这里, 不知道有没有同学意识到究竟哪里出了问题。 笔者研究再研究始终没弄明白, 只能隐约觉得和这个incomingConnection/nextPendingConnection 有关。 后来找了个高人帮忙才搞清楚, 原来问题确实出了nextPendingConnection上。
仔细回想一下我们的程序的架构, 在server进程里调用nextPendingConnection获得一个QTcpSocket的指针, 将此指针内的fd信息发送给子进程由子进程负责与client通讯。 大家再想想QTcpSocket提供了那么多的API包括signal等, 这意味着什么? 肯定Qt在底层对fd进行了监控啊, 也就是说在我们的程序里出现了两个QTcpSocket分别在两个线程里对同一个fd进行了监控和操作, 所以出现一些奇怪的现象也就不算奇怪了。 如果大家尝试对主线程的QTcpSocket进行处理就会发现, 所谓“丢失”的数据都可以在这个socket里得到, 即有一部分socket的数据由于线程切换的关系由主线程的socket截获了。
为了解决这个问题当然最好的办法还是沿用例子中的架构, 对QTcpServer进行派生, 因为在incomingConnection的参数里可以直接得到fd, 此时还没有创建QTcpSocket对此fd做任何操作, 是个干净的状态, 不会有任何冲突;
另外还有一个办法是在不改变现有程序架构的情况下把这两个QTcpSocket搬到同一个线程里。 这样也不会出现两个线程同时访问一个fd的情况。 具体是使用 QObject::moveToThread方法。 需要注意的是文档中对moveToThread有个说明, 有parent的object是不能被移动到其他线程中的, 所以还需要把QTcpSocket给setParent(NULL)一下再moveToThread.
经过实验, 第二种方法也可以很好的工作。
- 一个非常有趣的QTcpServer多线程编程问题
- 【SHELL】一个非常有趣的问题
- 【SHELL】一个非常有趣的问题
- 一个有趣的多线程问题
- 多线程的QTcpServer
- 有趣的多线程编程
- Java多线程学习中遇到的一个有趣的问题
- 一个有趣的问题
- 一个有趣的编程题
- 应用多线程的一个有趣的现象
- 关于继承和接口的一个非常有趣的比喻
- 关于继承和接口的一个非常有趣的比喻
- 一个有趣的SQL问题。
- 一个有趣的小问题
- 一个有趣的SQL问题。
- 一个有趣的SQL问题。
- 一个有趣的指针问题
- 一个奇怪有趣的问题
- ios5 选择了ARC但是不使用ARC编译,-fno-objc-arc
- 网络营销的精准之道
- web项目如何切换jdk
- Android zip文件压缩解压缩
- 《C++设计模式》第二章:创建(对象)型模式之工厂模式(多态性工厂模式)
- 一个非常有趣的QTcpServer多线程编程问题
- poj 2142 The Balance (基础扩展欧几里得)
- read和getchar的阻塞和非阻塞输入
- 基于FBX SDK的FBX模型解析与加载
- RHEL5下编译2.6.26.5内核
- 免费的Web压力测试工具
- maven编译项目抛出out of memory
- Google Dremel 原理 - 如何能3秒分析1PB
- 快速把web项目部署到weblogic上