本帖最后由 正点原子运营 于 2022-8-10 17:33 编辑
11.2 TCP通信
11.2.1 TCP简介TCP协议(Transmission Control Protocol)全称是传输控制协议是一种面向连接的、可靠的、基于字节流的传输层通信协议。 TCP通信必须先建立TCP连接,通信端分为客户端和服务端。服务端通过监听某个端口来监听是否有客户端连接到来,如果有连接到来,则建立新的socket连接;客户端通过ip和port连接服务端,当成功建立连接之后,就可进行数据的收发了。需要注意的是,在Qt中,Qt把socket当成输入输出流来对待的,数据的收发是通过read()和write()来进行的,需要与我们常见的send()与recv()进行区分。 TCP客户端与服务端通信示意图如下。
11.2.2 TCP服务端应用实例本例目的:了解TCP服务端的使用。 例08_tcpserver,TCP服务端(难度:一般)。项目路径为Qt/2/08_tcpserver。本例大体流程首先获取本地IP地址。创建一个tcpSocket套接字,一个tcpServer服务端。点击监听即监听本地的主机IP地址和端口,同时等待服务端的连接。此程序需要结合客户端一起使用。 项目文件08_tcpserver.pro文件第一行添加的代码部分如下。 - 08_tcpserver.pro编程后的代码
- 1 QT += core gui network
- 2
- 3 greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
- 4
- 5 CONFIG += c++11
- 6
- 7 # The following define makes your compiler emit warnings if you use
- 8 # any Qt feature that has been marked deprecated (the exact warnings
- 9 # depend on your compiler). Please consult the documentation of the
- 10 # deprecated API in order to know how to port your code away from it.
- 11 DEFINES += QT_DEPRECATED_WARNINGS
- 12
- 13 # You can also make your code fail to compile if it uses deprecated APIs.
- 14 # In order to do so, uncomment the following line.
- 15 # You can also select to disable deprecated APIs only up to a certain version of Qt.
- 16 #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
- 17
- 18 SOURCES += \
- 19 main.cpp \
- 20 mainwindow.cpp
- 21
- 22 HEADERS += \
- 23 mainwindow.h
- 24
- 25 # Default rules for deployment.
- 26 qnx: target.path = /tmp/${TARGET}/bin
- 27 else: unix:!android: target.path = /opt/${TARGET}/bin
- 28 !isEmpty(target.path): INSTALLS += target
复制代码在头文件“mainwindow.h”具体代码如下。 头文件里主要是声明界面用的元素,及一些槽函数。重点是声明tcpServer和tcpSocket。 在源文件“mainwindow.cpp”具体代码如下。 - mainwindow.cpp编程后的代码
- /******************************************************************
- Copyright © Deng Zhimao Co., Ltd. 1990-2021. All rights reserved.
- * @projectName 08_tcpserver
- * @brief mainwindow.cpp
- * @author Deng Zhimao
- * @email 1252699831@qq.com
- * @net www.openedv.com
- * @date 2021-04-13
- *******************************************************************/
- 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<QNetworkInterface> list
- 176 = QNetworkInterface::allInterfaces();
- 177
- 178 /* 遍历list */
- 179 foreach (QNetworkInterface interface, list) {
- 180
- 181 /* QNetworkAddressEntry类存储IP地址子网掩码和广播地址 */
- 182 QList<QNetworkAddressEntry> 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发送消息。注意发送消息和接收消息都是通过tcpSocket的read()和write()进行。
11.2.3 TCP客户端应用实例本例目的:了解TCP客户的使用。 例09_tcpclient,TCP客户端(难度:一般)。项目路径为Qt/2/09_ tcpclient。本例大体流程:首先获取本地IP地址。创建一个tcpSocket套接字,然后用tcpSocket套接字使用connectToHost函数连接服务端的主机IP地址和端口,即可相互通信。 项目文件08_tcpserver.pro文件第一行添加的代码部分如下。 - 09_tcpclient.pro编程后的代码
- 1 QT += core gui network
- 2
- 3 greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
- 4
- 5 CONFIG += c++11
- 6
- 7 # The following define makes your compiler emit warnings if you use
- 8 # any Qt feature that has been marked deprecated (the exact warnings
- 9 # depend on your compiler). Please consult the documentation of the
- 10 # deprecated API in order to know how to port your code away from it.
- 11 DEFINES += QT_DEPRECATED_WARNINGS
- 12
- 13 # You can also make your code fail to compile if it uses deprecated APIs.
- 14 # In order to do so, uncomment the following line.
- 15 # You can also select to disable deprecated APIs only up to a certain version of Qt.
- 16 #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
- 17
- 18 SOURCES += \
- 19 main.cpp \
- 20 mainwindow.cpp
- 21
- 22 HEADERS += \
- 23 mainwindow.h
- 24
- 25 # Default rules for deployment.
- 26 qnx: target.path = /tmp/${TARGET}/bin
- 27 else: unix:!android: target.path = /opt/${TARGET}/bin
- 28 !isEmpty(target.path): INSTALLS += target
复制代码在头文件“mainwindow.h”具体代码如下。 头文件里主要是声明界面用的元素,及一些槽函数。重点是声明tcpSocket。 在源文件“mainwindow.cpp”具体代码如下。 - mainwindow.cpp编程后的代码
- /******************************************************************
- Copyright © Deng Zhimao Co., Ltd. 1990-2021. All rights reserved.
- * @projectName 09_tcpclient
- * @brief mainwindow.cpp
- * @author Deng Zhimao
- * @email 1252699831@qq.com
- * @net www.openedv.com
- * @date 2021-04-13
- *******************************************************************/
- 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<QNetworkInterface> list
- 202 = QNetworkInterface::allInterfaces();
- 203
- 204 /* 遍历list */
- 205 foreach (QNetworkInterface interface, list) {
- 206
- 207 /* QNetworkAddressEntry类存储IP地址子网掩码和广播地址 */
- 208 QList<QNetworkAddressEntry> 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发送消息。注意发送消息和接收消息都是通过tcpSocket的read()和write()进行。
11.2.4 程序运行效果开启服务端后,需要选择本地监听的IP地址和监听的端口(特别需要注意,不要选择监听的端口与本地主机的已经使用的端口,所以编者把端口号设置的特别大,查看本地已经使用的端口号可以使用netstat指令。) 启动客户端后,选择需要连接的服务器IP地址和服务器监听的端口。点击连接后就可以相互发送消息了。 注意服务端和客户端都本例都是选择了本地环回IP 127.0.0.1测试。也可以选择本地的其他IP地址进行测试。 TCP服务端:
TCP客户端:
|