Netcom 実験 - QT は TCP プロトコルに基づいたソケット通信を実装します (ソース コードを含む)

このプロジェクトは学部のコースワークであり、参照のみを目的としています。ご質問やご提案がある場合は、著者にご連絡ください。


序文

TCP连接:Socket套接字基础知识

TCP (Transmission Control Protocol 伝送制御プロトコル) は、接続を最も基本的な抽象概念とみなしますTCP の多くの特性は、TCP が接続指向であるという基本特性に関連しています。したがって、TCP 接続についてより明確に理解する必要があります。
すべての TCP 接続には 2 つのエンドポイントがあります。

では、TCP 接続のエンドポイントは何でしょうか?


1. TCP 接続のエンドポイント

TCP 接続のエンドポイントは、ホストの IP アドレス、アプリケーション プロセス、トランスポート層のプロトコル ポートではありません。
TCP は 2 つの端末間の通信を実装するため、ターゲット ホストの IP アドレスの取得に加えて、ターゲット ホストの対応するアプリケーション プロセスのポート番号も必要となるため、TCP 接続のエンドポイントはソケットまたはソケットと呼ば
ますによるとRFC 793定義:ポート番号は IP アドレスに結合されてソケットを形成する
ため、TCP は Socket ソケットをエンドポイントとして使用します。

套接字socket = (IP地址:端口号)

各 TCP 接続は、通信の両端の 2 つのエンドポイント (つまり、ソケット ペア) によって一意に決定されます。たった今:

TCP连接:: = { socket1,socket2 } = { (IP1, Port1), (IP2, Port2) }

ここで、IP1 と IP2 はそれぞれ 2 つのエンドポイント ホストのIP アドレスであり、Port1 と Port はそれぞれ 2 つのエンドポイント ホストのポート番号です。

1 つの理解は、ソケットはこのモードの実装であるということです。つまり、ソケットは特別なファイルであり、一部のソケット関数はそのファイルに対する操作 (読み取り/書き込み IO、オープン、クローズ) です。
ソケット抽象化層

TCP/IP およびソケットの詳細な参考資料


2. コード分析

コード構造

ここに画像の説明を挿入

(1) ヘッダファイル

1.client.h

主にいくつかのライブラリをインクルードし、いくつかの関数を定義し、ソケット オブジェクトを作成します。
コードは次のとおりです。

#ifndef CLIENT_H
#define CLIENT_H

#include <QMainWindow>
#include <QTcpSocket>
#include <QKeyEvent>
#include <QWidget>

namespace Ui {
    
    
class Client;
}

class Client : public QMainWindow
{
    
    
    Q_OBJECT

public:
    explicit Client(QWidget *parent = nullptr);
    ~Client();

private slots:
    void on_connect_button_clicked(bool checked);

    void on_send_button_clicked();

    void readyRead_SLOT();

    void connected_SLOT();

private:
    Ui::Client *ui;
    QTcpSocket *socket;
};

#endif // CLIENT_H

2.server.h

コードは以下のように表示されます:

#ifndef SERVER_H
#define SERVER_H

#include <QMainWindow>
#include <QTcpServer>
#include <QTcpSocket>
#include <QString>

QT_BEGIN_NAMESPACE
namespace Ui {
    
     class Server; }
QT_END_NAMESPACE

class Server : public QMainWindow
{
    
    
    Q_OBJECT

public:
    Server(QWidget *parent = nullptr);
    ~Server();

private slots:
    void on_send_button_clicked();

    void on_startorstop_Listen_clicked(bool checked);

    void readyRead_SLOT();

    void newConnection_SLOT();

private:
    Ui::Server *ui;
    QTcpSocket *socket;
    QTcpServer *server;
};
#endif // SERVER_H

(2) ソースファイル

1、クライアント.cpp

主にいくつかのライブラリを組み込み、いくつかの関数を定義し、ソケットとサーバーオブジェクトを作成します

#include "client.h"
#include "ui_client.h"
#include "stdio.h"

#include "QString"

Client::Client(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::Client)
{
    
    
    ui->setupUi(this);
    //设置clicked(bool checked)点击反转状态打开
    ui->connect_button->setCheckable(true);

    socket = new QTcpSocket();

    //信号:客户端申请连接成功 槽函数:允许写入数据
    connect(socket,SIGNAL(connected()),this,SLOT(connected_SLOT()));
}

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

//信号:客户端申请连接成功 槽函数:允许写入数据
void Client::connected_SLOT()
{
    
    
    connect(socket,SIGNAL(readyRead()),this,SLOT(readyRead_SLOT()));//如果socket中有缓存消息,触发槽函数
}

//接收消息并显示到接收框
void Client::readyRead_SLOT()
{
    
    
    qDebug() << "Client Received!";
    QString buffer;
    //读取缓冲区数据
    buffer = socket->readAll();
    if(!buffer.isEmpty())
    {
    
    
        //刷新显示
        ui->receiver->appendPlainText(buffer);
    }
}

//连接和断开按键
void Client::on_connect_button_clicked(bool checked)
{
    
    
    if(checked)
    {
    
    
        QString IP = ui->ipnum->text();
        int Port = ui->portnum->text().toUInt();
        //取消已有的连接
        socket->abort();
        //连接服务器
        socket->connectToHost(IP,Port);
        //如果等待超过1000ms
        if(!socket->waitForConnected(1000))
        {
    
    
            qDebug() << "Connect failed, please try again later!";
            //连接失败,再次点击则重新连接,将checked恢复为true
            ui->connect_button->toggle();
            return;
        }
        qDebug() << "Connect Successfully! Connect with IP:" << IP << "; port:" << Port;
        //修改按键文字
        ui->connect_button->setText("断开连接");
        //发送键使能
        ui->send_button->setEnabled(true);
    }
    else
    {
    
    
        qDebug() << "Disconnect!";
        //断开连接
        socket->disconnectFromHost();
        //修改按键文字&发送键静默
        ui->connect_button->setText("连接");
        ui->send_button->setEnabled(false);
    }
}

//发送消息,写入socket缓存区
void Client::on_send_button_clicked()
{
    
    
    qDebug() << "Client Send: " << ui->sender->toPlainText().toLatin1();
    //将输入框的内容写入socket缓冲区
    socket->write(ui->sender->toPlainText().toLatin1());
    //刷新socket缓冲区
    socket->flush();
}


2、サーバー.cpp

#include "server.h"
#include "ui_server.h"

Server::Server(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::Server)
{
    
    
    ui->setupUi(this);
    //设置clicked(bool checked)点击反转状态打开
    ui->startorstop_Listen->setCheckable(true);

    socket = new QTcpSocket();
    server = new QTcpServer();

    //信号:新的客户端连接建立 槽函数:获取客户端套接字,允许写入数据
    connect(server,SIGNAL(newConnection()),this,SLOT(newConnection_SLOT()));
}

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

//信号:新的客户端连接建立 槽函数:获取客户端套接字,允许写入数据
void Server::newConnection_SLOT()
{
    
    
    socket = server->nextPendingConnection(); //获取已经连接的客户端套接字
    connect(socket,SIGNAL(readyRead()),this,SLOT(readyRead_SLOT()));//如果socket中有缓存消息,触发槽函数
}

//接收消息并显示到接收框
void Server::readyRead_SLOT()
{
    
    
    qDebug() << "Server Received!";
    QString buffer;
    //读取缓冲区数据
    buffer = socket->readAll();
    if(!buffer.isEmpty())
    {
    
    
        //刷新显示
        ui->receiver->appendPlainText(buffer);
    }
}


//开始监听和停止监听按键
void Server::on_startorstop_Listen_clicked(bool checked)
{
    
    
    if(checked)
    {
    
    
        int port = ui->portnum->text().toUInt();
        //如果未监听到
        if(!server->listen(QHostAddress::Any, port))
        {
    
    
            qDebug() << server->errorString();
            //连接失败,再次点击则重新连接,将checked恢复为true
            ui->startorstop_Listen->toggle();
            return;
        }
        qDebug() << "Listen Successfully! Message from port:" << port;
        //修改按钮文字
        ui->startorstop_Listen->setText("停止监听");
        //发送键使能
        ui->send_button->setEnabled(true);
    }
    else
    {
    
    
         qDebug() << "Stop Listening!";
        //如果已经连接则断开连接
        if(socket->state() == QAbstractSocket::ConnectedState)
        {
    
    
            //断开连接
            socket->disconnectFromHost();
        }
        //关闭倾听服务
        server->close();
        //修改按钮文字&发送键静默
        ui->startorstop_Listen->setText("开始监听");
        ui->send_button->setEnabled(false);
    }
}

//发送消息,写入socket缓存区
void Server::on_send_button_clicked()
{
    
    
    qDebug() << "Server Send: " << ui->sender->toPlainText().toLatin1();
    //将输入框的内容写入socket缓冲区
    socket->write(ui->sender->toPlainText().toLatin1());
    //刷新socket缓冲区
    socket->flush();
}

3、main.cpp

#include "server.h"
#include "client.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    
    
    QApplication a(argc, argv);
    Server w1;
    Client w2;

    //Client窗口通过鼠标单机获得聚焦
    w2.setFocusPolicy(Qt::ClickFocus);
    //将客户端和服务端窗口移动到屏幕合适位置
    w1.move(320,340);
    w2.move(960,340);

    //打开客户端和服务端窗口
    w1.show();
    w2.show();

    return a.exec();
}

(3) UIデザインファイル

client.ui
server.ui は

手動で設計でき、対応するテキスト ボックスまたはウィンドウ、キー名、コードは一貫している必要があります。
(デザインするのが面倒で効果を確認したい場合は、下部にあるソースコードを直接ダウンロードできます)
サーバー サーバーインターフェース
サーバー サーバーオブジェクトの名前付け

クライアント クライアントインターフェース
クライアント クライアントオブジェクトの名前付け


3. 概要とソースコードのリンク

コード内のコメントは非常に完全なので、修正する必要があります。読んでいただきありがとうございます。皆様のご支援が私にとって最大の助けです。
ソースコードはこちら

おすすめ

転載: blog.csdn.net/huangweijie0426/article/details/127327905