最近要在QT下开发Tcp通讯,发送序列化数据以便于接收。
这里涉及到几个问题:
1.QTcpSocket、QTcpServer的通讯
2.QDataStream序列化数据
多的不说,直接上干货!!!
客户端:
tcpclient.h
1 #ifndef TCPCLIENT_H 2 #define TCPCLIENT_H 3 4 #include <QMainWindow> 5 #include <qt4/Qt/qtcpsocket.h> 6 #include <Qt/qhostinfo.h> 7 #include <QDataStream> 8 #include <QtNetwork> 9 10 11 12 struct Control_Motor 13 { 14 int length; 15 int command; 16 QString data; 17 }; 18 19 20 class Motor 21 { 22 public: 23 Motor(){} 24 Motor(int speed,int accele_speed,int p_some) 25 { 26 m_speed = speed; 27 m_accele_speed = accele_speed; 28 m_p_some = p_some; 29 } 30 31 32 33 public: 34 int getV(){return m_speed;} 35 int getA(){return m_accele_speed;} 36 int getP(){return m_p_some;} 37 38 void setV(const int v){m_speed = v;} 39 void setA(const int a){m_accele_speed = a;} 40 void setP(const int p){m_p_some = p;} 41 42 43 44 public: 45 //friend QDataStream & operator <<(QDataStream &out,const Motor &motor); 46 //friend QDataStream & operator >>(QDataStream &in,Motor &motor); 47 /* 48 friend QDataStream & operator <<(QDataStream &out,Motor &motor) 49 { 50 out << motor.m_speed<<motor.m_p_some<<motor.m_accele_speed; 51 qDebug()<< motor.m_speed<<motor.m_p_some<<motor.m_accele_speed<<"Enter in this"; 52 return out; 53 } 54 */ 55 public: 56 int m_speed; 57 int m_accele_speed; 58 int m_p_some; 59 60 }; 61 62 63 namespace Ui { 64 class TcpClient; 65 } 66 67 class TcpClient : public QMainWindow 68 { 69 Q_OBJECT 70 71 public: 72 explicit TcpClient(QWidget *parent = 0); 73 ~TcpClient(); 74 75 private: 76 Ui::TcpClient *ui; 77 QTcpSocket *tcpClient; 78 79 80 private slots: 81 void slotConnect(); 82 void readMessage(); 83 void displayError(QAbstractSocket::SocketError); 84 void sendMessage(); 85 86 87 88 public: 89 Control_Motor control_Motor; 90 91 Motor *m_motor; 92 93 }; 94 95 96 #endif // TCPCLIENT_H
tcpclient.cpp
1 #include "tcpclient.h" 2 #include "ui_tcpclient.h" 3 #include <QFile> 4 #include <QDataStream> 5 6 7 QDataStream & operator<<(QDataStream &out,const Motor &motor) 8 { 9 //qDebug()<< motor.m_speed<<motor.m_p_some<<motor.m_accele_speed<<"Enter in"; 10 out << motor.m_speed<<motor.m_p_some<<motor.m_accele_speed; 11 //qDebug()<< motor.m_speed<<motor.m_p_some<<motor.m_accele_speed<<"Enter in this"; 12 return out; 13 } 14 15 QDataStream &operator >>(QDataStream &in,Motor &motor) 16 { 17 int speed = 0; 18 int accele_speed =0; 19 int p_some = 0; 20 21 in >> speed >> p_some >> accele_speed; 22 23 motor.setV(speed); 24 motor.setP(p_some); 25 motor.setA(accele_speed); 26 27 return in; 28 } 29 Q_DECLARE_METATYPE(Motor) 30 31 32 TcpClient::TcpClient(QWidget *parent) : 33 QMainWindow(parent), 34 ui(new Ui::TcpClient) 35 { 36 ui->setupUi(this); 37 38 qRegisterMetaType<Motor>("Motor"); 39 40 tcpClient = new QTcpSocket(this); 41 connect(ui->Connect_Btn,SIGNAL(clicked()),this,SLOT(slotConnect())); 42 connect(ui->Send_Btn,SIGNAL(clicked()),this,SLOT(sendMessage())); 43 connect(tcpClient, SIGNAL(readyRead()), this, SLOT(readMessage())); 44 connect(tcpClient, SIGNAL(error(QAbstractSocket::SocketError)), this, 45 SLOT(displayError(QAbstractSocket::SocketError))); 46 } 47 48 TcpClient::~TcpClient() 49 { 50 delete ui; 51 } 52 53 void TcpClient::slotConnect() 54 { 55 //QString stringAddress = ui->ldt_IP->text(); 56 //QString stringPort = ui->ldt_Port->text(); 57 QString stringAddress = "192.168.154.128"; 58 QString stringPort = "8080"; 59 int port = stringPort.toInt(); 60 QHostAddress address; 61 address.setAddress(stringAddress); 62 tcpClient->abort(); 63 tcpClient->connectToHost(address,port); 64 ui->Connect_Btn->setEnabled(false); 65 } 66 67 void TcpClient::readMessage() 68 { 69 70 } 71 72 void TcpClient::displayError(QAbstractSocket::SocketError) 73 { 74 qDebug() << tcpClient->errorString(); 75 } 76 77 void TcpClient::sendMessage() 78 { 79 QString stringMotor = ui->ldt_Motor->text(); 80 QString stringData = ui->ldt_data->text(); 81 control_Motor.command = stringMotor.toInt(); 82 int dataLength = stringData.length(); 83 control_Motor.length = 8 + dataLength; 84 control_Motor.data = stringData; 85 QString data = stringMotor+stringData; 86 87 m_motor = new Motor(20,40,60); 88 89 //Motor m_motor(20,40,60); 90 91 //用于暂存要发送的数据 92 QByteArray block; 93 //使用数据流写入数据 94 QDataStream out(&block,QIODevice::WriteOnly); 95 //设置数据流的版本,客户端和服务器端使用的版本要相同 96 out.setVersion(QDataStream::Qt_4_6); 97 out<<(quint32) 0; 98 //设置发送长度初始值为0 99 //out << control_Motor.length<<control_Motor.command<<control_Motor.data; 100 101 //qDebug() << control_Motor.length<<control_Motor.command<<control_Motor.data; 102 //out 103 out << control_Motor.command; 104 qDebug()<<"Start out"<<endl; 105 out << *m_motor; 106 qDebug()<<"End out"<<endl; 107 qDebug() << control_Motor.command<< m_motor->getA()<<m_motor->getP()<<m_motor->getV(); 108 //回到字节流起始位置 109 out.device()->seek(0); 110 //重置字节流长度 111 //out << (quint16) (block.size()-sizeof(quint16)); 112 out << (quint32)(block.size()- sizeof(quint32)); 113 qDebug() << "block.size()"<<block.size(); 114 115 //往套接字缓存中写入数据,并发送 116 tcpClient->write(block,block.size()); 117 tcpClient->disconnectFromHost(); 118 tcpClient->waitForDisconnected(); 119 120 block.resize(0); 121 this->close(); 122 //tcpClient->write(data.toLatin1(),data.size()); 123 }
服务器端:
tcpserver.h
1 ifndef TCPSERVER_H 2 #define TCPSERVER_H 3 4 #include <QMainWindow> 5 #include <qt4/Qt/qhostinfo.h> 6 #include "server.h" 7 8 9 namespace Ui { 10 class TcpServer; 11 } 12 13 class TcpServer : public QMainWindow 14 { 15 Q_OBJECT 16 17 public: 18 explicit TcpServer(QWidget *parent = 0); 19 ~TcpServer(); 20 21 private: 22 Ui::TcpServer *ui; 23 int port; 24 Server *server; 25 26 protected slots: 27 void slotCreateServer(); 28 void updateServer(QString,int); 29 30 }; 31 32 #endif // TCPSERVER_H
tcpserver.cpp
1 #include "tcpserver.h" 2 #include "ui_tcpserver.h" 3 #include <QtNetwork/QNetworkInterface> 4 5 TcpServer::TcpServer(QWidget *parent) : 6 QMainWindow(parent), 7 ui(new Ui::TcpServer) 8 { 9 ui->setupUi(this); 10 port = 8080; 11 QString address = QNetworkInterface::allAddresses().first().toString(); 12 QList<QHostAddress> list2 = QNetworkInterface::allAddresses(); 13 foreach (QHostAddress address, list2) 14 { 15 if(address.protocol() == QAbstractSocket::IPv4Protocol) 16 ui->ldt_IP->setText(address.toString()); 17 } 18 ui->ldt_Port->setText(QString::number(port)); 19 connect(ui->Connect_Btn,SIGNAL(clicked()),this,SLOT(slotCreateServer())); 20 } 21 22 TcpServer::~TcpServer() 23 { 24 delete ui; 25 } 26 27 void TcpServer::slotCreateServer() 28 { 29 server = new Server(this,port); 30 connect(server,SIGNAL(updateServer(QString,int)),this,SLOT(updateServer(QString,int))); 31 ui->Connect_Btn->setEnabled(false); 32 } 33 34 void TcpServer::updateServer(QString msg, int length) 35 { 36 ui->lwt_Text->addItem(msg.left(length)); 37 }
server.h
1 #ifndef SERVER_H 2 #define SERVER_H 3 4 #include <qt4/Qt/qtcpserver.h> 5 #include <qt4/Qt/qtcpsocket.h> 6 7 struct Control_Motor 8 { 9 int length; 10 int command; 11 QString data; 12 }; 13 14 15 class Motor 16 { 17 public: 18 Motor(int speed,int accele_speed,int p_some) 19 { 20 m_speed = speed; 21 m_accele_speed = accele_speed; 22 m_p_some = p_some; 23 } 24 25 Motor(){m_speed = 0;} 26 27 28 29 public: 30 int getV(){return m_speed;} 31 int getA(){return m_accele_speed;} 32 int getP(){return m_p_some;} 33 34 void setV(const int v){m_speed = v;} 35 void setA(const int a){m_accele_speed = a;} 36 void setP(const int p){m_p_some = p;} 37 38 39 40 private: 41 int m_speed; 42 int m_accele_speed; 43 int m_p_some; 44 45 }; 46 47 48 49 class Server : public QTcpServer 50 { 51 Q_OBJECT 52 53 public: 54 Server(QObject *parents=0,int port=0); 55 QList<QTcpSocket*>TcpClientSocketList; 56 QTcpSocket *tcpClientSocket; 57 signals: 58 void updateServer(QString,int); 59 60 public slots: 61 void slotUpdateClient(QString,int); 62 void slotDisconnect(int); 63 // void slotnewconnection(); 64 protected: 65 void incomingConnection(int socketDescriptor); 66 67 signals: 68 void updateClients(QString,int); 69 void disconnected(int); 70 71 protected slots: 72 void dataReceive(); 73 void slotDisconnected(); 74 75 public: 76 Control_Motor control_motor; 77 Motor m_mtor; 78 }; 79 80 #endif // SERVER_H
server.cpp
1 #include "server.h" 2 3 QDataStream &operator <<(QDataStream &out,Motor &motor) 4 { 5 out << motor.getV()<<motor.getP()<<motor.getA(); 6 return out; 7 } 8 9 10 QDataStream &operator >>(QDataStream &in,Motor &motor) 11 { 12 int speed = motor.getV(); 13 int accele_speed =motor.getA(); 14 int p_some = motor.getP(); 15 16 in >> speed >> p_some >> accele_speed; 17 18 motor.setV(speed); 19 motor.setP(p_some); 20 motor.setA(accele_speed); 21 22 return in; 23 } 24 25 26 27 28 Server::Server(QObject *parent,int port) : 29 QTcpServer(parent) 30 { 31 this->listen(QHostAddress::Any,port); 32 } 33 34 void Server::incomingConnection(int socketDescriptor) 35 { 36 tcpClientSocket = new QTcpSocket(this); 37 //tcpClientSocket = this->nextPendingConnection(); 38 tcpClientSocket->setSocketDescriptor(socketDescriptor); 39 TcpClientSocketList.append(tcpClientSocket); 40 //connect(this,SIGNAL(updateClients(QString,int)),this,SLOT(slotUpdateClient(QString,int))); 41 //connect(this,SIGNAL(updateClients(QString,int)),this,SLOT(slotUpdateClient(QString,int))); 42 connect(this,SIGNAL(disconnected(int)),this,SLOT(slotDisconnect(int))); 43 connect(tcpClientSocket,SIGNAL(readyRead()),this,SLOT(dataReceive())); 44 connect(tcpClientSocket,SIGNAL(disconnected()),this,SLOT(slotDisconnected())); 45 //connect(tcpClientSocket,SIGNAL(disconnected()),tcpClientSocket,SLOT(deleteLater())); 46 47 } 48 void Server::slotUpdateClient(QString msg,int length) 49 { 50 emit updateServer(msg,length); 51 for (int i=0;i<TcpClientSocketList.count();i++) 52 { 53 QTcpSocket *item=TcpClientSocketList.at(i); 54 if (item->write(msg.toLatin1(),length)!=length) 55 continue; 56 } 57 } 58 void Server::slotDisconnect(int socketDescriptor) 59 { 60 qDebug()<<__FILE__<<__FUNCTION__<<__LINE__<<endl; 61 for (int i=0;i<TcpClientSocketList.count();i++) 62 if (TcpClientSocketList.at(i)->socketDescriptor()==socketDescriptor) 63 { 64 TcpClientSocketList.removeAt(i); 65 return; 66 } 67 } 68 69 void Server::dataReceive() 70 { 71 qDebug()<<"QQWQW11111111111111"; 72 //quint32 size = 0; 73 quint32 nextBlockSize = 0; 74 qDebug()<<"TcpClientSocketList.count()"<<TcpClientSocketList.count(); 75 //for(int i = 0; i < TcpClientSocketList.count();i++) 76 //{ 77 QDataStream in(tcpClientSocket); 78 in.setVersion(QDataStream::Qt_4_6); 79 if(nextBlockSize == 0) 80 { 81 if(tcpClientSocket->bytesAvailable()<sizeof(quint32)) 82 { 83 //break; 84 return; 85 } 86 in>>nextBlockSize; 87 qDebug()<<nextBlockSize; 88 } 89 if(nextBlockSize==0xFFFF) 90 { 91 //break; 92 return; 93 } 94 if(tcpClientSocket->bytesAvailable()<nextBlockSize) 95 { 96 //break; 97 return; 98 } 99 100 //in>>control_motor.length>>control_motor.command>>control_motor.data; 101 102 //qDebug()<<control_motor.length<<control_motor.command<<control_motor.data; 103 in >>control_motor.command >> m_mtor; 104 qDebug()<<control_motor.command<< m_mtor.getA()<<m_mtor.getP()<<m_mtor.getV(); 105 106 //ui->SN_lineEdit_2->setText(QString("%1").arg(message_rev.SN)); 107 //ui->IP_lineEdit->setText(message_rev.IP); 108 //ui->STATE_lineEdit_3->setText(message_rev.Condition); 109 //} 110 } 111 112 void Server::slotDisconnected() 113 { 114 qDebug()<<__FILE__<<__FUNCTION__<<__LINE__<<endl; 115 emit disconnected(tcpClientSocket->socketDescriptor()); 116 }
在这里要特别说明一下,在此遇到的几个问题,希望能帮到大家,也提醒一下自己。
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.重载的时候一定要正确。