最近要在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.重载的时候一定要正确。
源代码连接:http://download.csdn.net/detail/cmp15845953187/8800409