首页 > 其他分享 >TCP 通信-Qt-思维导图-学习笔记

TCP 通信-Qt-思维导图-学习笔记

时间:2024-08-20 14:58:20浏览次数:10  
标签:tcpSocket Qt 导图 pushButton TCP hBoxLayout new void 客户端

TCP 通信

在这里插入图片描述

TCP 简介

TCP协议概述

  • 全称:Transmission Control Protocol(传输控制协议)

  • 特性:面向连接、可靠、基于字节流的传输层通信协议

TCP通信流程

  • 建立连接:TCP通信必须先建立连接

  • 通信端:分为客户端和服务端

服务端操作

  • 监听端口:服务端监听某个端口,等待客户端连接

  • 建立连接:当有客户端连接到来时,服务端建立新的socket连接

客户端操作

  • 连接服务端:客户端通过指定的IP地址和端口号连接服务端

  • 数据收发:成功建立连接后,客户端和服务端即可进行数据的发送和接收

Qt中的TCP通信

  • Socket处理:Qt将socket当成输入输出流来处理

  • 数据收发方法:使用read()和write()函数进行数据的读取和写入

  • 区别:与常见的send()和recv()函数有区别

TCP 服务端应用实例

大致流程

  • 获取本地IP地址

    • 首先需要获取本地的IP地址,这是为了确保服务端能够监听正确的网络接口
  • 创建套接字和服务端

    • 创建一个tcpSocket套接字,用于客户端与服务端之间的通信

    • 创建一个tcpServer服务端,用于监听客户端的连接请求

  • 监听操作

    • 点击“监听”按钮后,程序将开始监听本地的主机IP地址和指定的端口

    • 服务端进入等待状态,准备接受客户端的连接请求

  • 结合客户端使用

    • 需要与客户端程序配合使用

    • 客户端程序将尝试连接到服务端的IP地址和端口,以便进行数据交换

项目文件文件第一行添加的代码部分如下

  • 1 QT += core gui network

mainwindow.h

  • 1 #ifndef MAINWINDOW_H
    2 #define MAINWINDOW_H
    3
    4 #include
    5 #include
    6 #include
    7 #include
    8 #include
    9 #include
    10 #include
    11 #include
    12 #include
    13 #include
    14 #include
    15 #include
    16 #include
    17 #include
    18
    19 class MainWindow : public QMainWindow
    20 {
    21 Q_OBJECT
    22
    23 public:
    24 MainWindow(QWidget parent = nullptr);
    25 ~MainWindow();
    26
    27 private:
    28 /
    tcp 服务器 */
    29 QTcpServer tcpServer;
    30
    31 /
    通信套接字 */
    32 QTcpSocket tcpSocket;
    33
    34 /
    按钮 */
    35 QPushButton pushButton[4];
    36
    37 /
    标签文本 */
    38 QLabel label[2];
    39
    40 /
    水平容器 */
    41 QWidget hWidget[3];
    42
    43 /
    水平布局 */
    44 QHBoxLayout hBoxLayout[3];
    45
    46 /
    垂直容器 */
    47 QWidget vWidget;
    48
    49 /
    垂直布局 */
    50 QVBoxLayout vBoxLayout;
    51
    52 /
    文本浏览框 */
    53 QTextBrowser textBrowser;
    54
    55 /
    用于显示本地 ip */
    56 QComboBox comboBox;
    57
    58 /
    用于选择端口 */
    59 QSpinBox spinBox;
    60
    61 /
    文本输入框 */
    62 QLineEdit lineEdit;
    63
    64 /
    存储本地的 ip 列表地址 /
    65 QList IPlist;
    66
    67 /
    获取本地的所有 ip /
    68 void getLocalHostIP();
    69
    70 private slots:
    71 /
    客户端连接处理槽函数 /
    72 void clientConnected();
    73
    74 /
    开始监听槽函数 /
    75 void startListen();
    76
    77 /
    停止监听槽函数 /
    78 void stopListen();
    79
    80 /
    清除文本框时的内容 /
    81 void clearTextBrowser();
    82
    83 /
    接收到消息 /
    84 void receiveMessages();
    85
    86 /
    发送消息 /
    87 void sendMessages();
    88
    89 /
    连接状态改变槽函数 */
    90 void socketStateChange(QAbstractSocket::SocketState);
    91 };
    92 #endif // MAINWINDOW_H

  • 主要是声明界面用的元素,及一些槽函数。重点是声明 tcpServer 和 tcpSocket

mainwindow.cpp

  • 1 #include “mainwindow.h”
    2
    3 MainWindow::MainWindow(QWidget parent)
    4 : QMainWindow(parent)
    5{
    6 /
    设置主窗体的位置与大小 /
    7 this->setGeometry(0, 0, 800, 480);
    8
    9 /
    实例化 tcp 服务器与 tcp 套接字 /
    10 tcpServer = new QTcpServer(this);
    11 tcpSocket = new QTcpSocket(this);
    12
    13 /
    开始监听按钮 /
    14 pushButton[0] = new QPushButton();
    15 /
    停止监听按钮 /
    16 pushButton[1] = new QPushButton();
    17 /
    清空聊天文本按钮 /
    18 pushButton[2] = new QPushButton();
    19 /
    发送消息按钮 /
    20 pushButton[3] = new QPushButton();
    21
    22 /
    水平布局一 /
    23 hBoxLayout[0] = new QHBoxLayout();
    24 /
    水平布局二 /
    25 hBoxLayout[1] = new QHBoxLayout();
    26 /
    水平布局三 /
    27 hBoxLayout[2] = new QHBoxLayout();
    28 /
    水平布局四 /
    29 hBoxLayout[3] = new QHBoxLayout();
    30
    31 /
    水平容器一 /
    32 hWidget[0] = new QWidget();
    33 /
    水平容器二 /
    34 hWidget[1] = new QWidget();
    35 /
    水平容器三 /
    36 hWidget[2] = new QWidget();
    37
    38 vWidget = new QWidget();
    39 vBoxLayout = new QVBoxLayout();
    40
    41 /
    标签实例化 /
    42 label[0] = new QLabel();
    43 label[1] = new QLabel();
    44
    45 lineEdit = new QLineEdit();
    46 comboBox = new QComboBox();
    47 spinBox = new QSpinBox();
    48 textBrowser = new QTextBrowser();
    49
    50 label[0]->setText(“监听 IP 地址:”);
    51 label[1]->setText(“监听端口:”);
    52
    53 /
    设置标签根据文本文字大小自适应大小 /
    54 label[0]->setSizePolicy(QSizePolicy::Fixed,
    55 QSizePolicy::Fixed);
    56 label[1]->setSizePolicy(QSizePolicy::Fixed,
    57 QSizePolicy::Fixed);
    58
    59 /
    设置端口号的范围,注意不要与主机的已使用的端口号冲突 /
    60 spinBox->setRange(10000, 99999);
    61
    62 pushButton[0]->setText(“开始监听”);
    63 pushButton[1]->setText(“停止监听”);
    64 pushButton[2]->setText(“清空文本”);
    65 pushButton[3]->setText(“发送消息”);
    66
    67 /
    设置停止监听状态不可用 /
    68 pushButton[1]->setEnabled(false);
    69
    70 /
    设置输入框默认的文本 /
    71 lineEdit->setText(“www.openedv.com 正点原子论坛”);
    72
    73 /
    水平布局一添加内容 /
    74 hBoxLayout[0]->addWidget(pushButton[0]);
    75 hBoxLayout[0]->addWidget(pushButton[1]);
    76 hBoxLayout[0]->addWidget(pushButton[2]);
    77
    78 /
    设置水平容器一的布局为水平布局一 /
    79 hWidget[0]->setLayout(hBoxLayout[0]);
    80
    81 /
    水平布局二添加内容 /
    82 hBoxLayout[1]->addWidget(label[0]);
    83 hBoxLayout[1]->addWidget(comboBox);
    84 hBoxLayout[1]->addWidget(label[1]);
    85 hBoxLayout[1]->addWidget(spinBox);
    86
    87 /
    设置水平容器二的布局为水平布局二 /
    88 hWidget[1]->setLayout(hBoxLayout[1]);
    89
    90 /
    水平布局三添加内容 /
    91 hBoxLayout[2]->addWidget(lineEdit);
    92 hBoxLayout[2]->addWidget(pushButton[3]);
    93
    94 /
    设置水平容器三的布局为水平布局一 /
    95 hWidget[2]->setLayout(hBoxLayout[2]);
    96
    97 /
    垂直布局添加内容 /
    98 vBoxLayout->addWidget(textBrowser);
    99 vBoxLayout->addWidget(hWidget[1]);
    100 vBoxLayout->addWidget(hWidget[0]);
    101 vBoxLayout->addWidget(hWidget[2]);
    102
    103 /
    设置垂直容器的布局为垂直布局 /
    104 vWidget->setLayout(vBoxLayout);
    105
    106 /
    居中显示 /
    107 setCentralWidget(vWidget);
    108
    109 /
    获取本地 ip /
    110 getLocalHostIP();
    111
    112 /
    信号槽连接 /
    113 connect(pushButton[0], SIGNAL(clicked()),
    114 this, SLOT(startListen()));
    115 connect(pushButton[1], SIGNAL(clicked()),
    116 this, SLOT(stopListen()));
    117 connect(pushButton[2], SIGNAL(clicked()),
    118 this, SLOT(clearTextBrowser()));
    119 connect(pushButton[3], SIGNAL(clicked()),
    120 this, SLOT(sendMessages()));
    121 connect(tcpServer, SIGNAL(newConnection()),
    122 this, SLOT(clientConnected()));
    123 }
    124
    125 MainWindow::~MainWindow()
    126 {
    127 }
    128
    129 /
    新的客户端连接 /
    130 void MainWindow::clientConnected()
    131 {
    132 /
    获取客户端的套接字 /
    133 tcpSocket = tcpServer->nextPendingConnection();
    134 /
    客户端的 ip 信息 /
    135 QString ip = tcpSocket->peerAddress().toString();
    136 /
    客户端的端口信息 /
    137 quint16 port = tcpSocket->peerPort();
    138 /
    在文本浏览框里显示出客户端的连接信息 /
    139 textBrowser->append(“客户端已连接”);
    140 textBrowser->append(“客户端 ip 地址:”
    141 + ip);
    142 textBrowser->append(“客户端端口:”
    143 + QString::number(port));
    144
    145 connect(tcpSocket, SIGNAL(readyRead()),
    146 this, SLOT(receiveMessages()));
    147 connect(tcpSocket,
    148 SIGNAL(stateChanged(QAbstractSocket::SocketState)),
    149 this,
    150 SLOT(socketStateChange(QAbstractSocket::SocketState)));
    151 }
    152
    153 /
    获取本地 IP /
    154 void MainWindow::getLocalHostIP()
    155 {
    156 // /
    获取主机的名称 /
    157 // QString hostName = QHostInfo::localHostName();
    158
    159 // /
    主机的信息 /
    160 // QHostInfo hostInfo = QHostInfo::fromName(hostName);
    161
    162 // /
    ip 列表,addresses 返回 ip 地址列表,注意主机应能从路由器获取到
    163 // * IP,否则可能返回空的列表(ubuntu 用此方法只能获取到环回 IP) /
    164 // IPlist = hostInfo.addresses();
    165 // qDebug()<<IPlist<<endl;
    166
    167 // /
    遍历 IPlist /
    168 // foreach (QHostAddress ip, IPlist) {
    169 // if (ip.protocol() == QAbstractSocket::IPv4Protocol)
    170 // comboBox->addItem(ip.toString());
    171 // }
    172
    173 /
    获取所有的网络接口,
    174 * QNetworkInterface 类提供主机的 IP 地址和网络接口的列表 /
    175 QList list
    176 = QNetworkInterface::allInterfaces();
    177
    178 /
    遍历 list /
    179 foreach (QNetworkInterface interface, list) {
    180
    181 /
    QNetworkAddressEntry 类存储 IP 地址子网掩码和广播地址 /
    182 QList entryList
    183 = interface.addressEntries();
    184
    185 /
    遍历 entryList /
    186 foreach (QNetworkAddressEntry entry, entryList) {
    187 /
    过滤 IPv6 地址,只留下 IPv4 /
    188 if (entry.ip().protocol() ==
    189 QAbstractSocket::IPv4Protocol) {
    190 comboBox->addItem(entry.ip().toString());
    191 /
    添加到 IP 列表中 /
    192 IPlist<<entry.ip();
    193 }
    194 }
    195 }
    196 }
    197
    198 /
    开始监听 /
    199 void MainWindow::startListen()
    200 {
    201 /
    需要判断当前主机是否有 IP 项 /
    202 if (comboBox->currentIndex() != -1) {
    203 qDebug()<<“start listen”<<endl;
    204 tcpServer->listen(IPlist[comboBox->currentIndex()],
    205 spinBox->value());
    206
    207 /
    设置按钮与下拉列表框的状态 /
    208 pushButton[0]->setEnabled(false);
    209 pushButton[1]->setEnabled(true);
    210 comboBox->setEnabled(false);
    211 spinBox->setEnabled(false);
    212
    213 /
    在文本浏览框里显示出服务端 /
    214 textBrowser->append(“服务器 IP 地址:”
    215 + comboBox->currentText());
    216 textBrowser->append(“正在监听端口:”
    217 + spinBox->text());
    218 }
    219 }
    220
    221 /
    停止监听 /
    222 void MainWindow::stopListen()
    223 {
    224 qDebug()<<“stop listen”<<endl;
    225 /
    停止监听 /
    226 tcpServer->close();
    227
    228 /
    如果是连接上了也应该断开,如果不断开客户端还能继续发送信息,
    229 * 因为 socket 未断开,还在监听上一次端口 /
    230 if (tcpSocket->state() == tcpSocket->ConnectedState)
    231 tcpSocket->disconnectFromHost();
    232
    233 /
    设置按钮与下拉列表框的状态 /
    234 pushButton[1]->setEnabled(false);
    235 pushButton[0]->setEnabled(true);
    236 comboBox->setEnabled(true);
    237 spinBox->setEnabled(true);
    238
    239 /
    将停止监听的信息添加到文本浏览框中 /
    240 textBrowser->append(“已停止监听端口:”
    241 + spinBox->text());
    242 }
    243
    244 /
    清除文本浏览框里的内容 /
    245 void MainWindow::clearTextBrowser()
    246 {
    247 /
    清除文本浏览器的内容 /
    248 textBrowser->clear();
    249 }
    250
    251 /
    服务端接收消息 /
    252 void MainWindow::receiveMessages()
    253 {
    254 /
    读取接收到的消息 /
    255 QString messages = “客户端:” + tcpSocket->readAll();
    256 textBrowser->append(messages);
    257 }
    258
    259 /
    服务端发送消息 /
    260 void MainWindow::sendMessages()
    261 {
    262 if(NULL == tcpSocket)
    263 return;
    264
    265 /
    如果已经连接 /
    266 if(tcpSocket->state() == tcpSocket->ConnectedState) {
    267 /
    发送消息 /
    268 tcpSocket->write(lineEdit->text().toUtf8().data());
    269
    270 /
    在服务端插入发送的消息 /
    271 textBrowser->append(“服务端:” + lineEdit->text());
    272 }
    273 }
    274
    275 /
    服务端状态改变 */
    276 void MainWindow::socketStateChange(QAbstractSocket::SocketState
    state)
    277 {
    278 switch (state) {
    279 case QAbstractSocket::UnconnectedState:
    280 textBrowser->append(“scoket 状态:UnconnectedState”);
    281 break;
    282 case QAbstractSocket::ConnectedState:
    283 textBrowser->append(“scoket 状态:ConnectedState”);
    284 break;
    285 case QAbstractSocket::ConnectingState:
    286 textBrowser->append(“scoket 状态:ConnectingState”);
    287 break;
    288 case QAbstractSocket::HostLookupState:
    289 textBrowser->append(“scoket 状态:HostLookupState”);
    290 break;
    291 case QAbstractSocket::ClosingState:
    292 textBrowser->append(“scoket 状态:ClosingState”);
    293 break;
    294 case QAbstractSocket::ListeningState:
    295 textBrowser->append(“scoket 状态:ListeningState”);
    296 break;
    297 case QAbstractSocket::BoundState:
    298 textBrowser->append(“scoket 状态:BoundState”);
    299 break;
    300 default:
    301 break;
    302 }
    303 }

  • 服务端开启监听后,通过newConnection()信号处理客户端连接,连接到接收消息的槽函数,通过点击按钮进行消息发送,一切的消息收发都通过tcpSocket的read()和write()函数完成

TCP 客户端应用实例

大致流程

  • 获取本地IP地址

    • 程序首先需要获取本地的IP地址,这一步是为了确保客户端能够知道自己的网络接口信息
  • 创建套接字

    • 创建一个tcpSocket套接字,用于与服务端之间的通信
  • 连接服务端

    • 使用tcpSocket的connectToHost函数,指定服务端的主机IP地址和端口,尝试建立连接
  • 开始通信

    • 一旦连接成功,客户端与服务端即可进行相互通信

项目文件文件第一行添加的代码部分如下

  • 1 QT += core gui network

mainwindow.h

  • 1 #ifndef MAINWINDOW_H
    2 #define MAINWINDOW_H
    3
    4 #include
    5 #include
    6 #include
    7 #include
    8 #include
    9 #include
    10 #include
    11 #include
    12 #include
    13 #include
    14 #include
    15 #include
    16 #include
    17 #include
    18
    19 class MainWindow : public QMainWindow
    20 {
    21 Q_OBJECT
    22
    23 public:
    24 MainWindow(QWidget parent = nullptr);
    25 ~MainWindow();
    26
    27 private:
    28 /
    通信套接字 */
    29 QTcpSocket tcpSocket;
    30
    31 /
    按钮 */
    32 QPushButton pushButton[4];
    33
    34 /
    标签文本 */
    35 QLabel label[2];
    36
    37 /
    水平容器 */
    38 QWidget hWidget[3];
    39
    40 /
    水平布局 */
    41 QHBoxLayout hBoxLayout[3];
    42
    43 /
    垂直容器 */
    44 QWidget vWidget;
    45
    46 /
    垂直布局 */
    47 QVBoxLayout vBoxLayout;
    48
    49 /
    文本浏览框 */
    50 QTextBrowser textBrowser;
    51
    52 /
    用于显示本地 ip */
    53 QComboBox comboBox;
    54
    55 /
    用于选择端口 */
    56 QSpinBox spinBox;
    57
    58 /
    文本输入框 */
    59 QLineEdit lineEdit;
    60
    61 /
    存储本地的 ip 列表地址 /
    62 QList IPlist;
    63
    64 /
    获取本地的所有 ip /
    65 void getLocalHostIP();
    66
    67 private slots:
    68 /
    连接 /
    69 void toConnect();
    70
    71 /
    断开连接 /
    72 void toDisConnect();
    73
    74 /
    已连接 /
    75 void connected();
    76
    77 /
    已断开连接 /
    78 void disconnected();
    79
    80 /
    清除文本框时的内容 /
    81 void clearTextBrowser();
    82
    83 /
    接收到消息 /
    84 void receiveMessages();
    85
    86 /
    发送消息 /
    87 void sendMessages();
    88
    89 /
    连接状态改变槽函数 */
    90 void socketStateChange(QAbstractSocket::SocketState);
    91 };
    92 #endif // MAINWINDOW_H

  • 主要是声明界面用的元素,及一些槽函数。重点是声明 tcpSocket

mainwindow.cpp

  • 1 #include “mainwindow.h”
    2
    3 MainWindow::MainWindow(QWidget parent)
    4 : QMainWindow(parent)
    5{
    6 /
    设置主窗体的位置与大小 /
    7 this->setGeometry(0, 0, 800, 480);
    8
    9 /
    tcp 套接字 /
    10 tcpSocket = new QTcpSocket(this);
    11
    12 /
    开始监听按钮 /
    13 pushButton[0] = new QPushButton();
    14 /
    停止监听按钮 /
    15 pushButton[1] = new QPushButton();
    16 /
    清空聊天文本按钮 /
    17 pushButton[2] = new QPushButton();
    18 /
    发送消息按钮 /
    19 pushButton[3] = new QPushButton();
    20
    21 /
    水平布局一 /
    22 hBoxLayout[0] = new QHBoxLayout();
    23 /
    水平布局二 /
    24 hBoxLayout[1] = new QHBoxLayout();
    25 /
    水平布局三 /
    26 hBoxLayout[2] = new QHBoxLayout();
    27 /
    水平布局四 /
    28 hBoxLayout[3] = new QHBoxLayout();
    29
    30 /
    水平容器一 /
    31 hWidget[0] = new QWidget();
    32 /
    水平容器二 /
    33 hWidget[1] = new QWidget();
    34 /
    水平容器三 /
    35 hWidget[2] = new QWidget();
    36
    37
    38 vWidget = new QWidget();
    39 vBoxLayout = new QVBoxLayout();
    40
    41 /
    标签实例化 /
    42 label[0] = new QLabel();
    43 label[1] = new QLabel();
    44
    45 lineEdit = new QLineEdit();
    46 comboBox = new QComboBox();
    47 spinBox = new QSpinBox();
    48 textBrowser = new QTextBrowser();
    49
    50 label[0]->setText(“服务器地址:”);
    51 label[1]->setText(“服务器端口:”);
    52
    53 /
    设置标签根据文本文字大小自适应大小 /
    54 label[0]->setSizePolicy(QSizePolicy::Fixed,
    55 QSizePolicy::Fixed);
    56 label[1]->setSizePolicy(QSizePolicy::Fixed,
    57 QSizePolicy::Fixed);
    58
    59 /
    设置端口号的范围,注意不要与主机的已使用的端口号冲突 /
    60 spinBox->setRange(10000, 99999);
    61
    62 pushButton[0]->setText(“连接服务器”);
    63 pushButton[1]->setText(“断开连接”);
    64 pushButton[2]->setText(“清空文本”);
    65 pushButton[3]->setText(“发送消息”);
    66
    67 /
    设置停止监听状态不可用 /
    68 pushButton[1]->setEnabled(false);
    69
    70 /
    设置输入框默认的文本 /
    71 lineEdit->setText(“广州星翼电子科技有限公司”);
    72
    73 /
    水平布局一添加内容 /
    74 hBoxLayout[0]->addWidget(pushButton[0]);
    75 hBoxLayout[0]->addWidget(pushButton[1]);
    76 hBoxLayout[0]->addWidget(pushButton[2]);
    77
    78 /
    设置水平容器的布局为水平布局一 /
    79 hWidget[0]->setLayout(hBoxLayout[0]);
    80
    81 hBoxLayout[1]->addWidget(label[0]);
    82 hBoxLayout[1]->addWidget(comboBox);
    83 hBoxLayout[1]->addWidget(label[1]);
    84 hBoxLayout[1]->addWidget(spinBox);
    85
    86 /
    设置水平容器的布局为水平布局二 /
    87 hWidget[1]->setLayout(hBoxLayout[1]);
    88
    89 /
    水平布局三添加内容 /
    90 hBoxLayout[2]->addWidget(lineEdit);
    91 hBoxLayout[2]->addWidget(pushButton[3]);
    92
    93 /
    设置水平容器三的布局为水平布局一 /
    94 hWidget[2]->setLayout(hBoxLayout[2]);
    95
    96 /
    垂直布局添加内容 /
    97 vBoxLayout->addWidget(textBrowser);
    98 vBoxLayout->addWidget(hWidget[1]);
    99 vBoxLayout->addWidget(hWidget[0]);
    100 vBoxLayout->addWidget(hWidget[2]);
    101
    102 /
    设置垂直容器的布局为垂直布局 /
    103 vWidget->setLayout(vBoxLayout);
    104
    105 /
    居中显示 /
    106 setCentralWidget(vWidget);
    107
    108 /
    获取本地 ip /
    109 getLocalHostIP();
    110
    111 /
    信号槽连接 /
    112 connect(pushButton[0], SIGNAL(clicked()),
    113 this, SLOT(toConnect()));
    114 connect(pushButton[1], SIGNAL(clicked()),
    115 this, SLOT(toDisConnect()));
    116 connect(pushButton[2], SIGNAL(clicked()),
    117 this, SLOT(clearTextBrowser()));
    118 connect(pushButton[3], SIGNAL(clicked()),
    119 this, SLOT(sendMessages()));
    120 connect(tcpSocket, SIGNAL(connected()),
    121 this, SLOT(connected()));
    122 connect(tcpSocket, SIGNAL(disconnected()),
    123 this, SLOT(disconnected()));
    124 connect(tcpSocket, SIGNAL(readyRead()),
    125 this, SLOT(receiveMessages()));
    126 connect(tcpSocket,
    127 SIGNAL(stateChanged(QAbstractSocket::SocketState)),
    128 this,
    129 SLOT(socketStateChange(QAbstractSocket::SocketState)));
    130 }
    131
    132 MainWindow::~MainWindow()
    133 {
    134 }
    135
    136 void MainWindow::toConnect()
    137 {
    138 /
    如果连接状态还没有连接 /
    139 if (tcpSocket->state() != tcpSocket->ConnectedState) {
    140 /
    指定 IP 地址和端口连接 /
    141 tcpSocket->connectToHost(IPlist[comboBox->currentIndex()],
    142 spinBox->value());
    143 }
    144 }
    145
    146 void MainWindow::toDisConnect()
    147 {
    148 /
    断开连接 /
    149 tcpSocket->disconnectFromHost();
    150
    151 /
    关闭 socket*/
    152 tcpSocket->close();
    153 }
    154
    155 void MainWindow::connected()
    156 {
    157 /* 显示已经连接 /
    158 textBrowser->append(“已经连上服务端”);
    159
    160 /
    设置按钮与下拉列表框的状态 /
    161 pushButton[0]->setEnabled(false);
    162 pushButton[1]->setEnabled(true);
    163 comboBox->setEnabled(false);
    164 spinBox->setEnabled(false);
    165 }
    166
    167 void MainWindow::disconnected()
    168 {
    169 /
    显示已经断开连接 /
    170 textBrowser->append(“已经断开服务端”);
    171
    172 /
    设置按钮与下拉列表框的状态 /
    173 pushButton[1]->setEnabled(false);
    174 pushButton[0]->setEnabled(true);
    175 comboBox->setEnabled(true);
    176 spinBox->setEnabled(true);
    177 }
    178
    179 /
    获取本地 IP /
    180 void MainWindow::getLocalHostIP()
    181 {
    182 // /
    获取主机的名称 /
    183 // QString hostName = QHostInfo::localHostName();
    184
    185 // /
    主机的信息 /
    186 // QHostInfo hostInfo = QHostInfo::fromName(hostName);
    187
    188 // /
    ip 列表,addresses 返回 ip 地址列表,注意主机应能从路由器获取到
    189 // * IP,否则可能返回空的列表(ubuntu 用此方法只能获取到环回 IP) /
    190 // IPlist = hostInfo.addresses();
    191 // qDebug()<<IPlist<<endl;
    192
    193 // /
    遍历 IPlist /
    194 // foreach (QHostAddress ip, IPlist) {
    195 // if (ip.protocol() == QAbstractSocket::IPv4Protocol)
    196 // comboBox->addItem(ip.toString());
    197 // }
    198
    199 /
    获取所有的网络接口,
    200 * QNetworkInterface 类提供主机的 IP 地址和网络接口的列表 /
    201 QList list
    202 = QNetworkInterface::allInterfaces();
    203
    204 /
    遍历 list /
    205 foreach (QNetworkInterface interface, list) {
    206
    207 /
    QNetworkAddressEntry 类存储 IP 地址子网掩码和广播地址 /
    208 QList entryList
    209 = interface.addressEntries();
    210
    211 /
    遍历 entryList /
    212 foreach (QNetworkAddressEntry entry, entryList) {
    213 /
    过滤 IPv6 地址,只留下 IPv4 /
    214 if (entry.ip().protocol() ==
    215 QAbstractSocket::IPv4Protocol) {
    216 comboBox->addItem(entry.ip().toString());
    217 /
    添加到 IP 列表中 /
    218 IPlist<<entry.ip();
    219 }
    220 }
    221 }
    222 }
    223
    224 /
    清除文本浏览框里的内容 /
    225 void MainWindow::clearTextBrowser()
    226 {
    227 /
    清除文本浏览器的内容 /
    228 textBrowser->clear();
    229 }
    230
    231 /
    客户端接收消息 /
    232 void MainWindow::receiveMessages()
    233 {
    234 /
    读取接收到的消息 /
    235 QString messages = tcpSocket->readAll();
    236 textBrowser->append(“服务端:” + messages);
    237 }
    238
    239 /
    客户端发送消息 /
    240 void MainWindow::sendMessages()
    241 {
    242 if(NULL == tcpSocket)
    243 return;
    244
    245 if(tcpSocket->state() == tcpSocket->ConnectedState) {
    246 /
    客户端显示发送的消息 /
    247 textBrowser->append(“客户端:” + lineEdit->text());
    248
    249 /
    发送消息 /
    250 tcpSocket->write(lineEdit->text().toUtf8().data());
    251 }
    252 }
    253
    254 /
    客户端状态改变 */
    255 void MainWindow::socketStateChange(QAbstractSocket::SocketState
    state)
    256 {
    257 switch (state) {
    258 case QAbstractSocket::UnconnectedState:
    259 textBrowser->append(“scoket 状态:UnconnectedState”);
    260 break;
    261 case QAbstractSocket::ConnectedState:
    262 textBrowser->append(“scoket 状态:ConnectedState”);
    263 break;
    264 case QAbstractSocket::ConnectingState:
    265 textBrowser->append(“scoket 状态:ConnectingState”);
    266 break;
    267 case QAbstractSocket::HostLookupState:
    268 textBrowser->append(“scoket 状态:HostLookupState”);
    269 break;
    270 case QAbstractSocket::ClosingState:
    271 textBrowser->append(“scoket 状态:ClosingState”);
    272 break;
    273 case QAbstractSocket::ListeningState:
    274 textBrowser->append(“scoket 状态:ListeningState”);
    275 break;
    276 case QAbstractSocket::BoundState:
    277 textBrowser->append(“scoket 状态:BoundState”);
    278 break;
    279 default:
    280 break;
    281 }
    282 }

  • 客户端使用connectToHost连接到服务端的IP地址和端口,连接成功后发射connected()信号并连接到相应的槽函数,通过点击按钮发送消息,一切消息的发送和接收都是通过tcpSocket的read()和write()函数完成

程序运行效果

选择服务端监听IP地址和端口

  • 开启服务端后,需要选择一个本地IP地址和监听端口

  • 特别注意不要选择已经被本地主机使用的端口号,可以通过netstat指令查看本机已经使用的端口号

  • 建议设置一个较大的端口号以避免冲突

启动客户端

  • 启动客户端后,需要选择要连接的服务器IP地址和服务器监听的端口

点击连接

  • 在客户端选择好服务器IP地址和端口后,点击连接按钮

相互发送消息

  • 连接成功后,服务端和客户端即可相互发送消息

测试环境

  • 服务端和客户端都选择了本地环回IP地址127.0.0.1进行测试

  • 也可以选择本地的其他IP地址进行测试

TCP 服务端

TCP 客户端

标签:tcpSocket,Qt,导图,pushButton,TCP,hBoxLayout,new,void,客户端
From: https://blog.csdn.net/weixin_62434750/article/details/141305163

相关文章

  • 学懂C++(三十九):网络编程——深入详解 TCP 和 UDP 的区别和应用场景
    目录一、TCP的特点及应用场景1.可靠性2.流控制和拥塞控制3.有序传输4.应用场景二、UDP的特点及应用场景1.无连接2.不可靠性3.轻量级4.支持广播和多播5.应用场景三、TCP和UDP的区别四、TCP和UDP的工作原理1.TCP的工作原理三次握手数据传输......
  • 面试必备之TCP知识
    概述关于TCP的杂乱知识点,不成体系,毕竟TCP真的太复杂。TCP,TransmissionControlProtocol;IP,InternetProtocol,两者共同组成TCP/IP协议族,包含一系列构成互联网基础的网络协议。OSI七层网络模型图片来自于OSI七层网络模型OSI七层由于太过严格,所以并没有应用在计算机中,其衍生的T......
  • TCPIP路由技术第一卷第八章OSPF 第六部分-1虚链路
    tcp/ip_ospf案例研究6虚链路/认证/ABRfiltering1.area1virtual-link33.1.1.1(rid)2.gretunnel(ip封装ip的技术)inttunnel0ipadd113.1.1.1255.255.255.0ipospf110area0tunnelsourcelo0tunneldestination33.1.1.13.认证有很多种组合,值需要记住本资粮链......
  • TCPIP路由技术第一卷第八章OSPF 第五部分-2 Forward address
    tcp/ip_ospf案例研究5forwardaddressforwardaddress:intheautonomoussystem'sinteriortofunctionas"routeserver"initsas-external-lsas,packetsshouldberouteddirectly通告0.0.0.0非0的情况nssa区域:转发地址为asbr上最大的环回口非nssa:直接为下一跳地......
  • TCPIP路由技术第一卷第八章OSPF 第五部分-1 特殊区域
    tcp/ip_ospf案例研究4特殊区域1.stub区域:区域内所有设备areaidstub:abr会通告一条oia(默认cost1)的默认路由,存在3类lsa不存在4,5类lsa2.totallystub区域:abr配置no-summary,其他设备配置areaidstub;abr会通告一条oia的默认路由;不存在3,4,5类lsa3.nssa区域:区域内所有......
  • TCPIP路由技术第一卷 第三大部分-2 重分步的定义及实验
    tcp/ip路由控制案例研究1单向重分布和双向重分布1.什么是充分:从一个协议(或者进程域)学习到的路由(以及运行该协议的直连接口)重分布到另一个协议的数据库中2.度量值,重分布时需要制定度量值让多种协议可以理解原来的度量值(seedmetric)3.ad(管理距离),从多个协议学习到同一......
  • TCPIP路由技术第一卷第八章OSPF 第六部分-2认证和LSA过滤
    ospf认证明文认证:链路,区域,虚链路密文认证(md5):链路,区域,虚链路ospf链路明文认证step1:在接口下设置认证密钥r1(config-if)#ipospfauthentication-keyccnpr2(config-if)#ipospfauthentication-keyccnpstep2:在接口下开启明文认证r1(config-if)#ipospfauthenti......
  • TCPIP路由技术第一卷 第三大部分-4 路由更新Distribute-list
    外部的路由可以进入到路由表中,路由表中的路由也可以被通告出去,那么路由过滤器正是通过管制这些出入路由表的路由来工作的.distributelisteigrpoutin方向完全满足ospfout方向不行r1:routerripnoautoversion2network12.0.0.0r2:routerripnoautoversion2ne......
  • TCPIP路由技术第一卷 第三大部分-3 同一协议的重分步以及ODR
    odr160r1:routereigrp1network12.1.1.10.0.0.0r2:routereigrp1noautonetwork12.1.1.20.0.0.0network22.1.1.10.0.0.0r1:routereigrp1redistributeeigrp90routereigrp90redistrbuteeigrp1r2:routerospf1network12.1.1.20.0.0.0area0......
  • TCPIP路由技术第一卷 第三大部分-6-route-map
    tcp/ip路由控制案例研究3多点重分布和ad值,route-map1.r1,r4正常双向重分布2.r1重分步ospf时拒绝某路由route-mapdenydeny10matchipadd1route-mapdenypermit203.r1上为某些路由做tacroute-maptacpermit10matchipaddress10settag44r2上会受到含tag44的......