当前位置:   article > 正文

QTTCP客户端服务端通信_qt tcp 服务端

qt tcp 服务端
Qt 网络模块为我们提供了编写 TCP / IP 客户端和服务器的类。它提供了较低级别的类,例
如代表低级网络概念的 QTcpSocket QTcpServer QUdpSocket ,以及诸如 QNetworkRequest
QNetworkReply QNetworkAccessManager 之类的高级类来执行使用通用协议的网络操作。
还提供了诸如 QNetworkConfiguration QNetworkConfigurationManager QNetworkSession 等类,
实现承载管理。
想要在程序中使用 Qt 网络模块,我们需要在 pro 项目配置文件里增加下面的一条语句。
QT += network

TCP介绍

TCP 协议( Transmission Control Protocol )全称是传输控制协议是一种 面向连接的、可靠的、
基于字节流 的传输层通信协议。
TCP 通信必 须先建立 TCP 连接 ,通信端分为客户端和服务端。服务端通过监听某个端口
来监听是否有客户端连接到来,如果有连接到来,则建立新的 socket 连接;客户端通过 ip
port 连接服务端,当成功建立连接之后,就可进行数据的收发了。需要注意的是,在 Qt 中,
Qt socket 当成输入输出流来对待的,数据的收发是通过 read() write() 来进行的,需要与我
们常见的 send() recv() 进行区分。
TCP 客户端与服务端通信示意图如下。

 TCP 服务端应用实例

本例大体流程
首先获取本地 IP 地址。创建一个 tcpSocket 套接字,一个 tcpServer 服务端。点击监听即监听本
地的主机 IP 地址和端口,同时等待服务端的连接。此程序需要结合客户端一起使用,可实现多个客户端的传播。
widget.h
  1. #ifndef WIDGET_H
  2. #define WIDGET_H
  3. #include <QWidget>
  4. #include <QTcpServer>
  5. #include <QTcpSocket>
  6. #include <QNetworkInterface>
  7. #include <QDebug>
  8. QT_BEGIN_NAMESPACE
  9. namespace Ui { class Widget; }
  10. QT_END_NAMESPACE
  11. class Widget : public QWidget
  12. {
  13. Q_OBJECT
  14. public:
  15. Widget(QWidget *parent = nullptr);
  16. ~Widget();
  17. private:
  18. Ui::Widget *ui;
  19. /* tcp 服务器 */
  20. QTcpServer *tcpServer;
  21. /* 通信套接字 */
  22. QTcpSocket *tcpSocket;
  23. /* 存储本地的 ip 列表地址 */
  24. QList<QHostAddress> IPlist;
  25. /* 获取本地的所有 ip */
  26. void getLocalHostIP();
  27. private slots:
  28. /* 客户端连接处理槽函数 */
  29. void clientConnected();
  30. /* 开始监听槽函数 */
  31. void startListen();
  32. /* 停止监听槽函数 */
  33. void stopListen();
  34. /* 清除文本框时的内容 */
  35. void clearTextBrowser();
  36. /* 接收到消息 */
  37. void receiveMessages();
  38. /* 发送消息 */
  39. void sendMessages();
  40. /* 连接状态改变槽函数 */
  41. void socketStateChange(QAbstractSocket::SocketState);
  42. };
  43. #endif // WIDGET_H

widget.cpp

  1. #include "widget.h"
  2. #include "ui_widget.h"
  3. Widget::Widget(QWidget *parent)
  4. : QWidget(parent)
  5. , ui(new Ui::Widget)
  6. {
  7. ui->setupUi(this);
  8. tcpServer = new QTcpServer(this);
  9. tcpSocket = new QTcpSocket(this);
  10. ui->spinBox->setRange(10000, 99999);
  11. ui->pushButton_5->setEnabled(false);
  12. getLocalHostIP();
  13. /* 信号槽连接 */
  14. connect(ui->pushButton, SIGNAL(clicked()),this, SLOT(startListen()));
  15. connect(ui->pushButton_5, SIGNAL(clicked()),this, SLOT(stopListen()));
  16. connect(ui->pushButton_6, SIGNAL(clicked()),this, SLOT(clearTextBrowser()));
  17. connect(ui->pushButton_4, SIGNAL(clicked()),this, SLOT(sendMessages()));
  18. connect(tcpServer, SIGNAL(newConnection()),this, SLOT(clientConnected()));
  19. }
  20. Widget::~Widget()
  21. {
  22. delete ui;
  23. }
  24. /* 新的客户端连接 */
  25. void Widget::clientConnected()
  26. {
  27. /* 获取客户端的套接字 */
  28. tcpSocket = tcpServer->nextPendingConnection();
  29. /* 客户端的 ip 信息 */
  30. QString ip = tcpSocket->peerAddress().toString();
  31. /* 客户端的端口信息 */
  32. quint16 port = tcpSocket->peerPort();
  33. /* 在文本浏览框里显示出客户端的连接信息 */
  34. ui->textBrowser->append("客户端已连接");
  35. ui->textBrowser->append("客户端 ip 地址:" + ip);
  36. ui->textBrowser->append("客户端端口:" + QString::number(port));
  37. connect(tcpSocket, SIGNAL(readyRead()),this, SLOT(receiveMessages()));
  38. connect(tcpSocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),this,
  39. SLOT(socketStateChange(QAbstractSocket::SocketState)));
  40. }
  41. void Widget::getLocalHostIP()
  42. {
  43. QList<QNetworkInterface> list= QNetworkInterface::allInterfaces();
  44. /* 遍历 list */
  45. foreach (QNetworkInterface interface, list) {
  46. /* QNetworkAddressEntry 类存储 IP 地址子网掩码和广播地址 */
  47. QList<QNetworkAddressEntry> entryList= interface.addressEntries();
  48. /* 遍历 entryList */
  49. foreach (QNetworkAddressEntry entry, entryList) {
  50. /* 过滤 IPv6 地址,只留下 IPv4 */
  51. if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol) {
  52. ui->comboBox->addItem(entry.ip().toString());
  53. /* 添加到 IP 列表中 */
  54. IPlist<<entry.ip();
  55. }
  56. }
  57. }
  58. }
  59. /* 开始监听槽函数 */
  60. void Widget::startListen()
  61. {
  62. /* 需要判断当前主机是否有IP项 */
  63. if (ui->comboBox->currentIndex() != -1) {
  64. qDebug()<<"start listen"<<endl;
  65. tcpServer->listen(IPlist[ui->comboBox->currentIndex()],ui->spinBox->value());
  66. /* 设置按钮与下拉列表框的状态 */
  67. ui->pushButton->setEnabled(false);
  68. ui->pushButton_5->setEnabled(true);
  69. ui->comboBox->setEnabled(false);
  70. ui->spinBox->setEnabled(false);
  71. /* 在文本浏览框里显示出服务端 */
  72. ui->textBrowser->append("服务器IP地址:"+ ui->comboBox->currentText());
  73. ui->textBrowser->append("正在监听端口:"+ ui->spinBox->text());
  74. }
  75. }
  76. /* 停止监听槽函数 */
  77. void Widget::stopListen()
  78. {
  79. qDebug()<<"stop listen"<<endl;
  80. /* 停止监听 */
  81. tcpServer->close();
  82. /* 如果是连接上了也应该断开,如果不断开客户端还能继续发送信息,
  83. * 因为socket未断开,还在监听上一次端口 */
  84. if (tcpSocket->state() == tcpSocket->ConnectedState)
  85. tcpSocket->disconnectFromHost();
  86. /* 设置按钮与下拉列表框的状态 */
  87. ui->pushButton_5->setEnabled(false);
  88. ui->pushButton->setEnabled(true);
  89. ui->comboBox->setEnabled(true);
  90. ui->spinBox->setEnabled(true);
  91. /* 将停止监听的信息添加到文本浏览框中 */
  92. ui->textBrowser->append("已停止监听端口:" + ui->spinBox->text());
  93. }
  94. /* 清除文本框时的内容 */
  95. void Widget::clearTextBrowser()
  96. {
  97. /* 清除文本浏览器的内容 */
  98. ui->textBrowser->clear();
  99. }
  100. /* 接收到消息 */
  101. void Widget::receiveMessages()
  102. {
  103. /* 读取接收到的消息 */
  104. QString messages = "客户端:" + tcpSocket->readAll();
  105. ui->textBrowser->append(messages);
  106. }
  107. /* 发送消息 */
  108. void Widget::sendMessages()
  109. {
  110. QList <QTcpSocket *> socketList=tcpServer->findChildren<QTcpSocket *>();
  111. qDebug()<<"tcpSocket 数量: "<<socketList.count()<<endl;
  112. if(socketList.count()== 0){
  113. ui->textBrowser->append("请先与客户端连接!");
  114. return;
  115. }
  116. foreach(QTcpSocket *tmpTcpSocket,socketList){
  117. tmpTcpSocket->write(ui->lineEdit->text().toUtf8());
  118. }
  119. ui->textBrowser->append("服务端 "+ui->lineEdit->text());
  120. }
  121. /* 连接状态改变槽函数 */
  122. void Widget::socketStateChange(QAbstractSocket::SocketState state)
  123. {
  124. switch (state) {
  125. case QAbstractSocket::UnconnectedState:
  126. ui->textBrowser->append("scoket状态:客户端断开连接");
  127. tcpSocket->deleteLater();
  128. break;
  129. case QAbstractSocket::ConnectedState:
  130. ui->textBrowser->append("scoket状态:客户端已连接");
  131. break;
  132. case QAbstractSocket::ConnectingState:
  133. ui->textBrowser->append("scoket状态:ConnectingState");
  134. break;
  135. case QAbstractSocket::HostLookupState:
  136. ui->textBrowser->append("scoket状态:HostLookupState");
  137. break;
  138. case QAbstractSocket::ClosingState:
  139. ui->textBrowser->append("scoket状态:ClosingState");
  140. break;
  141. case QAbstractSocket::ListeningState:
  142. ui->textBrowser->append("scoket状态:ListeningState");
  143. break;
  144. case QAbstractSocket::BoundState:
  145. ui->textBrowser->append("scoket状态:BoundState");
  146. break;
  147. default:
  148. break;
  149. }
  150. }

 TCP 客户端应用实例

本例大体流程:
首先获取本地 IP 地址。创建一个 tcpSocket 套接字,然后用 tcpSocket 套接字使用 connectToHost 函数连接服务端的主机 IP 地址和端口,即可相互通信。

 widget.h

  1. #ifndef WIDGET_H
  2. #define WIDGET_H
  3. #include <QWidget>
  4. #include <QTcpServer>
  5. #include <QTcpSocket>
  6. #include <QNetworkInterface>
  7. #include <QDebug>
  8. QT_BEGIN_NAMESPACE
  9. namespace Ui { class Widget; }
  10. QT_END_NAMESPACE
  11. class Widget : public QWidget
  12. {
  13. Q_OBJECT
  14. public:
  15. Widget(QWidget *parent = nullptr);
  16. ~Widget();
  17. private:
  18. Ui::Widget *ui;
  19. /* 通信套接字 */
  20. QTcpSocket *tcpSocket;
  21. /* 存储本地的ip列表地址 */
  22. QList<QHostAddress> IPlist;
  23. /* 获取本地的所有ip */
  24. void getLocalHostIP();
  25. private slots:
  26. /* 连接 */
  27. void toConnect();
  28. /* 断开连接 */
  29. void toDisConnect();
  30. /* 已连接 */
  31. void connected();
  32. /* 已断开连接 */
  33. void disconnected();
  34. /* 清除文本框时的内容 */
  35. void clearTextBrowser();
  36. /* 接收到消息 */
  37. void receiveMessages();
  38. /* 发送消息 */
  39. void sendMessages();
  40. /* 连接状态改变槽函数 */
  41. void socketStateChange(QAbstractSocket::SocketState);
  42. };
  43. #endif // WIDGET_H

widget.cpp

  1. #include "widget.h"
  2. #include "ui_widget.h"
  3. Widget::Widget(QWidget *parent)
  4. : QWidget(parent)
  5. , ui(new Ui::Widget)
  6. {
  7. ui->setupUi(this);
  8. /* tcp套接字 */
  9. tcpSocket = new QTcpSocket(this);
  10. /* 设置端口号的范围,注意不要与主机的已使用的端口号冲突 */
  11. ui->spinBox->setRange(10000, 99999);
  12. /* 设置断开连接状态不可用 */
  13. ui->pushButton_2->setEnabled(false);
  14. /* 获取本地 ip */
  15. getLocalHostIP();
  16. /* 信号槽连接 */
  17. connect(ui->pushButton, SIGNAL(clicked()),this, SLOT(toConnect()));
  18. connect(ui->pushButton_2, SIGNAL(clicked()),this, SLOT(toDisConnect()));
  19. connect(ui->pushButton_3, SIGNAL(clicked()),this, SLOT(clearTextBrowser()));
  20. connect(ui->pushButton_4, SIGNAL(clicked()),this, SLOT(sendMessages()));
  21. connect(tcpSocket, SIGNAL(connected()),this, SLOT(connected()));
  22. connect(tcpSocket, SIGNAL(disconnected()),this, SLOT(disconnected()));
  23. connect(tcpSocket, SIGNAL(readyRead()),this, SLOT(receiveMessages()));
  24. connect(tcpSocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),this,
  25. SLOT(socketStateChange(QAbstractSocket::SocketState)));
  26. }
  27. Widget::~Widget()
  28. {
  29. delete ui;
  30. }
  31. void Widget::toConnect()
  32. {
  33. /* 如果连接状态还没有连接 */
  34. if (tcpSocket->state() != tcpSocket->ConnectedState) {
  35. /* 指定IP地址和端口连接 */
  36. tcpSocket->connectToHost(IPlist[ui->comboBox->currentIndex()],ui->spinBox->value());
  37. }
  38. }
  39. void Widget::toDisConnect()
  40. {
  41. /* 断开连接 */
  42. tcpSocket->disconnectFromHost();
  43. /* 关闭socket*/
  44. tcpSocket->close();
  45. }
  46. void Widget::connected()
  47. {
  48. /* 显示已经连接 */
  49. ui->textBrowser->append("已经连上服务端");
  50. /* 设置按钮与下拉列表框的状态 */
  51. ui->pushButton->setEnabled(false);
  52. ui->pushButton_2->setEnabled(true);
  53. ui->comboBox->setEnabled(false);
  54. ui->spinBox->setEnabled(false);
  55. }
  56. void Widget::disconnected()
  57. {
  58. /* 显示已经断开连接 */
  59. ui->textBrowser->append("已经断开服务端");
  60. /* 设置按钮与下拉列表框的状态 */
  61. ui->pushButton_2->setEnabled(false);
  62. ui->pushButton->setEnabled(true);
  63. ui->comboBox->setEnabled(true);
  64. ui->spinBox->setEnabled(true);
  65. }
  66. /* 获取本地IP */
  67. void Widget::getLocalHostIP()
  68. {
  69. // /* 获取主机的名称 */
  70. // QString hostName = QHostInfo::localHostName();
  71. // /* 主机的信息 */
  72. // QHostInfo hostInfo = QHostInfo::fromName(hostName);
  73. // /* ip列表,addresses返回ip地址列表,注意主机应能从路由器获取到
  74. // * IP,否则可能返回空的列表(ubuntu用此方法只能获取到环回IP) */
  75. // IPlist = hostInfo.addresses();
  76. // qDebug()<<IPlist<<endl;
  77. // /* 遍历IPlist */
  78. // foreach (QHostAddress ip, IPlist) {
  79. // if (ip.protocol() == QAbstractSocket::IPv4Protocol)
  80. // comboBox->addItem(ip.toString());
  81. // }
  82. /* 获取所有的网络接口,
  83. * QNetworkInterface类提供主机的IP地址和网络接口的列表 */
  84. QList<QNetworkInterface> list = QNetworkInterface::allInterfaces();
  85. /* 遍历list */
  86. foreach (QNetworkInterface interface, list) {
  87. /* QNetworkAddressEntry类存储IP地址子网掩码和广播地址 */
  88. QList<QNetworkAddressEntry> entryList = interface.addressEntries();
  89. /* 遍历entryList */
  90. foreach (QNetworkAddressEntry entry, entryList) {
  91. /* 过滤IPv6地址,只留下IPv4 */
  92. if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol) {
  93. ui->comboBox->addItem(entry.ip().toString());
  94. /* 添加到IP列表中 */
  95. IPlist<<entry.ip();
  96. }
  97. }
  98. }
  99. }
  100. /* 清除文本浏览框里的内容 */
  101. void Widget::clearTextBrowser()
  102. {
  103. /* 清除文本浏览器的内容 */
  104. ui->textBrowser->clear();
  105. }
  106. /* 客户端接收消息 */
  107. void Widget::receiveMessages()
  108. {
  109. /* 读取接收到的消息 */
  110. QString messages = tcpSocket->readAll();
  111. ui->textBrowser->append("服务端:" + messages);
  112. }
  113. /* 客户端发送消息 */
  114. void Widget::sendMessages()
  115. {
  116. if(NULL == tcpSocket)
  117. return;
  118. if(tcpSocket->state() == tcpSocket->ConnectedState) {
  119. /* 客户端显示发送的消息 */
  120. ui->textBrowser->append("客户端:" + ui->lineEdit->text());
  121. /* 发送消息 */
  122. tcpSocket->write(ui->lineEdit->text().toUtf8().data());
  123. }
  124. }
  125. /* 客户端状态改变 */
  126. void Widget::socketStateChange(QAbstractSocket::SocketState state)
  127. {
  128. switch (state) {
  129. case QAbstractSocket::UnconnectedState:
  130. ui->textBrowser->append("scoket状态:与服务端未连接");
  131. tcpSocket->deleteLater();
  132. break;
  133. case QAbstractSocket::ConnectedState:
  134. ui->textBrowser->append("scoket状态:与服务端已连接");
  135. break;
  136. case QAbstractSocket::ConnectingState:
  137. ui->textBrowser->append("scoket状态:ConnectingState");
  138. break;
  139. case QAbstractSocket::HostLookupState:
  140. ui->textBrowser->append("scoket状态:HostLookupState");
  141. break;
  142. case QAbstractSocket::ClosingState:
  143. ui->textBrowser->append("scoket状态:ClosingState");
  144. break;
  145. case QAbstractSocket::ListeningState:
  146. ui->textBrowser->append("scoket状态:ListeningState");
  147. break;
  148. case QAbstractSocket::BoundState:
  149. ui->textBrowser->append("scoket状态:BoundState");
  150. break;
  151. default:
  152. break;
  153. }
  154. }

运行结果:

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/704255
推荐阅读
相关标签
  

闽ICP备14008679号