TCP調試工具顧名思義用來調試TCP通信的,網上這樣的工具N多,之前用.NET寫過一個,無奈在XP下還要安裝個.NET框架才能運行,索性這次用QT重寫,發現QT寫TCP通信比.NET還要便捷一些,運行效率貌似要高,還能識別客戶端斷開,這個真神奇,除了斷電之外。
項目名稱:TCP調試工具
開發環境:WIN7+QT4.7+QT CREATOR2.8+MINGW
技術實現:通過QTcpServer和QTcpSocket類,解析協議並作出處理
實現功能:ASCII格式和16進制數據收發,支持多個客戶端收發消息,可以指定客戶端發送消息,動態增加和移除已連接客戶端。
運行截圖:
粗略步驟:
第一步:添加主界面,布局好主界面,並命名好控件,例如服務端的清空按鈕命名為btnClearServer,客戶端的清空按鈕命名為btnClearClient。
第二步:編寫服務端中客戶端通信類,服務端可以接受多個客戶端的連接,這里采用了同步通信機制,先編寫myTcpClient類,封裝了客戶端連接斷開接收數據的操作。具體代碼如下:
myTcpClient.h #ifndef MYTCPCLIENT_H #define MYTCPCLIENT_H #include <QTcpSocket> class myTcpClient : public QTcpSocket { Q_OBJECT public: explicit myTcpClient(QObject *parent = 0,int clientID=0); private: int clientID; signals: void ClientReadData(int clientID,QString IP,int Port,QByteArray data); void ClientDisConnect(int clientID,QString IP,int Port); private slots: void ReadData(); void DisConnect(); public slots: }; #endif // MYTCPCLIENT_H myTcpClient.cpp #include "mytcpclient.h" #include <QHostAddress> #include "myhelper.h" myTcpClient::myTcpClient(QObject *parent,int clientID) : QTcpSocket(parent) { this->clientID=clientID; connect(this,SIGNAL(readyRead()),this,SLOT(ReadData()));//掛接讀取數據信號 connect(this,SIGNAL(disconnected()),this,SLOT(DisConnect()));//關閉連接時,發送斷開連接信號 //如果關閉連接自動刪除,則下次不能再次監聽,奇怪的問題 //connect(this,SIGNAL(disconnected()),this,SLOT(deleteLater()));//關閉連接時,對象自動刪除 } void myTcpClient::ReadData() { myHelper::Sleep(100); //讀取完整一條數據並發送信號 QByteArray data=this->readAll(); emit ClientReadData(this->clientID,this->peerAddress().toString(),this->peerPort(),data); } void myTcpClient::DisConnect() { //斷開連接時,發送斷開信號 emit ClientDisConnect(this->clientID,this->peerAddress().toString(),this->peerPort()); }
一旦客戶端斷開則發送ClientDisConnect信號,參數包含IP地址和端口。
第三步:編寫服務端通信類。
myTcpServer.h #ifndef MYTCPSERVER_H #define MYTCPSERVER_H #include <QTcpServer> #include "mytcpclient.h" class myTcpServer : public QTcpServer { Q_OBJECT public: explicit myTcpServer(QObject *parent = 0); void SendData(int clientID, QByteArray data); void SendDataCurrent(QByteArray data); void SendDataAll(QByteArray data); int ClientCount()const{return clientCount;} void CloseAllClient(); private: QList<myTcpClient *> ClientList; QList<int> ClientID; myTcpClient *CurrentClient; int clientCount; protected: void incomingConnection(int handle); signals: void ClientReadData(int clientID,QString IP,int Port,QByteArray data); void ClientConnect(int clientID,QString IP,int Port); void ClientDisConnect(int clientID,QString IP,int Port); private slots: void DisConnect(int clientID,QString IP,int Port); public slots: }; #endif // MYTCPSERVER_H myTcpServer.cpp #include "mytcpserver.h" #include <QHostAddress> myTcpServer::myTcpServer(QObject *parent) : QTcpServer(parent) { this->clientCount=0; } void myTcpServer::incomingConnection(int handle) { myTcpClient *client=new myTcpClient(this,handle); client->setSocketDescriptor(handle); connect(client,SIGNAL(ClientReadData(int,QString,int,QByteArray)),this,SIGNAL(ClientReadData(int,QString,int,QByteArray))); connect(client,SIGNAL(ClientDisConnect(int,QString,int)),this,SLOT(DisConnect(int,QString,int))); emit ClientConnect(handle, client->peerAddress().toString(),client->peerPort()); ClientList.append(client);//將新的連接添加到客戶端列表 ClientID.append(handle);//將新的連接的ID添加到客戶端ID列表 clientCount++; //存儲當前連接 CurrentClient=client; } void myTcpServer::DisConnect(int clientID,QString IP,int Port) { for (int i=0;i<clientCount;i++) { if (ClientID[i]==clientID) { ClientList.removeAt(i);//從列表中移除該連接 ClientID.removeAt(i); clientCount--; i--;//不然的話,永遠只會移除第一個連接 emit ClientDisConnect(clientID,IP,Port); break; } } } //指定客戶端連接發消息 void myTcpServer::SendData(int clientID, QByteArray data) { for (int i=0;i<clientCount;i++) { if (ClientID[i]==clientID) { ClientList[i]->write(data); break; } } } //對當前連接發送數據 void myTcpServer::SendDataCurrent(QByteArray data) { //如果沒有一個存在的連接,則不處理 if (clientCount<1){return;} CurrentClient->write(data); } //對所有連接發送數據 void myTcpServer::SendDataAll(QByteArray data) { for (int i=0;i<clientCount;i++) { ClientList[i]->write(data); } } void myTcpServer::CloseAllClient() { for (int i=0;i<clientCount;i++) { ClientList[i]->close(); i--;//不然的話,永遠只會斷開第一個連接 } }
這里封裝了指定客戶端發消息,對當前連接發消息,對所有客戶端發消息三種發送消息方法。
最開始的時候發現直接close停止監聽,發現依然可以接收客戶端的消息,原因是還沒有關閉客戶端連接,所以增加了CloseAllClient()方法,用來關閉所有客戶端連接,這樣的話才是徹底的停止監聽。
可執行文件下載地址:http://download.csdn.net/detail/feiyangqingyun/6717009
源碼猛點這里:http://download.csdn.net/detail/feiyangqingyun/6717017