1.共用的结构体inf.h
#ifndef INF_H
#define INF_H
#include <QColor>
#include <QPoint>
struct MoveInf
{
QPoint srcP;
QPoint targetP;
QColor turnSide;
QColor winSide;
bool isOver=true;
QString inf;
MoveInf(){}
MoveInf(QPoint srcP,QPoint targetP,QColor turnSide, QColor winSide,bool isOver,QString inf){
this->srcP=srcP;
this->targetP=targetP;
this->turnSide=turnSide;
this->winSide=winSide;
this->isOver=isOver;
this->inf=inf;
}
};
#endif // INF_H
2.服务器端
2.1服务器端头文件
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include<QtNetwork>
#include<QDebug>
#include"inf.h"
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void errorSlot(QAbstractSocket::SocketError);
void serverReadData();
void on_btnSend_clicked();
void hasNewConn();
private:
Ui::Widget *ui;
QTcpServer *tcpServer=NULL;
QTcpSocket *tcpSocketConn=NULL;
const int DATATYPE_MOVE_INF=0;
int port =12366;
QByteArray outBytes;
qint64 totalBytesSize=0;
qint64 receivedBytesSize=0;
void initServer();
void serverSendData(MoveInf moveInf, int dataType);
};
#endif // WIDGET_H
2.2服务器端cpp文件
#include "widget.h"
#include "ui_widget.h"
#include <QAbstractSocket>
#include<QDebug>
#include <QJsonDocument>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
initServer();
}
Widget::~Widget()
{
delete ui;
if(tcpSocketConn){
tcpSocketConn->close();
delete tcpSocketConn;
}
if(tcpServer){
tcpServer->close(); //因为建在this上,故无需手工delete
}
}
void Widget::initServer()
{
tcpServer=new QTcpServer(this);
connect(tcpServer,SIGNAL(newConnection()),this,SLOT(hasNewConn()));
tcpServer->listen(QHostAddress::Any,port);
}
void Widget::hasNewConn()
{
tcpSocketConn=tcpServer->nextPendingConnection();
connect(tcpSocketConn,SIGNAL(readyRead()),this,SLOT(serverReadData()));
connect(tcpSocketConn,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(errorSlot(QAbstractSocket::SocketError)));
connect(tcpSocketConn,&QTcpSocket::disconnected,[=]{});//客户端断开连接时
}
void Widget::errorSlot(QAbstractSocket::SocketError)
{
qDebug()<<"服务器端错误"<<tcpServer->errorString();
}
void Widget::serverSendData(MoveInf moveInf,int dataType)
{
QDataStream out(&outBytes,QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_5_5);//C/S两端均采用相同版本
//构建和传出Json
QJsonDocument jsonDoc;
QJsonObject moveInfJsonObject;
moveInfJsonObject.insert("srcX",moveInf.srcP.x());
moveInfJsonObject.insert("srcY",moveInf.srcP.y());
moveInfJsonObject.insert("targetX",moveInf.targetP.x());
moveInfJsonObject.insert("targetY",moveInf.targetP.y());
moveInfJsonObject.insert("turnSide",QString::number(moveInf.turnSide.rgb(),16));
moveInfJsonObject.insert("winSide",QString::number(moveInf.winSide.rgb(),16));
moveInfJsonObject.insert("isOver",moveInf.isOver);
moveInfJsonObject.insert("inf",moveInf.inf);
jsonDoc.setObject(moveInfJsonObject);
QByteArray jsonBytes=jsonDoc.toJson();
//out数值总长度,数据类型,具体数据
out<<qint64(0)<<qint64(dataType)<<jsonBytes;
out.device()->seek(0);
out<<qint64(outBytes.size());
tcpSocketConn->write(outBytes);
tcpSocketConn->flush();
outBytes.resize(0);
}
void Widget::serverReadData()
{
QDataStream in(tcpSocketConn);//接收的是二进制数据
in.setVersion(QDataStream::Qt_5_5);//确保C/S版本相同
qint64 dataType=-1;
//如果接收长度小于等于数据包总大小信息+DataType
if(receivedBytesSize<=sizeof(qint64)*2){
//bytesAvailable为已传来但未读取的数据数据
if(tcpSocketConn->bytesAvailable()>=sizeof(qint64)*2){
in>>totalBytesSize>>dataType;//读取方法之一
receivedBytesSize+=sizeof(qint64)*2;
}else{
//返回,等待读完头信息
return;
}
}
//如果未读取的数据大于等于真正数据部分的大小
if(tcpSocketConn->bytesAvailable()>=totalBytesSize-receivedBytesSize){
if(dataType==DATATYPE_MOVE_INF){//如果接收的是DATATYPE_MOVE_INF数的数据
//构建并解析Json
QByteArray jsonBytes;
in>>jsonBytes;
QJsonDocument jsonDoc=QJsonDocument::fromJson(jsonBytes);
if(jsonDoc.isObject()){
QJsonObject jsonObject=jsonDoc.object();
MoveInf moveInf;
moveInf.srcP=QPoint(jsonObject["srcX"].toInt()
,jsonObject["srcY"].toInt());
moveInf.targetP=QPoint(jsonObject["targetX"].toInt()
,jsonObject["targetY"].toInt());
moveInf.turnSide=QColor(jsonObject["turnSide"].toString().toUInt(NULL,16));
moveInf.winSide=QColor(jsonObject["winSide"].toString().toUInt(NULL,16));
moveInf.isOver=jsonObject["isOver"].toBool();
moveInf.inf=jsonObject["inf"].toString();
qDebug()<<moveInf.srcP<<moveInf.targetP<<moveInf.turnSide
<<moveInf.winSide<<moveInf.isOver<<moveInf.inf;
}
}
receivedBytesSize=0;
}
}
void Widget::on_btnSend_clicked()
{
MoveInf moveInf;
moveInf.srcP=QPoint(3,33);
moveInf.targetP=QPoint(88,8);
moveInf.turnSide=Qt::blue;
moveInf.winSide=Qt::green;
moveInf.isOver=!moveInf.isOver;
moveInf.inf="这是服务器发来的信息";
serverSendData(moveInf,DATATYPE_MOVE_INF);
}
3.客户端
3.1客户端头文件
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include<QtNetwork>
#include<QDebug>
#include"inf.h"
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void on_btnConnect_clicked();
void connectSuccess();
void errorSlot(QAbstractSocket::SocketError);
void clientReadData();
void on_btnSend_clicked();
private:
Ui::Widget *ui;
MoveInf inf;
QTcpSocket *tcpClient=NULL;
int port =12366;
const int DATATYPE_MOVE_INF=0;
QByteArray outBytes;
qint64 totalBytesSize=0;
qint64 receivedBytesSize=0;
void initClient();
void clientSendData(MoveInf moveInf, int dataType);
};
#endif // WIDGET_H
3.2客户端cpp文件
#include "widget.h"
#include "ui_widget.h"
#include <QAbstractSocket>
#include<QDebug>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
initClient();
}
Widget::~Widget()
{
delete ui;
if(tcpClient){
tcpClient->close();
delete tcpClient;
}
}
void Widget::initClient()
{
tcpClient=new QTcpSocket(this);
connect(tcpClient,SIGNAL(connected()),this,SLOT(connectSuccess()));
connect(tcpClient,SIGNAL(readyRead()),this,SLOT(clientReadData()));
connect(tcpClient,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(errorSlot(QAbstractSocket::SocketError)));
}
void Widget::on_btnConnect_clicked()
{
tcpClient->connectToHost(QHostAddress::LocalHost,port);
}
void Widget::connectSuccess()
{
qDebug()<<"连接成功";
}
void Widget::errorSlot(QAbstractSocket::SocketError)
{
qDebug()<<"客户端错误"<<tcpClient->errorString();
}
void Widget::clientSendData(MoveInf moveInf,int dataType)
{
QDataStream out(&outBytes,QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_5_5);//C/S两端均采用相同版本
//构建和传出Json
QJsonDocument jsonDoc;
QJsonObject moveInfJsonObject;
moveInfJsonObject.insert("srcX",moveInf.srcP.x());
moveInfJsonObject.insert("srcY",moveInf.srcP.y());
moveInfJsonObject.insert("targetX",moveInf.targetP.x());
moveInfJsonObject.insert("targetY",moveInf.targetP.y());
moveInfJsonObject.insert("turnSide",QString::number(moveInf.turnSide.rgb(),16));
moveInfJsonObject.insert("winSide",QString::number(moveInf.winSide.rgb(),16));
moveInfJsonObject.insert("isOver",moveInf.isOver);
moveInfJsonObject.insert("inf",moveInf.inf);
jsonDoc.setObject(moveInfJsonObject);
QByteArray jsonBytes=jsonDoc.toJson();
//out数值总长度,数据类型,具体数据
out<<qint64(0)<<qint64(dataType)<<jsonBytes;
out.device()->seek(0);
out<<qint64(outBytes.size());
tcpClient->write(outBytes);
tcpClient->flush();
outBytes.resize(0);
}
void Widget::clientReadData()
{
QDataStream in(tcpClient);//接收的是二进制数据
in.setVersion(QDataStream::Qt_5_5);//确保C/S版本相同
qint64 dataType=-1;
//如果接收长度小于等于数据包总大小信息+DataType
if(receivedBytesSize<=sizeof(qint64)*2){
//bytesAvailable为已传来但未读取的数据数据
if(tcpClient->bytesAvailable()>=sizeof(qint64)*2){
in>>totalBytesSize>>dataType;//读取方法之一
receivedBytesSize+=sizeof(qint64)*2;
}else{
//返回,等待读完头信息
return;
}
}
//如果未读取的数据大于等于真正数据部分的大小
if(tcpClient->bytesAvailable()>=totalBytesSize-receivedBytesSize){
if(dataType==DATATYPE_MOVE_INF){//如果接收的是DATATYPE_MOVE_INF数的数据
//构建并解析Json
QByteArray jsonBytes;
in>>jsonBytes;
QJsonDocument jsonDoc=QJsonDocument::fromJson(jsonBytes);
if(jsonDoc.isObject()){
QJsonObject jsonObject=jsonDoc.object();
MoveInf moveInf;
moveInf.srcP=QPoint(jsonObject["srcX"].toInt()
,jsonObject["srcY"].toInt());
moveInf.targetP=QPoint(jsonObject["targetX"].toInt()
,jsonObject["targetY"].toInt());
moveInf.turnSide=QColor(jsonObject["turnSide"].toString().toUInt(NULL,16));
moveInf.winSide=QColor(jsonObject["winSide"].toString().toUInt(NULL,16));
moveInf.isOver=jsonObject["isOver"].toBool();
moveInf.inf=jsonObject["inf"].toString();
qDebug()<<moveInf.srcP<<moveInf.targetP<<moveInf.turnSide
<<moveInf.winSide<<moveInf.isOver<<moveInf.inf;
}
}
receivedBytesSize=0;
}
}
void Widget::on_btnSend_clicked()
{
MoveInf moveInf;
moveInf.srcP=QPoint(3,33);
moveInf.targetP=QPoint(88,8);
moveInf.turnSide=Qt::blue;
moveInf.winSide=Qt::green;
moveInf.isOver=!moveInf.isOver;
moveInf.inf="这是客户端发来的信息";
clientSendData(moveInf,DATATYPE_MOVE_INF);
}