一、演示案例一
本案例中,服务端与客户端对数据的读取都是“行读取”
服务端
第一步:创建一个基于QMainWindow的窗体,类名采用默认值,然后设计窗体

第二步:类的定义
//省略了系统自定义的代码,只列出了自己定义的代码
#include <QTcpServer>
#include <QTcpSocket>
#include <QHostInfo>
class MainWindow : public QMainWindow
{
private:
QLabel *LabListen; //状态栏标签,显示监听状态
QLabel *LabSocketState;//状态栏标签,显示连接状态
QTcpServer *tcpServer; //TCP服务端对象
QTcpSocket *tcpSocket; //TCP通信的Socket
QString getLocalIP(); //获取本机的IP地址
protected:
void closeEvent(QCloseEvent *event);
private slots:
//一系列自定义槽函数
void onNewConnection(); //QTcpServer的newConnection()信号
void onSocketStateChange(QAbstractSocket::SocketState socketState);
void onClientConnected(); //客户端连接
void onClientDisconneced();//客户端断开连接
void onSocketReadyRead(); //读取socket传入的数据
};第三步:构造函数
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//设置spin可以输入的最大值
ui->spinPort->setMaximum(65585);
LabListen=new QLabel(QStringLiteral("监听状态:"));
LabSocketState=new QLabel(QStringLiteral("Socket状态:"));
LabListen->setMinimumWidth(150);
LabSocketState->setMinimumWidth(200);
ui->statusBar->addWidget(LabListen);
ui->statusBar->addWidget(LabSocketState);
//调用自定义函数获取本机IP,并将IP设置为窗体标题和comboBox的项
QString localIP=getLocalIP();
this->setWindowTitle(this->windowTitle()+QStringLiteral("---本机IP:")+localIP);;
ui->comboIP->addItem(localIP);
//创建QTcpServer,并将QTcpServer的newConnection信号与自定义槽函数绑定
tcpServer=new QTcpServer(this);
connect(tcpServer,SIGNAL(newConnection()),this,SLOT(onNewConnection()));第四步:自定义函数getLocalIP的实现
QString MainWindow::getLocalIP()
{
QString hostName=QHostInfo::localHostName(); //获取主机名
QHostInfo hostInfo=QHostInfo::fromName(hostName); //通过主机名获取主机信息
QString localIP="";
QList<QHostAddress> addList=hostInfo.addresses(); //通过主机信息获取主机地址列表
if(!addList.isEmpty())
{
for(int i=0;i<addList.count();i++)
{
QHostAddress aHost=addList.at(i);
if(QAbstractSocket::IPv4Protocol==aHost.protocol())
{
localIP=aHost.toString();
break;
}
}
return localIP;
}
}第五步:开始监听按钮相应函数

void MainWindow::on_actStart_triggered()
{
//获取IP和端口
QString IP=ui->comboIP->currentText();
quint16 port=ui->spinPort->value();
//为服务端提供一个地址和端口,并开始监听
QHostAddress addr(IP);
tcpServer->listen(addr,port);
//设置组件的内容和状态
ui->plainTextEdit->appendPlainText(QStringLiteral("开始监听..."));
ui->plainTextEdit->appendPlainText(QStringLiteral("服务器地址...")+tcpServer->serverAddress().toString());
ui->plainTextEdit->appendPlainText(QStringLiteral("服务器端口...")+QString::number(tcpServer->serverPort()));
ui->actStart->setEnabled(false);
ui->actStop->setEnabled(true);
LabListen->setText(QStringLiteral("监听状态:正在监听..."));
}第六步:实现自定义的onNewConnection槽函数,当有客户端连接进来时执行该槽函数
void MainWindow::onNewConnection()
{
tcpSocket=tcpServer->nextPendingConnection();//获取连接客户端的socket套接字
//客户端socket连接建立时发射connected信号
connect(tcpSocket,SIGNAL(connected()),this,SLOT(onClientConnected()));
onClientConnected();
//客户端socket连接断开时发射disconnected信号
connect(tcpSocket,SIGNAL(disconnected()),this,SLOT(onClientDisconneced()));
//本程序的socket状态变化时发生stateChanged信号
connect(tcpSocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),this,SLOT(onSocketStateChange(QAbstractSocket::SocketState)));
//本程序的socket的读取缓冲区有新数据时发送此信号
connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(onSocketReadyRead()));
}第七步:实现在onNewConnection槽函数中调用的另一些自定义槽函数(onSocketReadyRead在下面介绍)
void MainWindow::onClientConnected()
{
//打印客户端的信息
ui->plainTextEdit->appendPlainText(QStringLiteral("client socket connected"));
ui->plainTextEdit->appendPlainText(QStringLiteral("peer address:")+tcpSocket->peerAddress().toString());
ui->plainTextEdit->appendPlainText(QStringLiteral("peer port:")+QString::number(tcpSocket->peerPort()));
}void MainWindow::onClientDisconneced()
{
//打印信息
ui->plainTextEdit->appendPlainText("client socket disconnected");
//稍后删除本次会话的socket
tcpSocket->deleteLater();
}void MainWindow::onSocketStateChange(QAbstractSocket::SocketState socketState)
{
//socket的各种状态
switch (socketState) {
case QAbstractSocket::UnconnectedState:
LabSocketState->setText(QStringLiteral("socket状态:UnconnectedState"));
break;
case QAbstractSocket::HostLookupState:
LabSocketState->setText(QStringLiteral("socket状态:HostLookupState"));
break;
case QAbstractSocket::ConnectedState:
LabSocketState->setText(QStringLiteral("socket状态:ConnectedState"));
break;
case QAbstractSocket::BoundState:
LabSocketState->setText(QStringLiteral("socket状态:BoundState"));
break;
case QAbstractSocket::ClosingState:
LabSocketState->setText(QStringLiteral("socket状态:ClosingState"));
break;
case QAbstractSocket::ListeningState:
LabSocketState->setText(QStringLiteral("socket状态:ListeningState"));
break;
}
}第八步:停止监听按钮响应函数

void MainWindow::on_actStop_triggered()
{
//如果服务端处于监听状态,断开连接
if(tcpServer->isListening())
{
tcpServer->close();
ui->actStart->setEnabled(true);
ui->actStop->setEnabled(false);
LabListen->setText(QStringLiteral("监听状态:已停止监听"));
}
}第九步:发送消息按钮的相应函数
void MainWindow::on_btnSend_clicked()
{
//获取输入的内容
QString msg=ui->editMsg->text();
ui->plainTextEdit->appendPlainText(QStringLiteral("[out]:")+msg);
ui->editMsg->clear();
ui->editMsg->setFocus();
//将数据转为字节数组,并在结尾加上换行符,然后发送一行数据出去
QByteArray str=msg.toUtf8();
str.append('\n');
tcpSocket->write(str);
}第十步:自定义onSocketReadyRead槽函数的实现(当缓冲区中有数据可以读取时,执行该槽函数)
void MainWindow::onSocketReadyRead()
{
//如果有一行数据可以读取,那么读取一行数据
while(tcpSocket->canReadLine())
{
ui->plainTextEdit->appendPlainText(QStringLiteral("[in]:")+tcpSocket->readLine());
}
}客户端
第一步:创建一个基于QMainWindow的窗体,类名采用默认值,然后设计窗体

第二步:类的定义
////省略了系统自定义的代码,只列出了自己定义的代码
#include <QLabel>
#include <QTcpServer>
#include <QTcpSocket>
#include <QHostInfo>
class MainWindow : public QMainWindow
{
private:
QLabel *LabSocketState;//状态栏标签,显示连接状态
QTcpSocket *tcpClient; //TCP通信的Socket
QString getLocalIP(); //获取本机的IP地址
protected:
void closeEvent(QCloseEvent *event);
private slots:
//一系列自定义槽函数
void onConnection();
void onDisconnection();
void onSocketStateChange(QAbstractSocket::SocketState socketState);
void onSocketReadyRead(); //读取socket传入的数据
};第三步:构造函数
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//设置spin可以输入的最大值
ui->spinPort->setMaximum(65585);
//创建socket对象
tcpClient=new QTcpSocket(this);
LabSocketState=new QLabel(QStringLiteral("Socket状态:"));
LabSocketState->setMinimumWidth(250);
ui->statusBar->addWidget(LabSocketState);
//获取自定义函数获取本机IP,并将IP设置为窗体标题和comboBox的项
QString localIP=getLocalIP();
this->setWindowTitle(this->windowTitle()+QStringLiteral("---本机IP:")+localIP);;
ui->comboIP->addItem(localIP);
//绑定一些列信号与槽
connect(tcpClient,SIGNAL(connected()),this,SLOT(onConnection()));
connect(tcpClient,SIGNAL(disconnected()),this,SLOT(onDisconnection()));
connect(tcpClient,SIGNAL(stateChanged(QAbstractSocket::SocketState)),this,SLOT(onSocketStateChange(QAbstractSocket::SocketState)));
connect(tcpClient,SIGNAL(readyRead()),this,SLOT(onSocketReadyRead()));
}第四步:自定义getLocalIP函数的实现
QString MainWindow::getLocalIP()
{
QString hostName=QHostInfo::localHostName(); //获取主机名
QHostInfo hostInfo=QHostInfo::fromName(hostName); //通过主机名获取主机信息
QString localIP="";
QList<QHostAddress> addList=hostInfo.addresses(); //通过主机信息获取主机地址列表
if(!addList.isEmpty())
{
for(int i=0;i<addList.count();i++)
{
QHostAddress aHost=addList.at(i);
if(QAbstractSocket::IPv4Protocol==aHost.protocol())
{
localIP=aHost.toString();
break;
}
}
return localIP;
}
}第五步:连接到服务器按钮的相应函数
void MainWindow::on_actConnect_triggered()
{
//获取IP和端口,并连接到服务端
QString addr=ui->comboIP->currentText();
quint16 port=ui->spinPort->value();
tcpClient->connectToHost(addr,port);
}第六步:断开连接按钮的相应函数
void MainWindow::on_actDisconnect_triggered()
{
if(tcpClient->state()==QAbstractSocket::ConnectedState)
tcpClient->disconnectFromHost();
}第七步:自定义onConnection、onDisconnection槽函数
void MainWindow::onConnection()
{
//打印信息
ui->plainTextEdit->appendPlainText(QStringLiteral("已连接到服务器"));
ui->plainTextEdit->appendPlainText(QStringLiteral("peer address:")+tcpClient->peerAddress().toString());
ui->plainTextEdit->appendPlainText(QStringLiteral("peer port:")+QString::number(tcpClient->peerPort()));
ui->actConnect->setEnabled(false);
ui->actDisconnect->setEnabled(true);
}void MainWindow::onDisconnection()
{
ui->plainTextEdit->appendPlainText(QStringLiteral("已断开与服务器的连接"));
ui->actConnect->setEnabled(true);
ui->actDisconnect->setEnabled(false);
}第八步:自定义onSocketReadyRead、onSocketStateChange槽函数的实现
void MainWindow::onSocketReadyRead()
{
//如果有一行数据可以读取,就读取
while(tcpClient->canReadLine())
ui->plainTextEdit->appendPlainText(QStringLiteral("[in]:")+tcpClient->readLine());
}void MainWindow::onSocketStateChange(QAbstractSocket::SocketState socketState)
{
//socket的各种状态
switch (socketState) {
case QAbstractSocket::UnconnectedState:
LabSocketState->setText(QStringLiteral("socket状态:UnconnectedState"));
break;
case QAbstractSocket::HostLookupState:
LabSocketState->setText(QStringLiteral("socket状态:HostLookupState"));
break;
case QAbstractSocket::ConnectedState:
LabSocketState->setText(QStringLiteral("socket状态:ConnectedState"));
break;
case QAbstractSocket::BoundState:
LabSocketState->setText(QStringLiteral("socket状态:BoundState"));
break;
case QAbstractSocket::ClosingState:
LabSocketState->setText(QStringLiteral("socket状态:ClosingState"));
break;
case QAbstractSocket::ListeningState:
LabSocketState->setText(QStringLiteral("socket状态:ListeningState"));
break;
}
}第九步:发送信息按钮的响应函数
void MainWindow::on_btnSend_clicked()
{
//获取输入的内容
QString msg=ui->editMsg->text();
ui->plainTextEdit->appendPlainText(QStringLiteral("[out]:")+msg);
ui->editMsg->clear();
ui->editMsg->setFocus();
//将数据转为字节数组,并在结尾加上换行符,然后发送一行数据出去
QByteArray str=msg.toUtf8();
str.append('\n');
tcpClient->write(str);
}演示效果:

二、演示案例二
本案例中,服务端与客户端对数据的读取都是“字节读取”
客户端

//客户端类
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private:
Ui::Widget *ui;
QTcpSocket* clientSocket;
bool isConnect;//一个标志,用于判断是否连接服务器
private slots:
void connectServerSlot();
void isConnectSlot();
void isDisConnectSlot();
void recvDataFromServerSlot();
void sendDataToServerSlot();
};Widget::Widget(QWidget *parent) :
QWidget(parent),isConnect(false),//初始化连接表示为false
ui(new Ui::Widget)
{
ui->setupUi(this);
clientSocket=new QTcpSocket(this);
connect(ui->conServerBtn,SIGNAL(clicked()),this,SLOT(connectServerSlot()));//点击按钮连接/断开服务器
connect(clientSocket,SIGNAL(connected()),this,SLOT(isConnectSlot()));//连接成功后相应
connect(clientSocket,SIGNAL(disconnected()),this,SLOT(isDisConnectSlot()));//如果没有连接相应
connect(ui->sendMsgBtn,SIGNAL(clicked()),this,SLOT(sendDataToServerSlot()));//点击按钮发送消息
}
Widget::~Widget()
{
if(clientSocket->isOpen())
clientSocket->close();//关闭套接字
delete clientSocket;//释放套接字
delete ui;
}
void Widget::connectServerSlot()
{
if(!isConnect)//如果当前未连接
{
QString ServerIp=ui->serverIpLEdit->text();//得到服务器IP
QString Port=ui->portLEdit->text();//得到服务器端口号
clientSocket->connectToHost(QHostAddress(ServerIp),Port.toInt());//通过IP与端口号连接服务器
if(clientSocket->waitForConnected(1000))//如果等待一秒内连接成功
{
QMessageBox::information(this,QStringLiteral("提示"),QStringLiteral("连接服务器成功"));
isConnect=true;
}
else//如果连接超时
{
clientSocket->disconnect();//套接字不连接
QMessageBox::warning(this,QStringLiteral("提示"),QStringLiteral("连接服务器失败"));
}
}
else//如果当前连接
{
clientSocket->close();//关闭套接字
QMessageBox::information(this,QStringLiteral("提示"),QStringLiteral("断开服务器成功"));
isConnect=false;
}
}
void Widget::isDisConnectSlot()
{
ui->conServerBtn->setText(QStringLiteral("连接服务器"));
}
void Widget::isConnectSlot()
{
ui->conServerBtn->setText(QStringLiteral("断开服务器"));
//连接成功后,查看是否有数据发送过来
connect(clientSocket,SIGNAL(readyRead()),this,SLOT(recvDataFromServerSlot()));
}
void Widget::recvDataFromServerSlot()//接受数据
{
QByteArray recvData=clientSocket->readAll();//以字节类型得到数据
ui->recvTBrowser->append(QStringLiteral("服务器:")+QString::fromLocal8Bit(recvData));
ui->recvSizeTBrowser->setText(QString::number(recvData.size()));
}
void Widget::sendDataToServerSlot()//发送数据出去
{
QString sendData=ui->sendTEdit->toPlainText();
if(clientSocket->isOpen())//如果套接字处于打开状态
{
clientSocket->write(sendData.toLocal8Bit());//写数据
ui->recvTBrowser->append(QStringLiteral("客户端:")+sendData);
ui->sendSizeTBrowser->setText(QString::number(sendData.toLocal8Bit().size()));
ui->sendTEdit->clear();
}
}服务端

//服务端类
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private:
Ui::Widget *ui;
QTcpServer* tcpServer;//服务
QTcpSocket* tcpServerSocket;//套接字
private:
void showHostAddress();
private slots:
void listenSlot();
void newConSlot();
void recvDataFromClientSlot();
void sendDataToClientSlot();
};Widget::Widget(QWidget *parent) :
QWidget(parent),ui(new Ui::Widget)
{
ui->setupUi(this);
showHostAddress();//打印主机网络地址和端口
tcpServer=new QTcpServer(this);
connect(ui->listenBtn,SIGNAL(clicked()),this,SLOT(listenSlot())); //点击按钮开启加监听
connect(tcpServer,SIGNAL(newConnection()),this,SLOT(newConSlot()));//如果外界有客户端连接
connect(ui->sendMsgBtn,SIGNAL(clicked()),this,SLOT(sendDataToClientSlot()));//点击按钮发送数据
}
void Widget::showHostAddress()
{
//allAddresses:得到所有网络地址
QList<QHostAddress> addressList=QNetworkInterface::allAddresses();
foreach(QHostAddress address,addressList)//遍历网络地址
{
if(address.isNull())//为空退出
continue;
QAbstractSocket::NetworkLayerProtocol protocol=address.protocol();//得到网络地址类型
if(protocol!=QAbstractSocket::IPv4Protocol)//此处设置为判断是否为IPV4网络地址
continue;
ui->ipComBox->addItem(address.toString());//如果是IPV4,添加进组合框
}
}
void Widget::listenSlot()//监听
{
if(!tcpServer->isListening())//如果不处于监听状态,开启监听
{
//如果监听成功,参数:1.服务器IP地址 2.服务器端口号
if(tcpServer->listen(QHostAddress(ui->ipComBox->currentText()),\
ui->portLEdit->text().toInt()))
{
QMessageBox::information(this,QStringLiteral("提示"),QStringLiteral("启动监听成功"));
ui->listenBtn->setText(QStringLiteral("关闭监听"));
}
else
{
QMessageBox::warning(this,QStringLiteral("提示"),QStringLiteral("启动监听失败"));
}
}
else//如果处于监听状态,关闭监听
{
tcpServer->close();//关闭服务
tcpServerSocket->close();//关闭套接字
ui->clientTBrowser->clear();
ui->recvTBrowser->clear();
ui->recvSizeTBrowser->clear();
ui->sendSizeTBrowser->clear();
ui->listenBtn->setText(QStringLiteral("开启监听"));
}
}
void Widget::newConSlot()
{
tcpServerSocket=tcpServer->nextPendingConnection();//得到传入的客户套接字
QString clientName=tcpServerSocket->peerName();//得到客户端的名称
QHostAddress clientAddress=tcpServerSocket->peerAddress();//得到客户端的网络地址
qint64 clientPort=tcpServerSocket->peerPort();//得到客户端的端口
ui->clientTBrowser->append(QStringLiteral("客户端名:")+clientName+"\n");
ui->clientTBrowser->append(QStringLiteral("客户端IP:")+clientAddress.toString()+"\n");
ui->clientTBrowser->append(QStringLiteral("客户端端口:")+QString::number(clientPort)+"\n");
connect(tcpServerSocket,SIGNAL(readyRead()),this,SLOT(recvDataFromClientSlot()));//等待外界数据传入
}
void Widget::recvDataFromClientSlot()
{
QByteArray recvData=tcpServerSocket->readAll();//读取所有数据
ui->recvTBrowser->append(QStringLiteral("客户端:")+QString::fromLocal8Bit(recvData));
ui->recvSizeTBrowser->setText(QString::number(recvData.size()));
}
void Widget::sendDataToClientSlot()
{
QString sendData=ui->sendTEdit->toPlainText();
tcpServerSocket->write(sendData.toLocal8Bit());//向外发送数据
ui->recvTBrowser->append(QStringLiteral("服务端:")+sendData);
ui->sendSizeTBrowser->setText(QString::number(sendData.toLocal8Bit().size()));
ui->sendTEdit->clear();
}演示效果

————————————————
版权声明:本文为CSDN博主「江南、董少」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:
https://blog.csdn.net/qq_41453285/article/details/100137925


少有人走的路



















