QT实现客户端服务器HTTP(get请求、post请求)

服务器代码如下:

QtHttpForS.h

#pragma once

#include <QtWidgets/QWidget>
#include "ui_QtHttpForS.h"

QT_BEGIN_NAMESPACE
class QTcpServer;
class QTcpSocket;
QT_END_NAMESPACE

class QtHttpForS : public QWidget
{
    Q_OBJECT

public:
    QtHttpForS(QWidget *parent = Q_NULLPTR);
    ~QtHttpForS();
    int SumNums(QVector<int> nums);

protected slots:
    void newConnectionSlot();
    void errorStringSlot();
    void sendMsg();
private:
    Ui::QtHttpForSClass ui;
    QTcpServer *m_tcpServer;
    QTcpSocket *m_tcpSocket;
    QString m_SocketInfo;
};

QtHttpForS.cpp

#include "QtHttpForS.h"
#include <QTcpServer>
#include <QDebug>
#include <QTcpSocket>
#include <QJsonObject>
#include <QJsonDocument>
#include "QAbstractSocket"
#include "QStringList"

QtHttpForS::QtHttpForS(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);
	m_tcpServer = new QTcpServer(this);
	m_tcpServer->listen(QHostAddress::Any, 8080);
	connect(m_tcpServer, SIGNAL(newConnection()), this, SLOT(newConnectionSlot()));
	connect(m_tcpServer, SIGNAL(acceptError(QAbstractSocket::SocketError)), this, SLOT(errorStringSlot()));
}

QtHttpForS::~QtHttpForS()
{
	m_tcpServer->close();
}

void QtHttpForS::newConnectionSlot()
{
	ui.textEdit->append("newConnectionSlot() called!");
	m_tcpSocket = m_tcpServer->nextPendingConnection();
	connect(m_tcpSocket, SIGNAL(readyRead()), this, SLOT(sendMsg()));
}

void QtHttpForS::errorStringSlot()
{
	ui.textEdit->append(m_tcpServer->errorString());
	//qDebug() << m_tcpServer->errorString();
}

void QtHttpForS::sendMsg()
{
	QByteArray data = m_tcpSocket->readAll();
	QString m_requestInfo = data;
	m_SocketInfo += m_requestInfo;
	if (m_requestInfo.indexOf("=")>0)
	{
		ui.textEdit->append(m_SocketInfo);
		//qDebug() << m_requestInfo;

		QStringList list = m_SocketInfo.split(QRegExp("[\r\n]"), QString::SkipEmptyParts);
		qDebug() << list;
		if (!list.empty())
		{
			QStringList headlist = QString(list[0]).split(QRegExp("[ ]"));
			QString m_requestMethod = headlist[0];
			//ui.textEdit->append(m_requestMethod);
			//qDebug() << m_requestMethod;
			QStringList paramList;
			QString params(headlist[1]);
			if (QString(headlist[1]).size()>1)
			{
				paramList = QString(headlist[1]).split("/");
				params = paramList[1];
			}
			if (m_requestMethod == "GET" && params[0] == '?')
			{
				params = params.mid(1);
				QStringList numsList = params.split('&');
				QVector<int> nums;
				foreach(QString s, numsList) {
					nums.append(s.split('=')[1].toInt());
				};
				qDebug() << nums;
				int sum = SumNums(nums);

				QString contentStr = "<html>"
					"<head>"
					"<title>"
					"Hello"
					"</title>"
					"</head>"
					"<body>"
					"<h1>" + QString::number(sum) +
					"</h1>"
					"</body>"
					"</html>";

				//send msg
				QString str = "HTTP/1.1 200 OK\r\n";
				str.append("Server:nginx\r\n");
				str.append("Content-Type:text/html;charset=UTF-8\r\n");
				str.append("Connection:keep-alive\r\n");
				str.append(QString("Content-Length:%1\r\n\r\n").arg(contentStr.size()));
				str.append(contentStr);
				m_tcpSocket->write(str.toStdString().c_str());
			}

			if (m_requestMethod == "POST")
			{
				if (params[0] == '?')
				{
					params = params.mid(1);
					QStringList numsList = params.split('&');
					QVector<int> nums;
					foreach(QString s, numsList) {
						nums.append(s.split('=')[1].toInt());
					};
					qDebug() << nums;
					int sum = SumNums(nums);
					QJsonObject res;
					res.insert("sum", QJsonValue(sum));
					QJsonDocument documentJson(res);
					QString strJson(documentJson.toJson(QJsonDocument::Compact));

					QByteArray dataArray = documentJson.toJson();
					//send msg
					QString str = "HTTP/1.1 200 OK\r\n";
					str.append("Server:nginx\r\n");
					str.append("Content-Type:application/json;charset=UTF-8\r\n");
					str.append("Connection:keep-alive\r\n");
					str.append(QString("Content-Length:%1\r\n\r\n").arg(strJson.size()));
					str.append(strJson);
					m_tcpSocket->write(str.toStdString().c_str());
				} 
				else
				{
					params = list[list.size()-1];
					QStringList numsList = params.split('&');
					QVector<int> nums;
					foreach(QString s, numsList) {
						nums.append(s.split('=')[1].toInt());
					};
					qDebug() << nums;
					int sum = SumNums(nums);
					QJsonObject res;
					res.insert("sum", QJsonValue(sum));
					QJsonDocument documentJson(res);
					QString strJson(documentJson.toJson(QJsonDocument::Compact));

					QByteArray dataArray = documentJson.toJson();
					//send msg
					QString str = "HTTP/1.1 200 OK\r\n";
					str.append("Server:nginx\r\n");
					str.append("Content-Type:application/json;charset=UTF-8\r\n");
					str.append("Connection:keep-alive\r\n");
					str.append(QString("Content-Length:%1\r\n\r\n").arg(strJson.size()));
					str.append(strJson);
					m_tcpSocket->write(str.toStdString().c_str());
				}
				
			}
		}
		m_SocketInfo = "";
	}




	
}
int QtHttpForS::SumNums(QVector<int> nums)
{
	int res = 0;
	foreach(int num, nums) {
		res += num;
	};
	return res;
}

main.cpp

#include "QtHttpForS.h"
#include <QtWidgets/QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QtHttpForS w;
    w.show();
    return a.exec();
}

QtHttpForS.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>QtHttpForSClass</class>
 <widget class="QWidget" name="QtHttpForSClass">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>600</width>
    <height>400</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>QtHttpForS</string>
  </property>
  <layout class="QGridLayout" name="gridLayout">
   <item row="0" column="0">
    <widget class="QTextEdit" name="textEdit"/>
   </item>
  </layout>
 </widget>
 <layoutdefault spacing="6" margin="11"/>
 <resources>
  <include location="QtHttpForS.qrc"/>
 </resources>
 <connections/>
</ui>

客户端代码:

QtHttpForC.h

#pragma once

#include <QtWidgets/QWidget>
#include "ui_QtHttpForC.h"
#include <QTcpServer>

class QtHttpForC : public QWidget
{
    Q_OBJECT

public:
    QtHttpForC(QWidget *parent = Q_NULLPTR);
	~QtHttpForC();

private slots:
	void on_pushButton_clicked();

private:
	QButtonGroup *m_Buttongroup;
	QTcpSocket *m_Socket;
private:
	Ui::QtHttpForCClass ui;

};

QtHttpForC.cpp

#include "QtHttpForC.h"
#include <QButtonGroup>
#include <QTcpSocket>
#include <QNetworkRequest>
#include <QUrl>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QDebug>
#include <QJsonParseError>
#include <QJsonDocument>
#include <QJsonObject>
#include "QByteArray"

QtHttpForC::QtHttpForC(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);
	m_Buttongroup = new QButtonGroup(this);
	m_Buttongroup->addButton(ui.radioButton, 1);
	m_Buttongroup->addButton(ui.radioButton_2, 2);
	ui.textEdit_addr->setText("127.0.0.1");
	ui.textEdit_port->setText("8080");
	m_Socket = new QTcpSocket();
}

QtHttpForC::~QtHttpForC()
{
	
}

void QtHttpForC::on_pushButton_clicked()
{
	m_Socket->abort();
	qDebug() << "Connetting....";
	QNetworkRequest request;
	QString scheme = "http";
	QString serverAddr = ui.textEdit_addr->toPlainText();
	QString port = ui.textEdit_port->toPlainText();
	QString requestHeader = scheme + QString("://") + serverAddr + QString(":") + port;

	if (m_Buttongroup->checkedId() == 1)
	{
		//获取对应的参数数据
		QByteArray data;
		data.append("a=");
		data.append(ui.textEdit_parm_1->toPlainText().toUtf8());
		data.append("&b=");
		data.append(ui.textEdit_parm_2->toPlainText().toUtf8());

		QNetworkAccessManager manager;
		request.setUrl(QUrl(requestHeader));
		request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json"));

		QNetworkReply *reply = manager.post(request, data);
		QEventLoop eventLoop;
		QObject::connect(reply, SIGNAL(finished()), &eventLoop, SLOT(quit()));
		eventLoop.exec(QEventLoop::ExcludeUserInputEvents);
		//对请求的返回异常进行处理
		QByteArray replyData = reply->readAll();
		if (reply->error() != QNetworkReply::NoError) {
			qDebug() << reply->error();
			delete m_Socket;
		}
		ui.textEdit_res->setText(QString(replyData));
		reply->deleteLater();

	}
	else
	{
		QString fullRequest = requestHeader + QString("/?a=%1&b=%2").arg(ui.textEdit_parm_1->toPlainText().toInt()).arg(ui.textEdit_parm_2->toPlainText().toInt());
		request.setUrl(QUrl(fullRequest));
		QNetworkAccessManager manager;
		QNetworkReply *reply = manager.get(request);
		QEventLoop eventLoop;
		QObject::connect(reply, SIGNAL(finished()), &eventLoop, SLOT(quit()));
		eventLoop.exec(QEventLoop::ExcludeUserInputEvents);
		//对请求的返回异常进行处理
		if (reply->error() != QNetworkReply::NoError) {
			qDebug() << reply->error();
			delete m_Socket;
		}
		QByteArray replyData = reply->readAll();
		ui.textEdit_res->setText(QString(replyData));
		reply->deleteLater();
	}
}

mian.cpp

#include "QtHttpForC.h"
#include <QtWidgets/QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QtHttpForC w;
    w.show();
    return a.exec();
}

QtHttpForC.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>QtHttpForCClass</class>
 <widget class="QWidget" name="QtHttpForCClass">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>600</width>
    <height>400</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>QtHttpForC</string>
  </property>
  <layout class="QGridLayout" name="gridLayout_4">
   <item row="0" column="0">
    <widget class="QWidget" name="widget" native="true">
     <property name="maximumSize">
      <size>
       <width>16777215</width>
       <height>80</height>
      </size>
     </property>
     <layout class="QHBoxLayout" name="horizontalLayout">
      <item>
       <widget class="QWidget" name="widget_4" native="true">
        <layout class="QHBoxLayout" name="horizontalLayout_3">
         <item>
          <widget class="QLabel" name="label_2">
           <property name="text">
            <string>服务器地址:</string>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QTextEdit" name="textEdit_addr">
           <property name="maximumSize">
            <size>
             <width>10000</width>
             <height>30</height>
            </size>
           </property>
          </widget>
         </item>
        </layout>
       </widget>
      </item>
      <item>
       <widget class="QWidget" name="widget_3" native="true">
        <property name="maximumSize">
         <size>
          <width>120</width>
          <height>16777215</height>
         </size>
        </property>
        <layout class="QHBoxLayout" name="horizontalLayout_2">
         <item>
          <widget class="QLabel" name="label">
           <property name="maximumSize">
            <size>
             <width>30</width>
             <height>16777215</height>
            </size>
           </property>
           <property name="text">
            <string>端口:</string>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QTextEdit" name="textEdit_port">
           <property name="maximumSize">
            <size>
             <width>50</width>
             <height>30</height>
            </size>
           </property>
          </widget>
         </item>
        </layout>
       </widget>
      </item>
      <item>
       <widget class="QWidget" name="widget_2" native="true">
        <property name="maximumSize">
         <size>
          <width>80</width>
          <height>16777215</height>
         </size>
        </property>
        <layout class="QVBoxLayout" name="verticalLayout">
         <item>
          <widget class="QRadioButton" name="radioButton">
           <property name="text">
            <string>POST</string>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QRadioButton" name="radioButton_2">
           <property name="text">
            <string>GET</string>
           </property>
          </widget>
         </item>
        </layout>
       </widget>
      </item>
      <item>
       <widget class="QPushButton" name="pushButton">
        <property name="maximumSize">
         <size>
          <width>300</width>
          <height>500</height>
         </size>
        </property>
        <property name="text">
         <string>发送请求</string>
        </property>
        <property name="default">
         <bool>false</bool>
        </property>
       </widget>
      </item>
     </layout>
    </widget>
   </item>
   <item row="1" column="0">
    <widget class="QWidget" name="widget_7" native="true">
     <property name="maximumSize">
      <size>
       <width>16777215</width>
       <height>80</height>
      </size>
     </property>
     <layout class="QGridLayout" name="gridLayout_3">
      <item row="0" column="0">
       <widget class="QWidget" name="widget_5" native="true">
        <property name="maximumSize">
         <size>
          <width>300</width>
          <height>16777215</height>
         </size>
        </property>
        <layout class="QGridLayout" name="gridLayout_2">
         <item row="0" column="0">
          <widget class="QLabel" name="label_3">
           <property name="maximumSize">
            <size>
             <width>50</width>
             <height>16777215</height>
            </size>
           </property>
           <property name="text">
            <string>参数1:</string>
           </property>
          </widget>
         </item>
         <item row="0" column="1">
          <widget class="QTextEdit" name="textEdit_parm_1">
           <property name="maximumSize">
            <size>
             <width>100</width>
             <height>50</height>
            </size>
           </property>
          </widget>
         </item>
        </layout>
       </widget>
      </item>
      <item row="0" column="1">
       <widget class="QWidget" name="widget_6" native="true">
        <property name="maximumSize">
         <size>
          <width>300</width>
          <height>70</height>
         </size>
        </property>
        <layout class="QGridLayout" name="gridLayout">
         <item row="0" column="0">
          <widget class="QLabel" name="label_4">
           <property name="maximumSize">
            <size>
             <width>50</width>
             <height>16777215</height>
            </size>
           </property>
           <property name="text">
            <string>参数2:</string>
           </property>
          </widget>
         </item>
         <item row="0" column="1">
          <widget class="QTextEdit" name="textEdit_parm_2">
           <property name="maximumSize">
            <size>
             <width>100</width>
             <height>50</height>
            </size>
           </property>
          </widget>
         </item>
        </layout>
       </widget>
      </item>
     </layout>
    </widget>
   </item>
   <item row="2" column="0">
    <widget class="QTextEdit" name="textEdit_res"/>
   </item>
  </layout>
 </widget>
 <layoutdefault spacing="6" margin="11"/>
 <resources>
  <include location="QtHttpForC.qrc"/>
 </resources>
 <connections/>
</ui>

程序运行效果:

GET请求:

POST请求:

POST请求使用postman测试:

注意:可以发现,在使用postman进行POST请求发送时,服务器接收到的请求头与QTSocket的POST请求的请求头是不同的,这里的原因目前还没有想到很好的解释。其中QTSocket的请求是将所有的参数组合后放在了请求头的最后,所以程序中在进行POST解析时多了一种情况的解析。

另外服务端在接收请求时,使用readRedy()信号,会出现因为数据大小而导致的粘包,即客户端发送的请求,会触发一次或多次的readRedy()信号,这时就需要考虑判定服务器所接收的rely->readAll()是不是完整的。本例中主要用到的方法是根据info中是否包含”=“来确定的。

TODO:

当然更为健壮的一种方式应该是通过字节数来确定,请求是否完整。

需要考虑的是如何处理多线程,多请求异步发生。

  • 10
    点赞
  • 101
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值