效果圖
1、在項目管理文件(.pro) 裏面添加
QT += network //加入網絡模塊
2、引用頭文件
#include <QTcpServer> //建立Tcp通信應用程序
#include <QTcpSocket> //建立Tcp通信套接字
3、界面設計
3.1 服務器UI
3.1 客戶端UI
4、定義一些Tcp通信用到的類
QTcpServer *server; //Tcp服務器監聽套接字
QTcpSocket *socket; //Tcp服務器通信套接字
QTcpSocket *client; //Tcp客戶端
5、在構造函數裏面,爲指針分配空間,並獲取本地Ip地址
network::network(QWidget *parent) :
QWidget(parent),
ui(new Ui::network)
{
ui->setupUi(this);
server = new QTcpServer(this); //Tcp服務器監聽套接字
socket = new QTcpSocket(this); //Tcp服務器通信套接字
socket = NULL;
client = new QTcpSocket(this); //創建一個客戶端
Get_LocalIp(); //獲取本地IP地址
//未連接時失能 發送 按鈕
ui->TcpServersend_button->setEnabled(false);
ui->tcpclientsend_button->setEnabled(false);
}
6、服務器端的編程
6.1、獲取本地Ip的方法
//獲取本地Ip
void network::Get_LocalIp()
{
QString hostName=QHostInfo::localHostName(); //本地主機名
QHostInfo hostInfo=QHostInfo::fromName(hostName); //本機IP地址
QList<QHostAddress> addList=hostInfo.addresses(); //IP地址列表
for (int i=0;i<addList.count();i++)
{
QHostAddress aHost=addList.at(i); //每一項是一個QHostAddress
if(QAbstractSocket::IPv4Protocol==aHost.protocol())
{
ui->tcplisen_ip->setText(aHost.toString()); //顯示出Ip地址
break;
}
}
}
6.2、端口監聽
void network::on_tcplisten_Button_clicked()
{
if(server->isListening()==true) //若服務器正在監聽
{
if(socket !=NULL) //判斷是否已有客戶端連接
socket->disconnectFromHost(); //斷開與客戶端的連接
server->close(); //關閉服務器
QString str = "停止監聽成功"; //消息框提示信息
ui->TcpServer_receive->append(str);
ui->tcplisten_Button->setText("監聽"); //改變按鈕的提示文字
ui->LisenState->setText("已停止監聽"); //狀態欄改變連接狀態
disconnect(server , &QTcpServer::newConnection , this , &network::deal_NewConnection);
}
else //若服務器未監聽
{
quint16 port=ui->tcplisen_port->text().toInt(); //獲取監聽的端口號
QString ip = ui->tcplisen_ip->text(); //獲取監聽的Ip
server->listen(QHostAddress(ip),port); //監聽 設置的Ip
// server->listen(QHostAddress::Any,port); //監聽 所有的Ip
ui->tcplisten_Button->setText("停止"); //改變按鈕的提示文字
ui->LisenState->setText("正在監聽"); //狀態欄改變連接狀態
//建立連接時會發送 newConnection 信號,關聯對應的處理槽函數
connect(server , &QTcpServer::newConnection , this , &network::deal_NewConnection);
}
}
6.3、有客戶端接入時處理函數
void network::deal_NewConnection()
{
//獲取通信套接字
socket = server->nextPendingConnection();
//獲取對方的IP地址 端口號
QString ip = socket->peerAddress().toString();
quint16 port = socket->peerPort();
//消息框提示連接成功
QString package = QString("[%1:%2] 成功連接").arg(ip).arg(port);
ui->TcpServer_receive->append(package);
ui->SocketState->setText("Connected");
// 關聯接受到客戶端消息時的處理槽函數
connect(socket , &QTcpSocket::readyRead , this , &network::deal_readyRead);
//關聯斷開連接時的處理槽函數
connect(socket , &QTcpSocket::disconnected , this, &network::deal_disconnect);
//使能發送按鈕
ui->TcpServersend_button->setEnabled(true);
}
6.4、讀取客戶端發來的信息
/*
* 若設置爲監聽所有ip 則獲得的 ip 格式爲 "::ffff:xxx.xxx.xxx.xxx"
* 可通過 ip = ip.mid(7); 來截取指定位置字符 ,使得 ip = "xxx.xxx.xxx.xxx"
*
* 若設置爲監聽特定ip 則獲得的 ip 格式爲 "xxx.xxx.xxx.xxx"
*/
void network::deal_readyRead()
{
QString ip = socket->peerAddress().toString(); // 獲取客戶端 IP地址
quint16 port = socket->peerPort(); // 獲取客戶端 端口號
QString data = socket->readAll().data(); // 獲取客戶端 發來的數據
// 數據打包 顯示
data = QString("[%1:%2] \n%3").arg(ip).arg(port).arg(data);
ui->TcpServer_receive->append(data);
}
6.5、客戶端斷開連接處理函數,主要是一些提示信息
void network::deal_disconnect()
{
//消息框提示
QString ip = socket->peerAddress().toString();
quint16 port = socket->peerPort();
QString package = QString("[%1:%2] 已斷開").arg(ip).arg(port);
ui->TcpServer_receive->append(package);
//狀態欄信息更新
ui->SocketState->setText("Disconnected");
ui->TcpServersend_button->setEnabled(false);
socket->close();
}
7、客戶端的編程
7.1、與服務器連接
void network::on_connectserver_Button_clicked()
{
if(client->state()==QAbstractSocket::UnconnectedState) //與服務器未連接
{
QString ip = ui->serverIp_Edit->text(); //獲取要連接的服務器IP
quint16 port = ui->serverport_Edit->text().toInt(); //獲取要連接的服務器端口號
client->connectToHost(QHostAddress(ip),port); //主動和服務器建立連接
if(client->waitForConnected(2000)==true) //等待與服務器建立連接 等待2s
{
QString str="成功和服務器連接";
ui->TcpClient_receive->append(str);
ui->connectState->setText("已連接");
ui->connectserver_Button->setText("斷開");
ui->tcpclientsend_button->setEnabled(true);
connect(client , &QTcpSocket::readyRead, this , &network::deal_ClientRead);
connect(client,&QTcpSocket::disconnected,this,&network::deal_Clientdisconnect); //
}
else //連接失敗
{
QString str="和服務器連接失敗";
ui->TcpClient_receive->append(str);
}
}
else if(client->state()==QAbstractSocket::ConnectedState) //與服務器已連接
{
client->disconnectFromHost(); //主動與服務器斷開連接
}
}
7.2、讀取收到的數據
void network::deal_ClientRead()
{
//獲取接收到的數據
QString data = client->readAll().data();
//獲取IP地址
QString ip = client->peerAddress().toString();
//獲取端口號
quint16 port = client->peerPort();
data = QString("[%1:%2] \n%3").arg(ip).arg(port).arg(data);
ui->TcpClient_receive->append(data);
}
7.3、主動與服務器斷開處理函數
void network::deal_Clientdisconnect()
{
client->close();
QString str="成功和服務器斷開";
ui->TcpClient_receive->append(str);
ui->connectState->setText("已斷開");
ui->connectserver_Button->setText("連接");
ui->tcpclientsend_button->setEnabled(false);
// 斷開信號和槽的關聯
disconnect(client , &QTcpSocket::readyRead, this , &network::deal_ClientRead);
disconnect(client,&QTcpSocket::disconnected,this,&network::deal_Clientdisconnect);
}
7.4、發送數據
void network::on_tcpclientsend_button_clicked()
{
QString data = ui->TcpClient_send->toPlainText(); //獲取發送的內容
client->write(data.toUtf8().data()); // 發送
}
7.5、清除顯示的內容
void network::on_clear_clientReceive_clicked()
{
ui->TcpClient_receive->clear();
}
void network::on_clear_clientSend_clicked()
{
ui->TcpClient_send->clear();
}