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通信

Linux网络编程——TCP和UDP通信

Linux网络学习_网络的基本概念

QT网络编程Tcp下C/S架构的即时通信

阶段1 语言基础+高级_1-3-Java语言高级_07-网络编程_第2节 TCP协议_3_TCP通信的客户端代码实现

开源应用QT—TCP网络上位机的设计