TCP/IP通信(即SOCKET通信)是通过网线将服务器Server端和客户机Client端进行连接,在遵循ISO/OSI模型的四层层级构架的基础上通过TCP/IP协议建立的通讯。
以下代码为模拟客户端网络通信,所使用到服务端模拟器(TCP&UDP测试工具)
要实现网络通信,需要用到QTcpServer(监听套接字)和QTcpSocket(通讯套接字),首先在pro文件中添加network模块。
client.pro
#-------------------------------------------------
#
# Project created by QtCreator 2022-08-26T10:44:00
#
#-------------------------------------------------
QT += core gui network
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = Client
TEMPLATE = app
# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
widget.cpp
HEADERS += \
widget.h
FORMS += \
widget.ui
main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QTcpSocket> //qt中的tcp套接字头文件
#include <QThread>
#include <QDebug>
#include <QMessageBox>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private slots:
void on_btnStart_clicked();
void netConnected();
void netDisConnected();
void netError(QAbstractSocket::SocketError sError);
void recvData();
void on_btnSend_clicked();
void on_btnClrSend_clicked();
void on_btnClrRecv_clicked();
void on_btnClrBytes_clicked();
private:
Ui::Widget *ui;
QTcpSocket *socket;
int sendLen = 0;
int recvLen= 0;
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#pragma execution_character_set("utf-8")
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
ui->btnSend->setDisabled(true);
setWindowTitle("客户端");
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_btnStart_clicked()
{
static bool flag = true;
if(flag){
ui->btnStart->setText("正在连接....");
QString ip = ui->edtip->text();
int port = ui->edtport->text().toInt();
if(ip.isEmpty() || ui->edtport->text().isEmpty()){
return;
}
//构造套接字
socket =new QTcpSocket(this);
//关联网络连接成功的信号
connect(socket,&QTcpSocket::connected,this,&Widget::netConnected);
//关联网络断开连接成功的信号
connect(socket,&QTcpSocket::disconnected,this,&Widget::netDisConnected);
//关联网络错误的信号
connect(socket,QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::error),
this,&Widget::netError);
//关联读缓存有数据的信号,当读缓存区有一个字节的数据,
//就立即触发该信号,此时,就调用该槽函数read读数据
connect(socket,&QTcpSocket::readyRead,this,&Widget::recvData);
//连接到服务器
socket->connectToHost(ip,port);
flag = false;
}
else{
flag = true;
socket->disconnectFromHost();
socket->close();
}
}
void Widget::netConnected()
{
ui->btnStart->setText("断开连接");
ui->btnSend->setDisabled(false);
//断开信号与槽的连接
disconnect(socket,&QTcpSocket::connected,this,&Widget::netConnected);
}
void Widget::netDisConnected()
{
ui->btnStart->setText("连接");
ui->btnSend->setDisabled(true);
//断开信号与槽的连接,避免占用信号与槽的队列,提高程序的健壮性
disconnect(socket,&QTcpSocket::disconnected,this,&Widget::netDisConnected);
disconnect(socket, QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::error),
this, &Widget::netError);
disconnect(socket,&QTcpSocket::readyRead,this,&Widget::recvData);
}
void Widget::netError(QAbstractSocket::SocketError sError)
{
QString error;
qDebug() << sError;
switch (sError) {
case QAbstractSocket::ConnectionRefusedError:
error = "ConnectionRefuseError";
break;
case QAbstractSocket::HostNotFoundError:
error = "HostNotFoundError";
default:
break;
}
QMessageBox::critical(this,"错误",error);
}
void Widget::on_btnSend_clicked()
{
QString buf = ui->tdtSend->toPlainText();
sendLen += socket->write(buf.toLatin1());
//number():将int 转换为QString类型
ui->edtSend->setText(QString::number(sendLen));
}
void Widget::on_btnClrSend_clicked()
{
ui->tdtSend->clear();
}
void Widget::on_btnClrRecv_clicked()
{
ui->tdtRecv->clear();
}
void Widget::on_btnClrBytes_clicked()
{
sendLen = 0;
ui->edtSend->setText( QString::number(sendLen) );
recvLen = 0;
ui->edtRecv->setText( QString::number(recvLen) );
}
void Widget::recvData()
{
//bytesAvailable():返回读缓存中的有效字节数
qDebug() <<"bytes: "<< socket->bytesAvailable();
//readAll():读取缓冲区所有可用的数据,用于少量数据传输
// QByteArray buf = socket->readAll();
//read(int):从读缓存区中读取32个字节的数据,常用与大量数据传输,结合bytesAvailable()使用
QByteArray buf = socket->read(32);
if(buf.isEmpty()){
return ;
}
recvLen += buf.length();
ui->edtRecv->setText(QString::number(recvLen));
ui->tdtRecv->append(buf);
}
运行界面