最近使用一个第三方PDF控件,此控件提供的一个打开文件方法只能支持http和https协议,所以没办法加载本地文件,最后试了半天各种方案,决定在程序内部启动一个简单的http服务器。
原理很简单利用传输层的TCP协议,模拟HTTP协议。
首先搞清http是如何加载网络文件的,方法很简单,在浏览器里面打开一个文件(我这是需求是PDF类型),然后用抓包工具看返回数据格式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
HTTP/1.1 200 OK Content-Type: application/pdf Last-Modified: Mon, 08 Dec 2014 08:58:40 GMT Accept-Ranges: bytes ETag: "9516d29c512d01:0" Server: Microsoft-IIS/7.5 X-Powered-By: ASP.NET Date: Mon, 02 Nov 2015 08:34:34 GMT Content-Length: 545923 %PDF-1.5 %µµµµ 1 0 obj <</Type/Catalog/Pages 2 0 R/Lang(zh-CN) /StructTreeRoot 38 0 R/MarkInfo<</Marked true>>>> endobj 2 0 obj
这是一个简单的http协议,不是所有项都需要,只要模拟下面几项就可以了
1.HTTP/1.1 200 OK
2.Content-Type: application/pdf
3.Accept-Ranges: bytes
4.Content-Length: 545923
5.文件二进制数据
下面是代码:
httpSvr.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#pragma once #include <QCoreApplication> #include <QNetworkInterface> #include <iostream> #include <QObject> #include <QTcpSocket> #include <QTcpServer> #include <QDebug> #define PORT 61301 // TCP 端口1 class httpSvr : public QObject { Q_OBJECT public: explicit httpSvr(QObject *parent = 0); ~httpSvr(); QTcpSocket *socket; int port(); public slots: void myConnection(); void readMessage(); private: QTcpServer *server; int _port; signals: };
httpSvr.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include "httpSvr.h" #include <QFile> #include <QChar> using namespace std; httpSvr::httpSvr(QObject *parent) : QObject(parent) { socket = 0; // 客户端socket server = new QTcpServer(this); connect(server, SIGNAL(newConnection()),this, SLOT(myConnection())); qDebug()<< "httpSvr start listen, port:"<< PORT; if(server->listen(QHostAddress::Any, PORT)) { qDebug()<<"success"; } else { qDebug()<<"failed"; } } int httpSvr::port() { return PORT; } void httpSvr::readMessage(){ QString readmsg = socket->readAll(); //GET /J%3A%2Fmyclient%2Fmyclient%2FZB%2F2015_10_24_20_18_44%2FGC%2FZBWJ.pdf HTTP/1.1 // 通过URL取文件路径,具体看下面说明 QStringList msgList = readmsg.split('n'); QString getURL = msgList.first().toUpper(); getURL.replace("GET /", ""); getURL.replace(" HTTP/1.1", ""); getURL.replace("r", "").replace("n", ""); getURL.trimmed(); //URL解码 QByteArray ba; QString getPath = ba.fromPercentEncoding(getURL.toUtf8()); QFile f(getPath); if(!f.open(QIODevice::ReadOnly | QIODevice::Unbuffered)) { socket->disconnectFromHost(); return; } QByteArray barr = f.readAll(); f.close(); // 模拟http协议 QString lens(QString::number( barr.length())); socket->write("HTTP/1.1 200 OKrn"); socket->write("Content-Type: application/pdfrn"); socket->write("Accept-Ranges: bytesrn"); QString sLen("Content-Length: "+lens+"rnrn"); socket->write(sLen.toLatin1()); socket->write(barr); socket->flush(); connect(socket, SIGNAL(disconnected()),socket, SLOT(deleteLater())); socket->disconnectFromHost(); } void httpSvr::myConnection() { socket = server->nextPendingConnection(); if (socket) { connect(socket, SIGNAL(disconnected()),socket, SLOT(deleteLater())); connect(socket,SIGNAL(readyRead()),this,SLOT(readMessage())); //有可读的信息,触发读函数槽 } } httpSvr::~httpSvr() { if (socket) socket->close(); }
上面主要看readMessage方法,流程是解析http请求,获取要加载的文件路径,然后读取文件二进制数据,模拟http数据报文,通过socket发出即可。
http服务如何知道读取哪个文件呢?这地方我是通过URL来传递的,将带加载的文件的全路径,通过URL编码后拼接在URL请求后面,httpsvr解析请求,通过解码获取文件路径,再加载即可。
启动服务:
1
2
httpSvr *server; //全局的 server = new httpSvr();
调用方法:
1
2
3
4
QString path = "d:/myclient/myclient/abc.pdf"; QString baPath = path.toUtf8().toPercentEncoding(); QString openUrl = QString("http://127.0.0.1:61301/%1").arg(baPath); myCtrl.OpenUrl(openUrl);// 我的第三方控件调用方法
因为是本机,所以http的地址是127.0.0.1, 后面端口号是服务里面定义的端口号。然后将待加载的文件路径编码后拼接在地址后面。
也可以直接在浏览器里面打开openUrl地址,直接看到效果。
转载于:https://my.oschina.net/u/2492458/blog/524946
最后
以上就是认真香氛最近收集整理的关于QT下用代码在程序内部搭建一个简单的HTTP协议服务器的全部内容,更多相关QT下用代码在程序内部搭建一个简单内容请搜索靠谱客的其他文章。
发表评论 取消回复