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
