文档库 最新最全的文档下载
当前位置:文档库 › 多线程网络编程问题

多线程网络编程问题

多线程网络编程问题
多线程网络编程问题

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.

经过实验,第二种方法也可以很好的工作。

相关文档