QT–TCP网络通讯工具编写记录
文章目录
前言
功能描述:
1、实现服务端创建;
2、实现客户端创建 ;
3、实现服务端与客户端的通讯连接,包括:连接响应,断连响应等;
4、实现服务端一对多客户端,单发送消息,多发消息,循环发消息;
5、实现一键获取本地IP4地址;
演示如下:
一、服务端项目文件:
【1.1】server_tcp.h 服务端声明文件
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTcpServer>
#include <QTcpSocket>
#include <QDateTime>
#include <QListWidgetItem>
#include <thread_1.h>
#include <QtNetwork/QNetworkInterface>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
//server用于监听端口,获取新的tcp连接的描述符
QTcpServer *tcpServer;
QTcpSocket *socket;//TCP通讯的Socket
QList<QTcpSocket*> listClient; //创建一个容器
QString currentDateTimeString;//声明一个字符串变量
QByteArray buffer;
int socket_ret =0;
int all_select_ret = 0;
private:
void startServer(QString &,int port);
MyThread *thread = new MyThread;
private slots:
void initNetwork();
void onNewConnection();
void disconnectinfo();
void onSocketReadyRead();
void getcurrenttime();
void delataitem();
void all_slect();
void send_write(QString &);
void start_send();
private slots:
void on_pushButton_clicked();
void on_pushButton_3_clicked();
void on_pushButton_4_clicked();
void on_pushButton_2_clicked();
void on_listWidget_customContextMenuRequested(const QPoint &pos);
void on_pushButton_clear1_clicked();
void on_pushButton_fa2_clicked();
void on_pushButton_fa1_clicked();
void on_pushButton_stop_clicked();
void on_pushButton_getip_clicked();
void on_pushButton_ontop_clicked();
};
#endif // MAINWINDOW_H
【1.2】thread_1.h 线程处理声明文件
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include "QDebug"
class MyThread : public QThread
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = 0);
void stop();
void sleeptimeset(int);
protected:
void run();
private:
volatile bool stopped;
signals:
void sendinfo(int);
};
#endif // MYTHREAD_H
【1.3】main.cpp 执行源文件
#include "server_tcp.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
【1.4】server_tcp.cpp 服务端逻辑实现源文件
#include "server_tcp.h"
#include "ui_server_tcp.h"
#include "QDebug"
#include <QHostAddress>
#include <QThread>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->setWindowTitle("服务端");
//窗口打开位置设置
this->move(568,250);
this->setWindowIcon(QIcon(":/server.ico"));
initNetwork();
ui->pushButton_2->setDisabled(true);
ui->pushButton_fa1->setDisabled(true); //禁用发送按钮
ui->pushButton_fa2->setDisabled(true);
ui->pushButton_stop->setDisabled(true);
//设置所选项的背景颜色为深绿色
ui->listWidget->setStyleSheet("QListWidget::item:selected{background-color: #009900}");
//连接线程函数
//连接信号和槽函数
connect(thread,SIGNAL(sendinfo(int)), this, SLOT(start_send()));
}
//初始化网络
void MainWindow::initNetwork()
{
tcpServer=new QTcpServer(this);
connect(tcpServer,SIGNAL(newConnection()),this,SLOT(onNewConnection())); //绑定槽函数,当有新的连接请求就会调用该函数
}
//连接按钮点击
void MainWindow::on_pushButton_clicked()
{
//获取地址和端口
QString addres = ui->lineEdit->text();
QString port = ui->comboBox->currentText();
int port_ = port.toInt();
//服务端监听地址
startServer(addres,port_);
}
//服务端启动
void MainWindow::startServer(QString &addres,int port)
{
qDebug() << "=============";
QString ret = ui->pushButton->text();
if (ret == "监听")
{
if (!tcpServer->listen(QHostAddress(addres), port))
{
qDebug() << "Server could not start!";
ui->textBrowser->append(QString("<font color=\"#FF0000\">Server could not start!</font> "));
} else {
qDebug() << "Server started!";
ui->pushButton->setStyleSheet("background-color: green");
ui->pushButton->setText("断连");
}
} else if(ret == "断连")
{
if(socket_ret == 1)
{
for (int h = listClient.count(); h <= listClient.count(); h--)
{
if (h==0)
{
break;
}
int s= listClient.count();
qDebug() << "断连控制:" << s << h;
listClient.at(h-1)->disconnectFromHost();
}
}
tcpServer->close();
qDebug() << "Server close!";
ui->pushButton->setStyleSheet("background-color: ");
ui->pushButton->setText("监听");
}
}
//客户端连接
void MainWindow::onNewConnection()
{
ui->pushButton_2->setDisabled(false);
ui->pushButton_fa1->setDisabled(false);
ui->pushButton_fa2->setDisabled(false);
qDebug() << "客户端连接...";
socket_ret = 1;
socket = tcpServer->nextPendingConnection(); //创建sockit
listClient.append(socket); //将生成的socket添加到容器里
connect(socket, SIGNAL(disconnected()), this,SLOT(disconnectinfo())); //绑定槽函数,当客户端连接断掉后,触发disconnected信号,请求就会调用该函数
connect(socket,SIGNAL(readyRead()),this,SLOT(onSocketReadyRead())); //绑定槽函数,当接收到客户端的信息后,触发readyRead信号,请求就会调用该函数
//发送信息至客户端
socket->write("Hello from TCP Server!");
//获取对方的IP和端口
QString ip = socket->peerAddress().toString();
int port = socket->peerPort(); //该函数返回一个16位整数,表示连接到的远程主机的端口号
QString temp = QString("%1:%2").arg(ip).arg(port);
getcurrenttime();//获取当期时间
ui->textBrowser->append(QString("<font color=\"#0000FF\">%1: </font> "
"<font color=\"#3D9140\">%2====成功连接</font>").arg(currentDateTimeString,temp));
//添加连接至listwidget
ui->listWidget->addItem(temp);
}
//客户端断连后,调用该函数
void MainWindow::disconnectinfo()
{
qDebug() << listClient.count();
//监听是那个客户端断连
QTcpSocket* clientSocket = qobject_cast<QTcpSocket*>(sender());
int port =0;
QString address;
//利用for循环循环列表中的每一个连接进来的客户端,判断是哪一个客户端发的数据
for (int i = 0; i < listClient.count(); i++)
{
socket = listClient.at(i);
if (socket == clientSocket) {
// 找到该客户端,进行处理
address = socket->peerAddress().toString();;
port = socket->peerPort();
qDebug() << "Client " << address << ":" << port << " disconnected.";
break; //结束循环
}
}
QString temp = QString("%1:%2").arg(address).arg(port);
// qDebug() << temp;
getcurrenttime();//获取当期时间
ui->textBrowser->append(QString("<font color=\"#0000FF\">%1:</font> "
"<font color=\"#FF0000\">%2:客户端断连成功!</font>").arg(currentDateTimeString,temp));
qDebug() << "客户端断连!";
for(int i=0; i<ui->listWidget->count(); i++)
{
QListWidgetItem *item = ui->listWidget->item(i); // 获取第i行的项
QString text = item->text(); // 获取第i行的文本
// 处理获取到的数据
if (text == temp)
{
delete ui->listWidget->takeItem(i);
//删除对应的客户端IP
listClient.removeAt(i);
//与客户端断连
socket->close();
if (all_select_ret == 0)
{
//不选择所有项,设置QT ListWidget中的所有项都未选中
ui->listWidget->setCurrentItem(nullptr);
}
}
}
//判断是否还有客户端连接服务端
int connect_count = listClient.count();
if (connect_count == 0)
{
ui->pushButton_fa1->setDisabled(true); //禁用发送按钮
ui->pushButton_fa2->setDisabled(true);
ui->pushButton_2->setDisabled(true);
}
}
//读取数据
void MainWindow::onSocketReadyRead()
{
qDebug() << "读取数据:";
//监听是那个客户端断连
QTcpSocket* clientSocket = qobject_cast<QTcpSocket*>(sender());
//利用for循环循环列表中的每一个连接进来的客户端,判断是哪一个客户端发的数据
for (int i = 0; i < listClient.count(); i++)
{
socket = listClient.at(i);
if (socket == clientSocket)
{
// 获取端口
int ports = socket->peerPort();
// 找到该客户端,进行处理
QByteArray msg = socket->readAll();
QString str = QString::fromUtf8(msg); // 使用UTF-8编码
getcurrenttime();//获取当期时间
ui->textBrowser->append(QString("<font color=\"#0000FF\">%1 </font> "
"服务端《======客户端%2: %3").arg(currentDateTimeString).arg(ports).arg(str));
break; //结束循环
}
}
}
//发送按钮
void MainWindow::on_pushButton_2_clicked()
{
QString info1;
try {
//获取发送数据
QString shuju = ui->textEdit->toPlainText();
//判断数据长度是否大于0
if (shuju.length() > 0)
{
//获取当前选中行
int selectedRow = ui->listWidget->currentRow();
if(selectedRow == -1){
//没有选中任何项
getcurrenttime();//获取当期时间
ui->textBrowser->append(QString("<font color=\"#0000FF\">%1:</font> "
"<font color=\"#FF0000\">没有选中任何客户端</font>").arg(currentDateTimeString));
return;
}else
{
//获取选中多少行
QList<QListWidgetItem*> selectedItems = ui->listWidget->selectedItems();
foreach(QListWidgetItem* item, selectedItems)
{
// 获取当前项目
QString info1 = item->text();
//qDebug() << "获取选中项:" << info1;
//判断当前项目的文本
if (info1 != "")
{
//利用for循环循环列表中的每一个连接进来的客户端,判断是哪一个客户端发的数据
for (int i = 0; i < listClient.count(); i++)
{
socket = listClient.at(i);
// 找到该客户端,进行处理
QString address = socket->peerAddress().toString();;
int port = socket->peerPort();
QString ports = QString::number(port);
QString temp = QString("%1:%2").arg(address).arg(port);
if (temp == info1)
{
//判断连接状态是否正常
if (socket->state()== QAbstractSocket::ConnectedState)
{
//给对方发送数据, 使用套接字是tcpSocket 服务端到客户端
socket->write(shuju.toUtf8().data());//
getcurrenttime();//获取当期时间
ui->textBrowser->append(QString("<font color=\"#0000FF\">%1 服务端=====>>>客户端【%2】: </font> %3").arg(currentDateTimeString,ports,shuju));
}
}
}
} else
{
ui->textBrowser->append(QString("<font color=\"#FF0000\">未选择客户端!</font> "));
return;
}
}
}
} else
{
ui->textBrowser->append(QString("<font color=\"#FF0000\">未填写发送数据!</font> "));
}
}
catch(std::exception& e)
{
// 捕获并处理异常
qDebug() << "Exception caught: " << e.what();
}
}
//发送数据的函数
void MainWindow::send_write(QString &shuju)
{
QString shujus;
//判断数据长度是否大于0
if (shuju.length() > 0)
{
int selectedRow = ui->listWidget->currentRow();
if(selectedRow == -1){
//没有选中任何项
getcurrenttime();//获取当期时间
ui->textBrowser->append(QString("<font color=\"#0000FF\">%1:</font> "
"<font color=\"#FF0000\">没有选中任何客户端</font>").arg(currentDateTimeString));
return;
} else
{
//获取选中多少行
QList<QListWidgetItem*> selectedItems = ui->listWidget->selectedItems();
foreach(QListWidgetItem* item, selectedItems) {
//获取当前项目
QString shujus = item->text();
//qDebug() << "获取选中项:" << shujus;
//判断当前项目的文本
if (shujus.length() > 0)
{
//qDebug() << shujus;
//利用for循环循环列表中的每一个连接进来的客户端,判断是哪一个客户端发的数据
for (int i = 0; i < listClient.count(); i++)
{
socket = listClient.at(i);
// 找到该客户端,进行处理
QString address = socket->peerAddress().toString();;
int port = socket->peerPort();
QString ports = QString::number(port);
QString temp = QString("%1:%2").arg(address).arg(port);
if (temp == shujus)
{
//判断连接状态是否正常
if (socket->state()== QAbstractSocket::ConnectedState)
{
//给对方发送数据, 使用套接字是tcpSocket 服务端到客户端
socket->write(shuju.toUtf8().data());//
getcurrenttime();//获取当期时间
ui->textBrowser->append(QString("<font color=\"#0000FF\">%1 服务端=====>>>客户端【%2】: </font> %3").arg(currentDateTimeString,ports,shuju));
}
}
}
} else
{
ui->textBrowser->append(QString("<font color=\"#FF0000\">未选择客户端!</font> "));
return;
}
}
}
} else
{
ui->textBrowser->append(QString("<font color=\"#FF0000\">未填写发送数据!</font> "));
}
}
//获取当前时间模块
void MainWindow::getcurrenttime()
{
QDateTime currentDateTime = QDateTime::currentDateTime();
currentDateTimeString = currentDateTime.toString("yyyy-MM-dd hh:mm:ss");
// qDebug() << "当前时间:" << currentDateTimeString;
}
MainWindow::~MainWindow()
{
delete ui;
}
//清空按钮1
void MainWindow::on_pushButton_4_clicked()
{
ui->textEdit->clear();
}
//清空按钮2
void MainWindow::on_pushButton_3_clicked()
{
ui->textBrowser->clear();
}
//listWidget中创建右键菜单
void MainWindow::on_listWidget_customContextMenuRequested(const QPoint &pos)
{
QListWidgetItem* curItem = ui->listWidget->itemAt( pos );
if( curItem == NULL )
return;
QMenu *popMenu = new QMenu( this );
QAction *Menu1 = new QAction(tr("删除"), this);
QAction *Menu2 = new QAction(tr("全选"), this);
popMenu->addAction( Menu1 );
popMenu->addAction( Menu2 );
connect( Menu1, SIGNAL(triggered() ), this, SLOT( delataitem()));
connect( Menu2, SIGNAL(triggered() ), this, SLOT( all_slect()));
popMenu->exec( QCursor::pos() );
}
//删除选择客户端
void MainWindow::delataitem()
{
//获取当前项目
QString ip_port = ui->listWidget->currentItem()->text();
qDebug() << ip_port;
//移除当前客户端连接
//利用for循环循环列表中的每一个连接进来的客户端,判断是哪一个客户端发的数据
for (int i = 0; i < listClient.count(); i++)
{
socket = listClient.at(i);
// 找到该客户端,进行处理
QString address = socket->peerAddress().toString();;
int port = socket->peerPort();
QString temp = QString("%1:%2").arg(address).arg(port);
if (temp == ip_port)
{
qDebug() << "Client " << address << ":" << port << " disconnected.";
//删除对应的客户端IP
listClient.removeAt(i);
socket->close();
delete ui->listWidget->takeItem(i);
break; //结束循环
}
}
}
//右键菜单选择所有项目
void MainWindow::all_slect()
{
//选择所有项目
qDebug() << "选择所有项目";
//设置为多选模式
ui->listWidget->setSelectionMode(QAbstractItemView::MultiSelection);
ui->listWidget->selectAll();
all_select_ret = 1;
}
//清空按钮
void MainWindow::on_pushButton_clear1_clicked()
{
ui->lineEdit_fasong1->clear();
}
//循环发送信息按钮
void MainWindow::on_pushButton_fa2_clicked()
{
thread->start();
//启用禁止按钮
ui->pushButton_stop->setDisabled(false);
ui->pushButton_fa2->setDisabled(true);
}
//循环函数
void MainWindow::start_send()
{
qDebug() << "执行...";
QString shujus;
//获取数据
QString shuju = ui->lineEdit_fasong2->text();
if (shuju.length() > 0)
{
int selectedRow = ui->listWidget->currentRow();
if(selectedRow == -1){
//没有选中任何项
getcurrenttime();//获取当期时间
ui->textBrowser->append(QString("<font color=\"#0000FF\">%1:</font> "
"<font color=\"#FF0000\">未连接任何客户端</font>").arg(currentDateTimeString));
on_pushButton_stop_clicked();
return;
}else
{
//获取选中多少行
QList<QListWidgetItem*> selectedItems = ui->listWidget->selectedItems();
foreach(QListWidgetItem* item, selectedItems)
{
// 获取当前项目
QString shujus = item->text();
// qDebug() << "获取选中多少行" << shujus;
//服务端发送数据到客户端
//获取当前项目
if (shujus.length() > 0)
{
//利用for循环循环列表中的每一个连接进来的客户端,判断是哪一个客户端发的数据
for (int i = 0; i < listClient.count(); i++)
{
socket = listClient.at(i);
// 找到该客户端,进行处理
QString address = socket->peerAddress().toString();;
int port = socket->peerPort();
QString ports = QString::number(port);
QString temp = QString("%1:%2").arg(address).arg(port);
if (temp == shujus)
{
//判断连接状态是否正常
if (socket->state()== QAbstractSocket::ConnectedState)
{
//给对方发送数据, 使用套接字是tcpSocket 服务端到客户端
socket->write(shuju.toUtf8().data());//
getcurrenttime();//获取当期时间
ui->textBrowser->append(QString("<font color=\"#0000FF\">%1 服务端=====>>>客户端【%2】: </font> %3").arg(currentDateTimeString,ports,shuju));
}
}
}
} else
{
ui->textBrowser->append(QString("<font color=\"#FF0000\">未选择客户端!</font> "));
on_pushButton_stop_clicked();
return;
}
}
}
} else
{
ui->textBrowser->append(QString("<font color=\"#FF0000\">未填写发送数据!</font> "));
on_pushButton_stop_clicked();
}
}
//发送按钮2
void MainWindow::on_pushButton_fa1_clicked()
{
//获取发送数据
QString shuju = ui->lineEdit_fasong1->text();
send_write(shuju);
}
//停止循环按钮
void MainWindow::on_pushButton_stop_clicked()
{
thread->stop();
ui->pushButton_fa2->setDisabled(false);
ui->pushButton_stop->setDisabled(true);
}
//获取本机IP4地址
void MainWindow::on_pushButton_getip_clicked()
{
getcurrenttime();//获取当期时间
// 获取IP4地址
QList<QHostAddress> list = QNetworkInterface::allAddresses();
foreach (QHostAddress address, list)
{
if (address.protocol() == QAbstractSocket::IPv4Protocol && !address.isLoopback())
{
// qDebug() << "IP Address: " << address.toString();
ui->textBrowser->append(QString("<font color=\"#0000FF\">%1 IP4 Address : </font> %2").arg(currentDateTimeString,address.toString()));
}
}
}
//窗口置顶
void MainWindow::on_pushButton_ontop_clicked()
{
QString shuju = ui->pushButton_ontop->text();
if(shuju == "窗口置顶")
{
this->setWindowFlags(Qt::WindowStaysOnTopHint);
ui->pushButton_ontop->setText("取消置顶");
this->show();
}else if (shuju == "取消置顶")
{
// 获取窗口原有属性
Qt::WindowFlags flags = windowFlags();
// 修改窗口属性,去掉置顶属性
flags &= ~Qt::WindowStaysOnTopHint;
// 更新窗口属性
this->setWindowFlags(flags);
ui->pushButton_ontop->setText("窗口置顶");
this->show();
}
}
【1.5】thread_1.cpp 线程逻辑控制实现源文件
#include "thread_1.h"
int timeset = 1000;
MyThread::MyThread(QObject *parent) :
QThread(parent)
{
stopped = false;
}
void MyThread::run()
{
qDebug() << "线程启动成功======";
stopped = false;
int shuju = 1;
while (!stopped) {
QThread::msleep(timeset); // 休眠1000毫秒,即1秒;
emit sendinfo(shuju);
}
}
void MyThread::stop()
{
stopped = true;
}
void MyThread::sleeptimeset(int value=200)
{
timeset = value;
}
【1.6】server_tcp.ui 服务端UI设计文件
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>705</width>
<height>373</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<widget class="QLineEdit" name="lineEdit">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>115</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>192.168.1.200</string>
</property>
</widget>
</item>
<item row="5" column="3">
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>接收</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="2" column="0">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="2">
<widget class="QPushButton" name="pushButton_3">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<property name="text">
<string>清空</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="3">
<widget class="QTextBrowser" name="textBrowser"/>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="pushButton_ontop">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<property name="text">
<string>窗口置顶</string>
</property>
<property name="checkable">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="minimumSize">
<size>
<width>100</width>
<height>25</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::WinPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<property name="text">
<string><html><head/><body><p align="center">地址:</p></body></html></string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="comboBox">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<item>
<property name="text">
<string>1314</string>
</property>
</item>
<item>
<property name="text">
<string>2000</string>
</property>
</item>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::WinPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<property name="text">
<string><html><head/><body><p align="center">端口:</p></body></html></string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="pushButton">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<property name="text">
<string>监听</string>
</property>
</widget>
</item>
<item row="0" column="3" rowspan="4">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>发送</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="4">
<widget class="QPushButton" name="pushButton_4">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<property name="text">
<string>清空</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="3">
<widget class="QTextEdit" name="textEdit">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>25</height>
</size>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QPushButton" name="pushButton_2">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<property name="text">
<string>发送</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QPushButton" name="pushButton_fa1">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<property name="text">
<string>发送</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="3">
<widget class="QLineEdit" name="lineEdit_fasong1">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QPushButton" name="pushButton_clear1">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<property name="text">
<string>清空</string>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QPushButton" name="pushButton_fa2">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<property name="text">
<string>循环发送</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="3">
<widget class="QLineEdit" name="lineEdit_fasong2">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
</widget>
</item>
<item row="2" column="4">
<widget class="QPushButton" name="pushButton_stop">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<property name="text">
<string>停止</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="3" column="0" rowspan="3" colspan="2">
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>客户端连接</string>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<widget class="QListWidget" name="listWidget">
<property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="2" column="0">
<widget class="QPushButton" name="pushButton_getip">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<property name="text">
<string>获取本地IP</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>705</width>
<height>23</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>
【1.7】img.qrc 窗口图标文件
二、客户端项目文件:
【2.1】client_tcp.h 客户端声明文件
#ifndef CLIENT_TCP_H
#define CLIENT_TCP_H
#include <QWidget>
#include <QTcpSocket>
#include <QDateTime>
namespace Ui {
class client_tcp;
}
class client_tcp : public QWidget
{
Q_OBJECT
public:
explicit client_tcp(QWidget *parent = nullptr);
~client_tcp();
private slots:
void on_pushButton_clicked();
void onConnected();
void onDisconnected();
void readdate();
void on_pushButton_2_clicked();
void getcurrenttime();
void on_pushButton_5_clicked();
void on_pushButton_3_clicked();
void on_pushButton_4_clicked();
void on_pushButton_6_clicked();
private:
Ui::client_tcp *ci;
QTcpSocket *tcpClient;
QString currentDateTimeString;
};
#endif // CLIENT_TCP_H
【2.2】client_tcp.cpp 客户端逻辑控制源文件
#include "client_tcp.h"
#include "ui_client_tcp.h"
#include <QHostAddress>
#include "QDebug"
client_tcp::client_tcp(QWidget *parent) :
QWidget(parent),
ci(new Ui::client_tcp)
{
ci->setupUi(this);
this->setWindowTitle("客户端");
//窗口打开位置设置
this->move(1268,250);
//设置图标
this->setWindowIcon(QIcon(":/client.ico"));
//先禁用发送按钮
ci->pushButton_2->setDisabled(true);
ci->pushButton_3->setDisabled(true);
ci->pushButton_4->setDisabled(true);
}
client_tcp::~client_tcp()
{
delete ci;
}
//点击连接按钮
void client_tcp::on_pushButton_clicked()
{
//获取地址和端口
QString ip = ci->lineEdit->text();
QString port = ci->comboBox->currentText();
int port_ = port.toInt();
QString ret_ = ci->pushButton->text();
if (ret_ == "连接")
{
tcpClient =new QTcpSocket(this); //tcpClient
connect(tcpClient,SIGNAL(connected()),this,SLOT(onConnected())); //当客户端与服务端建立连接关系后,触发该信号
connect(tcpClient,SIGNAL(disconnected()),this,SLOT(onDisconnected())); //当客户端与服务端断连后,触发该信号
connect(tcpClient,SIGNAL(readyRead()),this,SLOT(readdate()));
//客户端连接服务端
tcpClient->connectToHost(QHostAddress(ip),port_);
//判断客户端是否连接成功
if (tcpClient->waitForConnected(100)) {
qDebug() << "Connected to server!";
//设置字体为绿色
getcurrenttime();//获取时间模块
ci->textBrowser->append(QString("<font color=\"#0000FF\">%1:</font>"
"<font color=\"#00FF00\">Connected to server Success!</font>").arg(currentDateTimeString));
ci->pushButton->setText("断开"); //设置按钮文本
ci->pushButton->setStyleSheet("background-color: green");//设置按钮背景颜色
//启用发送按钮
ci->pushButton_2->setDisabled(false);
ci->pushButton_3->setDisabled(false);
ci->pushButton_4->setDisabled(false);
// tcpClient->write("客户端连接成功!"); //发送信息到服务端
} else {
// qDebug() << "Could not connect to server!";
getcurrenttime();//获取时间模块
//设置字体为红色
ci->textBrowser->append(QString("<font color=\"#0000FF\">%1</font>"
"<font color=\"#FF0000\">:Could not connect to serve</font> ").arg(currentDateTimeString));
}
}else if(ret_ == "断开")
{
tcpClient->close();
ci->pushButton->setText("连接");
ci->pushButton->setStyleSheet("background-color: ");
ci->pushButton_2->setDisabled(true);
ci->pushButton_3->setDisabled(true);
ci->pushButton_4->setDisabled(true);
}
}
//连接触发该函数
void client_tcp::onConnected()
{
qDebug() << "***客户端已连接到服务器***";
}
//断连触发该函数
void client_tcp::onDisconnected()
{
qDebug() << "***已断连***";
tcpClient->close();
ci->pushButton->setText("连接");
ci->pushButton->setStyleSheet("background-color: ");
}
//读取服务端发送过来的数据
void client_tcp::readdate()
{
QByteArray msg = tcpClient->readAll();
QString str(msg);
getcurrenttime();//获取时间模块
ci->textBrowser->append(QString("<font color=\"#0000FF\"> %1 </font>"
"客户端《======服务端 %2").arg(currentDateTimeString,msg));
}
//获取当前时间模块
void client_tcp::getcurrenttime()
{
QDateTime currentDateTime = QDateTime::currentDateTime();
currentDateTimeString = currentDateTime.toString("yyyy-MM-dd hh:mm:ss");
// qDebug() << "当前时间:" << currentDateTimeString;
}
//清空按钮
void client_tcp::on_pushButton_5_clicked()
{
ci->textBrowser->clear();
}
//发送按钮1
void client_tcp::on_pushButton_2_clicked()
{
//读取文本框内的数据
QString shuju1 = ci->lineEdit_2->text();
if (shuju1.length()> 0)
{
//判断连接状态是否正常
if (tcpClient->state()== QAbstractSocket::ConnectedState)
{
//给对方发送数据, 使用套接字是tcpSocket 客户端到服务端
tcpClient->write(shuju1.toUtf8().data());//
getcurrenttime();//获取时间模块
ci->textBrowser->append(QString("<font color=\"#0000FF\">%1 客户端=====>>>服务端: </font>"
"%2").arg(currentDateTimeString,shuju1));
}
}
}
//发送按钮2
void client_tcp::on_pushButton_3_clicked()
{
//读取文本框内的数据
QString shuju1 = ci->lineEdit_3->text();
if (shuju1.length()> 0)
{
//判断连接状态是否正常
if (tcpClient->state()== QAbstractSocket::ConnectedState)
{
//给对方发送数据, 使用套接字是tcpSocket 客户端到服务端
tcpClient->write(shuju1.toUtf8().data());//
getcurrenttime();//获取时间模块
ci->textBrowser->append(QString("<font color=\"#0000FF\">%1 客户端=====>>>服务端: </font>"
"%2").arg(currentDateTimeString,shuju1));
}
}
}
//发送按钮3
void client_tcp::on_pushButton_4_clicked()
{
//读取文本框内的数据
QString shuju1 = ci->lineEdit_4->text();
if (shuju1.length()> 0)
{
//判断连接状态是否正常
if (tcpClient->state()== QAbstractSocket::ConnectedState)
{
//给对方发送数据, 使用套接字是tcpSocket 客户端到服务端
tcpClient->write(shuju1.toUtf8().data());//
getcurrenttime();//获取时间模块
ci->textBrowser->append(QString("<font color=\"#0000FF\">%1 客户端=====>>>服务端: </font>"
"%2").arg(currentDateTimeString,shuju1));
}
}
}
//窗口置顶
void client_tcp::on_pushButton_6_clicked()
{
QString shuju = ci->pushButton_6->text();
if(shuju == "窗口置顶")
{
this->setWindowFlags(Qt::WindowStaysOnTopHint);
ci->pushButton_6->setText("取消置顶");
this->show();
}else if (shuju == "取消置顶")
{
// 获取窗口原有属性
Qt::WindowFlags flags = windowFlags();
// 修改窗口属性,去掉置顶属性
flags &= ~Qt::WindowStaysOnTopHint;
// 更新窗口属性
this->setWindowFlags(flags);
ci->pushButton_6->setText("窗口置顶");
this->show();
}
}
【2.2】main.cpp 执行源文件
#include "client_tcp.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
client_tcp w;
w.show();
return a.exec();
}
【2.3】client_tcp.ui 客户端UI设计文件
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>client_tcp</class>
<widget class="QWidget" name="client_tcp">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>602</width>
<height>432</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<widget class="QLineEdit" name="lineEdit">
<property name="minimumSize">
<size>
<width>0</width>
<height>28</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>300</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>192.168.1.200</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QGroupBox" name="groupBox">
<property name="maximumSize">
<size>
<width>400</width>
<height>16777215</height>
</size>
</property>
<property name="title">
<string>发送</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="1">
<widget class="QPushButton" name="pushButton_3">
<property name="minimumSize">
<size>
<width>0</width>
<height>28</height>
</size>
</property>
<property name="text">
<string>发送2</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="pushButton_4">
<property name="minimumSize">
<size>
<width>0</width>
<height>28</height>
</size>
</property>
<property name="text">
<string>发送3</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLineEdit" name="lineEdit_4">
<property name="minimumSize">
<size>
<width>0</width>
<height>28</height>
</size>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="pushButton_2">
<property name="minimumSize">
<size>
<width>0</width>
<height>28</height>
</size>
</property>
<property name="text">
<string>发送1</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLineEdit" name="lineEdit_2">
<property name="minimumSize">
<size>
<width>0</width>
<height>28</height>
</size>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLineEdit" name="lineEdit_3">
<property name="minimumSize">
<size>
<width>0</width>
<height>28</height>
</size>
</property>
</widget>
</item>
<item row="3" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label_2">
<property name="minimumSize">
<size>
<width>0</width>
<height>28</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::WinPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<property name="text">
<string><html><head/><body><p align="center">端口:</p></body></html></string>
</property>
</widget>
</item>
<item row="1" column="2" colspan="3">
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>接收</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="1" column="0">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="pushButton_5">
<property name="minimumSize">
<size>
<width>0</width>
<height>28</height>
</size>
</property>
<property name="text">
<string>清空</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="3">
<widget class="QTextBrowser" name="textBrowser"/>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="pushButton_6">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<property name="text">
<string>窗口置顶</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="4">
<widget class="QPushButton" name="pushButton">
<property name="minimumSize">
<size>
<width>0</width>
<height>28</height>
</size>
</property>
<property name="text">
<string>连接</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="minimumSize">
<size>
<width>0</width>
<height>28</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::WinPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<property name="text">
<string>地址:</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QComboBox" name="comboBox">
<property name="minimumSize">
<size>
<width>0</width>
<height>28</height>
</size>
</property>
<item>
<property name="text">
<string>1314</string>
</property>
</item>
<item>
<property name="text">
<string>2000</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
三、设置项目构建的位置:
四、QT项目不能用于其他电脑的原因:
删除该用户记录文件,其他电脑上的QT都可打开同一个项目;
五、编译程序,使exe执行文件可正常使用:
【5.1】 打开该文件
【5.2】 进入项目构建的文件目录内,输入指令:windeployqt.exe connect_tcp.exe【这是你自己已构建的exe执行程序】
如下图所示:直接运行exe程序,会报错,缺少需要的文件。
输入指令后,会自动生成exe执行所需要的文件
再次点击exe执行文件,软件正常打开使用