QT网络编程:服务端和客户端编程

QtNetwork中的QTcpSocket和QTcpServer类可用來编写基于TCP的client和server

 

QTcpSocket提供client端的TCP功能,能够发出TCP的请求至服务器,其实它也是具有服务端发送数据到客户端的功能

QTcpServer则提供服务器的功能,并接受TCP连接请求,以及指定port或IP位址

 

一、客户端的请求与接收数据

基于Http的客户端可以用QHttp来编写。关于如何使用QHttp编写客户端请求和响应处理函数的例子很多,QHttp类也提供了多种请求方式,如get、post、head、request,下面是一个get方法发送请求的例子:

 

HttpGet.h 

 #ifndef HTTPGET_H #define HTTPGET_H #include class QUrl; class QHttp; class HttpGet : public QObject { Q_OBJECT public: HttpGet(QObject *parent = 0); void get(const QUrl &url); signals: void finished(); private slots: void done(bool error); virtual void httpRequestFinished(int, bool); private: QHttp *http; QBuffer *buffer; int m_httGetID; }; #endif

 这个HttpGet可以按照url地址进行Http请求,完成请求后会发出finished()的Signal,当QHttp所指定的全部请求完成时,会发出done()的Signal,HTTPGet类中自定义的Slot就是用来接收QHttp的done() Signal以进行相关处理的,这可以在HttpGet的实现中看到:

 

HttpGet.cpp

#include #include "HttpGet.h" #include HttpGet::HttpGet(QObject *parent) : QObject(parent) { http = new QHttp(this); connect(http, SIGNAL(done(bool)), this, SLOT(done(bool))); connect(http, SIGNAL(requestFinished(int, bool)), this, SLOT(httpRequestFinished(int, bool))); } void HttpGet::get(const QUrl &url) { if (response == NULL) { response = new QBuffer; if (!response->open(QIODevice::WriteOnly)) { delete response; response = 0; return; } } http->setHost(url.host(), url.port(80)); m_httGetID = http->get(url.path(), response); http->close(); } void HttpGet::done(bool error) { if(error) { cerr<<"Error: "<errorString())<state() << "/n"; } void HttpGet::httpRequestFinished(int requestId, bool error) { if (requestId != m_httpGetId) { qDebug() << "error/n"; return; } else { qDebug() << "request finished! the bytes' size is : " << response->data().size() << "/n"; } }

 

    HttpGet类实现了Http请求,并通过响应消息的槽httpRequestFinished函数对接收到的数据流进行解析,实现网络通信。

注意事项:

(1)书上和网上很多的例子都是直接根据url.path()来请求服务端的一个文件,但是url.path()函数得到的字符串不包含"?"及"?"号之后的字符串,所以不能只用url.path(),而应该还要加上查询字符串QString requestPath = url.path() + queryString

譬如:

QString queryString("?a=china&b=dazhi");

QUrl url("http://localhost:8081/" + queryString); //创建URL地址

QHttp http;

http.setHost(url.host(), url.port());

(2)//注意:一定要将m_httpGetId 保存,因为在通讯过程中,处理requestFinished消息的槽会判断m_httpGetId与当前状态下requestId是否相等,只有在相等时,才能正确进行解析客户端接收到的数据流,否则可能数据不完整。

 

二、服务端的响应与发送数据

    使用QTcpServer进行了服务器的创建,这里就不多说了,例子很多,但是QT的文档里和网上几乎没有关于如何使用QTcpSocket将数据传输到客户端的例子,我在使用QTcpSocket进行数据发送时,采用了如下方法:

譬如使用的QTcpSocket对象是tcpServerConnection,在响应请求消息并进行处理后,将数据发送到客户端,可以使用:

    tcpServerConnection->write(ba),其中ba是要输出到客户端的字节流QByteArray对象。

    有趣并折磨我很久的事情发生了!使用IE浏览器请求该服务器时,能够正确获取并解析数据,但我使用QHttp编写的客户端程序却死活也不能正确解析出接收到的字节流数据,跟踪后发现得到的数据流长度小于服务端的数据流长度,但为什么IE浏览器能正常解析呢???

    后来终于发现QT的服务端的response默认情况下不包括response header信息,而使用QHttp编写的客户端接收数据时又会默认认为接收到的数据包含了response header,导致它在解析数据流时,会把前面一部分数据作为header信息,而后面的才为作为传输的数据,这样解析出来数据流长度就会减少了,从而不能正确解析数据。因此我们需要在服务端发送数据时输出header信息,再输出我们所要传输的数据。

   下面是将影像数据流传输到客户端的示例:

   //下面的代码是服务端响应readyRead()消息的槽函数内的代码 QBuffer buffer; QImageWriter writer(&buffer, "PNG"); QImage image("F://test.png"); writer.write(image); QByteArray data = buffer.data(); QHttpResponseHeader header(200, "OK"); header.setContentType("image/png"); //header.setValue( "Content-Encoding", "UTF-8" ); header.setContentLength( data.size() ); tcpServerConnection->write( header.toString().toUtf8() ); tcpServerConnection->write( data ); qDebug() << "size is : " << data.size() << "/n"; qDebug() << data;

 

三、总结

    QT的例子程序不够丰富全面,深度也不够,甚至网络编程中服务端和客户端的消息模式都有区别,导致不知道内部机制的情况下,无法正确编写程序,真希望QT在快速发展的同时能为我们开发人员提供更加全面的示例程序。

 

你可能感兴趣的:(QT网络编程:服务端和客户端编程)