QT学习_网络编程_TCP通信聊天
Posted Leslie X徐
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了QT学习_网络编程_TCP通信聊天相关的知识,希望对你有一定的参考价值。
网络编程
TCP通信
1.用到的类
- QTcpServer
公共函数:
void close ()
QString errorString () const
bool isListening () const
bool listen ( const QHostAddress & address = QHostAddress::Any, quint16 port = 0 )
QHostAddress serverAddress () const
quint16 serverPort () const
bool waitForNewConnection ( int msec = 0, bool * timedOut = 0 )
virtual QTcpSocket * nextPendingConnection ()
信号:
void newConnection()
version5:
void acceptError(QAbstractSocket::SocketError socketError)
保护函数:
void addPendingConnection ( QTcpSocket * socket )
virtual void incomingConnection ( int socketDescriptor )
- QAbstractSocket
参数:
enum NetworkLayerProtocol { IPv4Protocol, IPv6Protocol, UnknownNetworkLayerProtocol }
enum SocketError { ConnectionRefusedError, RemoteHostClosedError, HostNotFoundError, SocketAccessError, ..., UnknownSocketError }
enum SocketOption { LowDelayOption, KeepAliveOption, MulticastTtlOption, MulticastLoopbackOption }
enum SocketState { UnconnectedState, HostLookupState, ConnectingState, ConnectedState, ..., ListeningState }
enum SocketType { TcpSocket, UdpSocket, UnknownSocketType }
公共函数:
QAbstractSocket ( SocketType socketType, QObject * parent )
void abort ()
void connectToHost ( const QString & hostName, quint16 port, OpenMode openMode = ReadWrite )
void connectToHost ( const QHostAddress & address, quint16 port, OpenMode openMode = ReadWrite )
void disconnectFromHost ()
bool waitForConnected ( int msecs = 30000 )
bool waitForDisconnected ( int msecs = 30000 )
QHostAddress localAddress () const
quint16 localPort () const
QHostAddress peerAddress () const
QString peerName () const
quint16 peerPort () const
虚函数:
virtual qint64 bytesAvailable () const
virtual qint64 bytesToWrite () const
virtual bool canReadLine () const
信号:
void connected ()
void disconnected ()
void error ( QAbstractSocket::SocketError socketError )
void hostFound ()
void stateChanged ( QAbstractSocket::SocketState socketState )
继承的QIODevice信号:
void readyRead()
界面
服务器端
1.主窗口定义和构造函数
MainWindow.h:
定义私有变量tcpServer建立TCP服务器,定义tcpSocket用于与客户端进行socket连接和通信。
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QLabel>
#include <QTcpServer>
#include <QTcpSocket>
#include <QHostInfo>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
private:
QLabel *LabListen;
QLabel *LabSocketState;
QTcpServer *tcpServer;
QTcpSocket *tcpSocket;
QString getLocalIP();
protected:
void closeEvent(QCloseEvent *event);
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void onNewConnection();//对应QTcpServer的newConnect信号
void onSocketStateChange(QAbstractSocket::SocketState socketState);
void onClientConnected();
void onClientDisconnected();
void onSocketReadyRead();//读取socket传入的数据
void on_actStart_triggered();
void on_actStop_triggered();
void on_actClear_triggered();
void on_actExit_triggered();
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
构造函数:
QString MainWindow::getLocalIP()
{
QString hostName = QHostInfo::localHostName();//得到本地主机名
QHostInfo hostInfo = QHostInfo::fromName(hostName);//根据主机名获得信息
QString localIP = "";
QList<QHostAddress> addList = hostInfo.addresses();//获得信息中的IP地址序列
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;
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//状态栏设置
LabListen = new QLabel("listen state: ");
LabListen->setMinimumWidth(150);
ui->statusBar->addWidget(LabListen);
LabSocketState = new QLabel("socket state: ");
LabSocketState->setMinimumWidth(200);
ui->statusBar->addWidget(LabSocketState);
//标题栏设置
QString localIP = getLocalIP();
this->setWindowTitle(this->windowTitle() + "----localIP: " + localIP);
ui->comboBox->addItem(localIP);
tcpServer = new QTcpServer(this);
connect(tcpServer,SIGNAL(newConnection()),
this,SLOT(onNewConnection()));
}
2.网络监听与socket建立
监听开始和停止:
void MainWindow::on_actStart_triggered()
{
//start listening
QString IP = ui->comboBox->currentText();
qint16 port = ui->spinBox->value();
QHostAddress addr(IP);
tcpServer->listen(addr,port);//监听指定地址和端口
//tcpServer->listen(QHostAddress::Any,port);
ui->plainTextEdit->appendPlainText("**start listening...");
ui->plainTextEdit->appendPlainText("**server Addr: " +
tcpServer->serverAddress().toString());
ui->plainTextEdit->appendPlainText("**server port: " +
QString::number(tcpServer->serverPort()));
ui->actStart->setEnabled(false);
ui->actStop->setEnabled(true);
LabListen->setText("listen state: listening");
}
void MainWindow::on_actStop_triggered()
{//停止监听
if(tcpServer->isListening())
{
tcpServer->close();//停止监听
ui->actStart->setEnabled(true);
ui->actStop->setEnabled(false);
LabListen->setText("Listing state: stop");
}
}
socket建立与连接
void MainWindow::onNewConnection()
{
tcpSocket = tcpServer->nextPendingConnection();
connect(tcpSocket, SIGNAL(connected()),
this, SLOT(onClientConnected()));
connect(tcpSocket,SIGNAL(disconnected()),
this, SLOT(onClientDisconnected()));
connect(tcpSocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),
this, SLOT(onSocketStateChange(QAbstractSocket::SocketState)));
connect(tcpSocket,SIGNAL(readyRead()),
this, SLOT(onSocketReadyRead()));
}
void MainWindow::onSocketStateChange(QAbstractSocket::SocketState socketState)
{//socket状态变化时
switch (socketState) {
case QAbstractSocket::UnconnectedState:
LabSocketState->setText("socket state: UnconnectedState");
break;
case QAbstractSocket::HostLookupState:
LabSocketState->setText("socket state: HostLookupState");
break;
case QAbstractSocket::ConnectingState:
LabSocketState->setText("socket state: ConnectingState");
break;
case QAbstractSocket::BoundState:
LabSocketState->setText("socket state: BoundState");
break;
case QAbstractSocket::ClosingState:
LabSocketState->setText("socket state: ClosingState");
break;
case QAbstractSocket::ListeningState:
LabSocketState->setText("socket state: ListeningState");
break;
case QAbstractSocket::ConnectedState:
LabSocketState->setText("socket state: ConnectedState");
break;
}
}
void MainWindow::onClientConnected()
{//客户接入时
ui->plainTextEdit->appendPlainText("**client socket connected");
ui->plainTextEdit->appendPlainText("**peer address: " +
tcpSocket->peerAddress().toString());
ui->plainTextEdit->appendPlainText("**peer port: " +
QString::number(tcpSocket->peerPort()));
}
void MainWindow::onClientDisconnected()
{//客户断开连接时
ui->plainTextEdit->appendPlainText("**client socket disconnected");
tcpSocket->deleteLater();
}
3.与客户端通信
//读取
void MainWindow::onSocketReadyRead()
{//数据通信
//读取缓冲区行文本
//canReadLine判断是否有新的一行数据需要读取
//再用readLine函数读取一行数据
while(tcpSocket->canReadLine())
ui->plainTextEdit->appendPlainText("[receive] " +
tcpSocket->readLine());
}
//发送
void MainWindow::on_pushButton_clicked()
{//发送一行字符串,以换行符结束
QString msg = ui->lineEdit->text();
ui->plainTextEdit->appendPlainText("[send] "+msg);
ui->lineEdit->clear();
ui->lineEdit->setFocus();//让键盘继续在lineedit框内
QByteArray str = msg.toUtf8();
str.append('\\n');
tcpSocket->write(str);
}
客户端
1.主窗口定义和构造函数
主窗口定义:
客户端只使用一个QTcpSocket对象
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTcpSocket>
#include <QLabel>
#include <QHostInfo>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
private:
QTcpSocket *tcpClient;
QLabel *LabSocketState;
QString getLocalIP();
protected:
void closeEvent(QCloseEvent *event);
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void onConnected();
void onDisconnected();
void onSocketStateChange(QAbstractSocket::SocketState socketState);
void onSocketReadyRead();
void on_actLink_triggered();
void on_actunLink_triggered();
void on_pushButton_clicked();
void on_actQuit_triggered();
void on_actClear_triggered();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
构造函数:
主要功能:创建tcpClient,并建立信号与槽函数的关联
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//设置套接字
tcpClient = new QTcpSocket(this);
//设置状态栏
LabSocketState = new QLabel("socket state:");
LabSocketState->setMinimumWidth(250);
ui->statusBar->addWidget(LabSocketState);
//获得本机地址,设置标题栏
QString localIP = getLocalIP();
this->setWindowTitle(this->windowTitle()+
"localIP: "+localIP);
ui->comboBox->addItem(localIP);
//链接信号
connect(tcpClient, SIGNAL(connected()),
this, SLOT(onConnected()));
connect(tcpClient, SIGNAL(disconnected()),
this, SLOT(onDisconnected()));
connect(tcpClient, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
this, SLOT(onSocketStateChange(QAbstractSocket::SocketState)));
connect(tcpClient, SIGNAL(readyRead()),
this, SLOT(onSocketReadyRead()));
}
2.建立连接
建立连接按钮:
void MainWindow::on_actLink_triggered()
{//连接到服务器
QString addr = ui->comboBox->currentText();
quint16 port = ui->spinBox->value();
tcpClient->connectToHost(addr,port);
}
void MainWindow::on_actunLink_triggered()
{//断开连接
if(tcpClient->state()==QAbstractSocket::ConnectedState)
tcpClient->disconnectFromHost();
}
接受连接信号的槽函数:
void MainWindow::onConnected()
{
ui->plainTextEdit->appendPlainText("**server connected...");
ui->plainTextEdit->appendPlainText("**peer Addr: " +
tcpClient->peerAddress().toString());
ui->plainTextEdit->appendPlainText("**peer port: " +
QString::number(tcpClient->peerPort()));
ui->actLink->setEnabled(false);
ui->actunLink->setEnabled(true);
}
void MainWindow::onDisconnected()
{
ui->plainTextEdit->appendPlainText("**server disconnected");
ui->actLink->setEnabled(true);
ui->actunLink->setEnabled(false);
}
3.与服务器数据收发
采用基于行的数据通信协议
void MainWindow::on_pushButton_clicked()
{
QString msg = ui->lineEdit->text();
ui->plainTextEdit->appendPlainText("[send] "+msg);
ui->lineEdit->clear();
ui->lineEdit->setFocus();//让键盘继续在lineedit框内
QByteArray str = msg.toUtf8();
str.append('\\n');
tcpClient->write(str);
}
void MainWindow::onSocketReadyRead()
{
while(tcpClient->canReadLine())
ui->plainTextEdit->appendPlainText("[receive] " +
tcpClient->readLine());
}
代码总结
服务器和客户端的MainWindow.cpp代码
1.TCP_Server代码
#include "mainwindow.h"
#include "ui_mainwindow.h"
QString MainWindow::getLocalIP()
{
QString hostName = QHostInfo::localHostName();//得到本地主机名
QHostInfo hostInfo = QHostInfo::fromName(hostName);//根据主机名获得信息
QString localIP = "";
QList<QHostAddress> addList = hostInfo.addresses();//获得信息中的IP地址序列
if(!addList.isEmptyQT创建TCP Socket通信