天天看點

Qt實作簡易區域網路通信(一)

開發環境:Windows10

Qt版本:Qt5.11.0

      此區域網路通信使用的是TCP傳輸控制協定,采用用戶端/伺服器模式,即C/S模式,使用QTcpSocket編寫用戶端,QTcpServer編寫伺服器,通過對端口的監聽,一旦發現用戶端的連接配接請求,就會發出相應的信号;用戶端一旦有資料到來也會發出信号,進行接收。

首先,來設計伺服器端,界面設計如下:

Qt實作簡易區域網路通信(一)

由于是和用戶端通信,此界面除了有伺服器的IP和端口外,還有用戶端的IP和端口,實作發送資訊給用戶端。

直接來看代碼,首先在.pro檔案裡添加網絡子產品

QT       += core gui network      

widget.h檔案代碼

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpServer>
#include <QNetworkInterface>
#include <QDebug>
#include <QMessageBox>
#include <QTcpSocket>


namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

private slots:
    void on_But_serve_bound_clicked();
    void on_Btn_socket_send_clicked();

    void oneProcessNewConnection();     //新的連接配接信号函數
    void oneProcessAcceptError(QAbstractSocket::SocketError err);       //錯誤處理函數
    void oneProcessDisconnected();      //用戶端斷開函數
    void oneProcessReadyRead();     //讀取用戶端内容
    void oneProcessConnected();     //用戶端連入函數



private:
    Ui::Widget *ui;
    QTcpServer *myServer;   //定義服務對象
    QList <QTcpSocket *> arrayClient;   //儲存用戶端
    QTcpSocket *client;     //定義用戶端描述符

    void InitServe();   //初始化伺服器函數

};

#endif // WIDGET_H      

widget.cpp檔案代碼

#include "widget.h"
#include "ui_widget.h"

#define MAXNUM 100

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    InitServe();
}

Widget::~Widget()
{
    delete ui;
}

//初始化函數
void Widget::InitServe()
{
    myServer = new QTcpServer(this);    //配置設定空間
}

//綁定槽函數實作
void Widget::on_But_serve_bound_clicked()
{
    //方法一:通過程式周遊網卡IP
    QString myAddr;
//    QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses();       //傳回所有IP位址,然後進行周遊
//    for(int i=0;i<ipAddressesList.length();i++)
//    {
//        QString myAddr;
//        QHostAddress  addr = ipAddressesList.at(i);
//        qDebug() << addr.toString();      //列印傳回資訊
//        if(addr.toString().contains("192."))      //篩選
//        {
//            myAddr = addr.toString();
//            qDebug() <<myAddr;
//            qDebug() << "***************";
//            ui->Edit_serve_IP->setText(myAddr);
//        }
//    }

    //方法二:手動設定IP
    myAddr = ui->Edit_serve_IP->text();     //手動輸入IP到edit框
    QString myPort = ui->Edit_serve_Port->text();       //手動設定端口
    QString msg;
    bool ret = myServer->listen(QHostAddress(myAddr),myPort.toUInt());      //伺服器監聽綁定
    if(!ret)
    {
        msg = "太可惜了,綁定失敗啦!";
    }
    else
    {
        msg = "哈哈哈,綁定成功啦,@OneStar!";
        ui->But_serve_bound->setEnabled(false);
    }
    ui->textEdit_serve->setText(msg);       //将資訊顯示在消息框

    myServer->setMaxPendingConnections(MAXNUM);     //設定監聽數量
    connect(myServer,SIGNAL(newConnection()),this,SLOT(oneProcessNewConnection()));     //建立新的連接配接信号
    connect(myServer,SIGNAL(acceptError(QAbstractSocket::SocketError)),this,SLOT(oneProcessAcceptError(QAbstractSocket::SocketError))); //錯誤處理

}

//建立連接配接信号函數
void Widget::oneProcessNewConnection()
{
    client = myServer->nextPendingConnection();     //用戶端的連接配接,擷取用戶端描述符
    arrayClient.append(client);

    //用戶端斷開
    connect(client,SIGNAL(disconnected()),this,SLOT(oneProcessDisconnected()));
    //讀取用戶端内容
    connect(client,SIGNAL(readyRead()),this,SLOT(oneProcessReadyRead()));
    //用戶端的連入
    connect(client,SIGNAL(connected()),this,SLOT(oneProcessConnected()));

}

//錯誤處理函數
void Widget::oneProcessAcceptError(QAbstractSocket::SocketError err)
{
    qDebug() << err;
}

//用戶端斷開函數
void Widget::oneProcessDisconnected()
{
    QTcpSocket *client = (QTcpSocket *)this->sender();      //強轉TCP類型
    QString msg = QString("用戶端[%1:%2]   退出!").arg(client->peerAddress().toString()).arg(client->peerPort());
    ui->textEdit_serve->append(msg);        //顯示斷開資訊

    //周遊删除對應用戶端
    for(int i=0;i<arrayClient.length();i++)
    {
        if(arrayClient.at(i)->peerAddress() == client->peerAddress())
        {
            if(arrayClient.at(i)->peerPort() == client->peerPort())
            {
                arrayClient.removeAt(i);               
                break;
            }
        }
    }
}

//讀取用戶端内容函數
void Widget::oneProcessReadyRead()
{
    QTcpSocket *client = (QTcpSocket *)this->sender();      //強轉TCP類型
    QString str1 = QString("用戶端[%1:%2] 說:").arg(client->peerAddress().toString()).arg(client->peerPort());
    QString msg;
    QString str2;
    while(!client->atEnd())     //不到末尾是進行讀取内容
    {
        msg.append(QString(client->readAll()));
    }
    str2 = QString("%1%2").arg(str1).arg(msg);
    ui->textEdit_serve->append(str2);       //将讀取用戶端的内容顯示在edit資訊框
}

void Widget::oneProcessConnected()
{
    QTcpSocket *client = (QTcpSocket *)this->sender();
    QString msg = QString("用戶端[%1:%2] 連入!").arg(client->peerAddress().toString()).arg(client->peerPort());
    ui->textEdit_serve->append(msg);
}

//點選槽函數實作,發送資訊給用戶端
void Widget::on_Btn_socket_send_clicked()
{
    QString ip = ui->Edit_socket_IP->text();    //擷取IP
    QString port = ui->Edit_socket_Port->text();    //擷取端口号
    //周遊查找對應的客戶
    for(int i=0;i<arrayClient.length();i++)
    {
        if(arrayClient.at(i)->peerAddress().toString() == ip)
        {
            if(arrayClient.at(i)->peerPort() == port.toUInt())
            {
                QString msg = ui->textEdit_socket->toPlainText();   //擷取發送消息
                arrayClient.at(i)->write(msg.toUtf8());     //将消息發送出去
                ui->textEdit_socket->clear();       //将消息框清空
                break;
            }
        }
    }

}      

總結一下服務端的編寫步驟

1、使用QTcpServer::listen(const ​​QHostAddress​​​ &address = QHostAddress::Any, ​​quint16​​ port = 0)進行監聽綁定;

2、使用newConnection()信号函數建立連接配接,對用戶端進行斷開,讀取内容等一系列操作;

3、編寫發送槽函數,使用arrayClient.at()->write(msg.toUtf8())将消息發送給用戶端。

接下來是用戶端編寫實作:​​Qt實作簡易區域網路通信(二)​​