您的位置:首页 > 理论基础 > 计算机网络

基于QTcpSocket和QTcpServer的Tcp通讯以及QDataStream序列化数据

2015-06-12 16:51 741 查看
最近要在QT下开发Tcp通讯,发送序列化数据以便于接收。

这里涉及到几个问题:

1.QTcpSocket、QTcpServer的通讯

2.QDataStream序列化数据

多的不说,直接上干货!!!

客户端:

tcpclient.h

#ifndef TCPCLIENT_H
#define TCPCLIENT_H

#include <QMainWindow>
#include <qt4/Qt/qtcpsocket.h>
#include <Qt/qhostinfo.h>
#include <QDataStream>
#include <QtNetwork>

struct Control_Motor
{
int length;
int command;
QString data;
};

class Motor
{
public:
Motor(){}
Motor(int speed,int accele_speed,int p_some)
{
m_speed = speed;
m_accele_speed = accele_speed;
m_p_some = p_some;
}

public:
int getV(){return m_speed;}
int getA(){return m_accele_speed;}
int getP(){return m_p_some;}

void setV(const int v){m_speed = v;}
void setA(const int a){m_accele_speed = a;}
void setP(const int p){m_p_some = p;}

public:
//friend QDataStream & operator <<(QDataStream &out,const Motor &motor);
//friend QDataStream & operator >>(QDataStream &in,Motor &motor);
/*
friend QDataStream & operator <<(QDataStream &out,Motor &motor)
{
out << motor.m_speed<<motor.m_p_some<<motor.m_accele_speed;
qDebug()<< motor.m_speed<<motor.m_p_some<<motor.m_accele_speed<<"Enter in this";
return out;
}
*/
public:
int m_speed;
int m_accele_speed;
int m_p_some;

};

namespace Ui {
class TcpClient;
}

class TcpClient : public QMainWindow
{
Q_OBJECT

public:
explicit TcpClient(QWidget *parent = 0);
~TcpClient();

private:
Ui::TcpClient *ui;
QTcpSocket *tcpClient;

private slots:
void slotConnect();
void readMessage();
void displayError(QAbstractSocket::SocketError);
void sendMessage();

public:
Control_Motor control_Motor;

Motor *m_motor;

};

#endif // TCPCLIENT_H


tcpclient.cpp

#include "tcpclient.h"
#include "ui_tcpclient.h"
#include <QFile>
#include <QDataStream>

QDataStream & operator<<(QDataStream &out,const Motor &motor)
{
//qDebug()<< motor.m_speed<<motor.m_p_some<<motor.m_accele_speed<<"Enter in";
out << motor.m_speed<<motor.m_p_some<<motor.m_accele_speed;
//qDebug()<< motor.m_speed<<motor.m_p_some<<motor.m_accele_speed<<"Enter in this";
return out;
}

QDataStream &operator >>(QDataStream &in,Motor &motor)
{
int speed = 0;
int accele_speed =0;
int p_some = 0;

in >> speed >> p_some >> accele_speed;

motor.setV(speed);
motor.setP(p_some);
motor.setA(accele_speed);

return in;
}
Q_DECLARE_METATYPE(Motor)

TcpClient::TcpClient(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::TcpClient)
{
ui->setupUi(this);

qRegisterMetaType<Motor>("Motor");

tcpClient = new QTcpSocket(this);
connect(ui->Connect_Btn,SIGNAL(clicked()),this,SLOT(slotConnect()));
connect(ui->Send_Btn,SIGNAL(clicked()),this,SLOT(sendMessage()));
connect(tcpClient, SIGNAL(readyRead()), this, SLOT(readMessage()));
connect(tcpClient, SIGNAL(error(QAbstractSocket::SocketError)), this,
SLOT(displayError(QAbstractSocket::SocketError)));
}

TcpClient::~TcpClient()
{
delete ui;
}

void TcpClient::slotConnect()
{
//QString stringAddress = ui->ldt_IP->text();
//QString stringPort = ui->ldt_Port->text();
QString stringAddress = "192.168.154.128";
QString stringPort = "8080";
int port = stringPort.toInt();
QHostAddress address;
address.setAddress(stringAddress);
tcpClient->abort();
tcpClient->connectToHost(address,port);
ui->Connect_Btn->setEnabled(false);
}

void TcpClient::readMessage()
{

}

void TcpClient::displayError(QAbstractSocket::SocketError)
{
qDebug() << tcpClient->errorString();
}

void TcpClient::sendMessage()
{
QString stringMotor = ui->ldt_Motor->text();
QString stringData = ui->ldt_data->text();
control_Motor.command = stringMotor.toInt();
int dataLength = stringData.length();
control_Motor.length = 8 + dataLength;
control_Motor.data = stringData;
QString data = stringMotor+stringData;

m_motor = new Motor(20,40,60);

//Motor m_motor(20,40,60);

//用于暂存要发送的数据
QByteArray block;
//使用数据流写入数据
QDataStream out(&block,QIODevice::WriteOnly);
//设置数据流的版本,客户端和服务器端使用的版本要相同
out.setVersion(QDataStream::Qt_4_6);
out<<(quint32) 0;
//设置发送长度初始值为0
//out << control_Motor.length<<control_Motor.command<<control_Motor.data;

//qDebug() << control_Motor.length<<control_Motor.command<<control_Motor.data;
//out
out << control_Motor.command;
qDebug()<<"Start out"<<endl;
out << *m_motor;
qDebug()<<"End out"<<endl;
qDebug() << control_Motor.command<< m_motor->getA()<<m_motor->getP()<<m_motor->getV();
//回到字节流起始位置
out.device()->seek(0);
//重置字节流长度
//out << (quint16) (block.size()-sizeof(quint16));
out << (quint32)(block.size()- sizeof(quint32));
qDebug() << "block.size()"<<block.size();

//往套接字缓存中写入数据,并发送
tcpClient->write(block,block.size());
tcpClient->disconnectFromHost();
tcpClient->waitForDisconnected();

block.resize(0);
this->close();
//tcpClient->write(data.toLatin1(),data.size());
}


服务器端:

tcpserver.h

ifndef TCPSERVER_H
#define TCPSERVER_H

#include <QMainWindow>
#include <qt4/Qt/qhostinfo.h>
#include "server.h"

namespace Ui {
class TcpServer;
}

class TcpServer : public QMainWindow
{
Q_OBJECT

public:
explicit TcpServer(QWidget *parent = 0);
~TcpServer();

private:
Ui::TcpServer *ui;
int port;
Server *server;

protected slots:
void slotCreateServer();
void updateServer(QString,int);

};

#endif // TCPSERVER_H


tcpserver.cpp

#include "tcpserver.h"
#include "ui_tcpserver.h"
#include <QtNetwork/QNetworkInterface>

TcpServer::TcpServer(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::TcpServer)
{
ui->setupUi(this);
port = 8080;
QString address = QNetworkInterface::allAddresses().first().toString();
QList<QHostAddress> list2 = QNetworkInterface::allAddresses();
foreach (QHostAddress address, list2)
{
if(address.protocol() == QAbstractSocket::IPv4Protocol)
ui->ldt_IP->setText(address.toString());
}
ui->ldt_Port->setText(QString::number(port));
connect(ui->Connect_Btn,SIGNAL(clicked()),this,SLOT(slotCreateServer()));
}

TcpServer::~TcpServer()
{
delete ui;
}

void TcpServer::slotCreateServer()
{
server = new Server(this,port);
connect(server,SIGNAL(updateServer(QString,int)),this,SLOT(updateServer(QString,int)));
ui->Connect_Btn->setEnabled(false);
}

void TcpServer::updateServer(QString msg, int length)
{
ui->lwt_Text->addItem(msg.left(length));
}


server.h

#ifndef SERVER_H
#define SERVER_H

#include <qt4/Qt/qtcpserver.h>
#include <qt4/Qt/qtcpsocket.h>

struct Control_Motor
{
int length;
int command;
QString data;
};

class Motor
{
public:
Motor(int speed,int accele_speed,int p_some)
{
m_speed = speed;
m_accele_speed = accele_speed;
m_p_some = p_some;
}

Motor(){m_speed = 0;}

public:
int getV(){return m_speed;}
int getA(){return m_accele_speed;}
int getP(){return m_p_some;}

void setV(const int v){m_speed = v;}
void setA(const int a){m_accele_speed = a;}
void setP(const int p){m_p_some = p;}

private:
int m_speed;
int m_accele_speed;
int m_p_some;

};

class Server : public QTcpServer
{
Q_OBJECT

public:
Server(QObject *parents=0,int port=0);
QList<QTcpSocket*>TcpClientSocketList;
QTcpSocket *tcpClientSocket;
signals:
void updateServer(QString,int);

public slots:
void slotUpdateClient(QString,int);
void slotDisconnect(int);
//    void slotnewconnection();
protected:
void incomingConnection(int socketDescriptor);

signals:
void updateClients(QString,int);
void disconnected(int);

protected slots:
void dataReceive();
void slotDisconnected();

public:
Control_Motor control_motor;
Motor m_mtor;
};

#endif // SERVER_H


server.cpp

#include "server.h"

QDataStream &operator <<(QDataStream &out,Motor &motor)
{
out << motor.getV()<<motor.getP()<<motor.getA();
return out;
}

QDataStream &operator >>(QDataStream &in,Motor &motor)
{
int speed = motor.getV();
int accele_speed =motor.getA();
int p_some = motor.getP();

in >> speed >> p_some >> accele_speed;

motor.setV(speed);
motor.setP(p_some);
motor.setA(accele_speed);

return in;
}

Server::Server(QObject *parent,int port) :
QTcpServer(parent)
{
this->listen(QHostAddress::Any,port);
}

void Server::incomingConnection(int socketDescriptor)
{
tcpClientSocket = new QTcpSocket(this);
//tcpClientSocket = this->nextPendingConnection();
tcpClientSocket->setSocketDescriptor(socketDescriptor);
TcpClientSocketList.append(tcpClientSocket);
//connect(this,SIGNAL(updateClients(QString,int)),this,SLOT(slotUpdateClient(QString,int)));
//connect(this,SIGNAL(updateClients(QString,int)),this,SLOT(slotUpdateClient(QString,int)));
connect(this,SIGNAL(disconnected(int)),this,SLOT(slotDisconnect(int)));
connect(tcpClientSocket,SIGNAL(readyRead()),this,SLOT(dataReceive()));
connect(tcpClientSocket,SIGNAL(disconnected()),this,SLOT(slotDisconnected()));
//connect(tcpClientSocket,SIGNAL(disconnected()),tcpClientSocket,SLOT(deleteLater()));

}
void Server::slotUpdateClient(QString msg,int length)
{
emit updateServer(msg,length);
for (int i=0;i<TcpClientSocketList.count();i++)
{
QTcpSocket *item=TcpClientSocketList.at(i);
if (item->write(msg.toLatin1(),length)!=length)
continue;
}
}
void Server::slotDisconnect(int socketDescriptor)
{
qDebug()<<__FILE__<<__FUNCTION__<<__LINE__<<endl;
for (int i=0;i<TcpClientSocketList.count();i++)
if (TcpClientSocketList.at(i)->socketDescriptor()==socketDescriptor)
{
TcpClientSocketList.removeAt(i);
return;
}
}

void Server::dataReceive()
{
qDebug()<<"QQWQW11111111111111";
//quint32 size = 0;
quint32 nextBlockSize = 0;
qDebug()<<"TcpClientSocketList.count()"<<TcpClientSocketList.count();
//for(int i = 0; i < TcpClientSocketList.count();i++)
//{
QDataStream in(tcpClientSocket);
in.setVersion(QDataStream::Qt_4_6);
if(nextBlockSize == 0)
{
if(tcpClientSocket->bytesAvailable()<sizeof(quint32))
{
//break;
return;
}
in>>nextBlockSize;
qDebug()<<nextBlockSize;
}
if(nextBlockSize==0xFFFF)
{
//break;
return;
}
if(tcpClientSocket->bytesAvailable()<nextBlockSize)
{
//break;
return;
}

//in>>control_motor.length>>control_motor.command>>control_motor.data;

//qDebug()<<control_motor.length<<control_motor.command<<control_motor.data;
in >>control_motor.command >> m_mtor;
qDebug()<<control_motor.command<< m_mtor.getA()<<m_mtor.getP()<<m_mtor.getV();

//ui->SN_lineEdit_2->setText(QString("%1").arg(message_rev.SN));
//ui->IP_lineEdit->setText(message_rev.IP);
//ui->STATE_lineEdit_3->setText(message_rev.Condition);
//}
}

void Server::slotDisconnected()
{
qDebug()<<__FILE__<<__FUNCTION__<<__LINE__<<endl;
emit disconnected(tcpClientSocket->socketDescriptor());
}


在这里要特别说明一下,在此遇到的几个问题,希望能帮到大家,也提醒一下自己。

1.在TcpClient.pro,TcpServer.pro里一定要注意加上QT += network,不然编译的时候QNetworkInterface、QHostAddress这些地方会报错误。

2.在QDataStream重载自定义的类的时候,一开始把重载写在.h文件里编译的时候总是报Tcp_DataStream/TcpServer/server.h:49: error: multiple definition of `operator<<(QDataStream&, Motor&)'这个错误,说实话这个问题真的困扰了我很久,然后把重载函数放到.cpp文件里,编译通过,简直是要命

3.QDataStream的nextBlock读取到的长度为发送的数据的长度(而不是整个包的长度out << (quint32)(block.size()- sizeof(quint32));),如果直接写out << (quint32)(block.size()),读的时候数据将会不正常。

4.重载的时候一定要正确。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: