全部博文(584)
分类:
2011-01-19 22:21:37
QT4中构建多线程的服务器
而对于服务器来说,多线程的这个特性太有用了,因为多线程使得服务器可能同时响应多个客户端的请求,所以现在服务器大多采用多线程,所以才会造成我开始的误解。
不管是多线程,还是服务器,QT中已经封装好了特定的类,所以使用起来也很方便。
下面一个支持多线程、TCP的服务器。
首先建立一个服务器。新建一个类(Server)继承QT中的QTcpServer类即可。服务器的职责是监听端口。当监听到有客户端试图与服务器建立连接的时候,分配与客户端连接,再进行数据。QTcpServer的listen()方法执行监听过程,可以指定监听的地址和端口。若给定了QHostAddress类型的监听地址,则监听该地址,否则,监听所有地址;若给定了quint16类型的监听端口,则监听该端口,否则,随机选定一个监听端口。
QTcpServer有一个虚函数incomingConnection(int socketDescriptor),服务器每当监听到一个客户端试图建立连接的时候,会自动调用这个函数,因此,处理这个请求的过程就可以在这个函数中 电影,即在子类Server的定义阶段,重新定义incomingConnection()这个函数。对于一个多线程的服务器,每当客户端试图连接的时 候,服务器应该启动一个线程,负责对这个客户端进行服务,所以,incomingConnection()这个函数所要做的就是建立一个线程,而所建立的 线程的作用就是对客户端进行服务,而这其中建立socket连接是基础。服务器在监听到客户端试图建立socket连接时,会为此socket分配一个唯 一的标识socketDescriptor,这个标识将在服务器端建立socket连接时使用,所以应提供给每一个线程。
在QT中使用多线程,建立一个类(Thread)继承QThread类即可。QThread类也有一个虚函数, 这个函数是run(),线程建立并启动(QThread::start())后,就会执行这里面的代码,因此,线程的逻辑过程就应该在run()里面定 义。服务器的线程要根据socketDescriptor标识的socket建立连接,然后进行数据通信,所以要将socketDescriptor传入 到Thread中,前面说过,线程是在incomingConnection()里面建立,用构造函数将socketDescriptor传入 Thread类,再用socketDescriptor建立socket连接。
定义incomingConnection()
定义run()
自此,一个简单的多线程服务器建立完毕。
写的不好,望请指教。
============================
QT4中socket通信
近的课程设计让我重新开始使用QT,上次数据结构的也是用QT,虽然是做出来了,但是现在想想,那个时候对QT的理解,或者说得更广一点,对OO的理解,简直太差劲了,当然,人的知识是进步的,所以现在有这样的感受是很正常的。虽然整体的开发工作还没有完全结束,但是已经有了很多心得体会,所以特来记录分享一下。
我们的系统采用的是C/S结构,所以客户端与通信是最关键,不幸的是,虽然我们没有用过QT的类,我们也没有估计好的难度,等到意识到第一次使用的困难时,已经是第5天了,始终没有进展,我临危受命。现在是第6天,刚刚把通信模块封装好,算是对这两天的的一个回报。
我们遇到的问题socket已经,并且发送端已经将消息发送,但是接收端始终收不到消息。(我用的socket类型是TCP,也就是QTcpSocket类)
发送端(发送端一直不存在问题)代码如下:
有问题的接收端代码如下:
以上是最原始的接收和发送端工作过程,调试过程中,分别讲两端的socket的状态打印出来,结果是发送端为A connection is established. 而接收端为The socket has started establishing a connection. 也就是说发送端正确的建立了连接,并将数据写入,而接收端只是正在建立连接,而并没有建立好,所以是根本不会受到数据的。所以先要确保接收端的连接建立 好。waitForConnected()方法就可以解决这个问题,它将一直等待直到连接已经建立。
改进后的接收端代码:
此时,接收端输出的socket状态为A connection is established,连接成功建立。
但是还是收不到信息,参考
了一下别人的程序,再比对一下参考手册,原来QTcpSocket的爷爷类(其实是父类QAbstractSocket的父类)QIODevice有一个
readyRead的信号(signal),当信息准备好并可以读的时候,这个信号就将发出,也就是说,只有当这个信号发出的时候,才可以读消息。所以要
把读消息的动作read作为一个槽(slot),并将其与readyRead信号连接。
但是直接触发socket信号,而不用图形界面的动作来触发一个动作并由这个动作来触发socket信号一直也触发不了read这个动作。但是我要 封装成一个接口类提供给上层使用,用图形界面自然是不现实的,于是翻阅了手册,发现了一个QAbstractSocket类的一个方法—— waitForReadyRead(),这个方法将一直等待到数据可以读时结束,此时就可以读数据了。方法也很简单:
这样,数据成功读取出来,实现数据的通信。
单向的数据传输问题解决了,然后再利用单向的数据通信组装成双向的数据通信,这过程中也会遇到不少问题,将在另一篇日志介绍。
========================