目录
网络模块介绍
TCP介绍
TCP 服务端应用实例
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 
 
 
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>
#include <QNetworkInterface>
#include <QDebug>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
    Q_OBJECT
public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
private:
    Ui::Widget *ui;
    /* tcp 服务器 */
    QTcpServer *tcpServer;
    /* 通信套接字 */
    QTcpSocket *tcpSocket;
    /* 存储本地的 ip 列表地址 */
    QList<QHostAddress> IPlist;
    /* 获取本地的所有 ip */
    void getLocalHostIP();
private slots:
    /* 客户端连接处理槽函数 */
    void clientConnected();
    /* 开始监听槽函数 */
    void startListen();
    /* 停止监听槽函数 */
    void stopListen();
    /* 清除文本框时的内容 */
    void clearTextBrowser();
    /* 接收到消息 */
    void receiveMessages();
    /* 发送消息 */
    void sendMessages();
    /* 连接状态改变槽函数 */
    void socketStateChange(QAbstractSocket::SocketState);
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    tcpServer = new QTcpServer(this);
    tcpSocket = new QTcpSocket(this);
    ui->spinBox->setRange(10000, 99999);
    ui->pushButton_5->setEnabled(false);
    getLocalHostIP();
    /* 信号槽连接 */
    connect(ui->pushButton, SIGNAL(clicked()),this, SLOT(startListen()));
    connect(ui->pushButton_5, SIGNAL(clicked()),this, SLOT(stopListen()));
    connect(ui->pushButton_6, SIGNAL(clicked()),this, SLOT(clearTextBrowser()));
    connect(ui->pushButton_4, SIGNAL(clicked()),this, SLOT(sendMessages()));
    connect(tcpServer, SIGNAL(newConnection()),this, SLOT(clientConnected()));
}
Widget::~Widget()
{
    delete ui;
}
/* 新的客户端连接 */
void Widget::clientConnected()
{
    /* 获取客户端的套接字 */
    tcpSocket = tcpServer->nextPendingConnection();
    /* 客户端的 ip 信息 */
    QString ip = tcpSocket->peerAddress().toString();
    /* 客户端的端口信息 */
    quint16 port = tcpSocket->peerPort();
    /* 在文本浏览框里显示出客户端的连接信息 */
    ui->textBrowser->append("客户端已连接");
    ui->textBrowser->append("客户端 ip 地址:" + ip);
    ui->textBrowser->append("客户端端口:" + QString::number(port));
    
    connect(tcpSocket, SIGNAL(readyRead()),this, SLOT(receiveMessages()));
    connect(tcpSocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),this,
            SLOT(socketStateChange(QAbstractSocket::SocketState)));
}
void Widget::getLocalHostIP()
{
    QList<QNetworkInterface> list= QNetworkInterface::allInterfaces();
 
    /* 遍历 list */
    foreach (QNetworkInterface interface, list) {
 
        /* QNetworkAddressEntry 类存储 IP 地址子网掩码和广播地址 */
        QList<QNetworkAddressEntry> entryList= interface.addressEntries();
   
        /* 遍历 entryList */
        foreach (QNetworkAddressEntry entry, entryList) {
            /* 过滤 IPv6 地址,只留下 IPv4 */
            if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol) {
            
                ui->comboBox->addItem(entry.ip().toString());
                /* 添加到 IP 列表中 */
                IPlist<<entry.ip();
             }
        }
     }
}
/* 开始监听槽函数 */
void Widget::startListen()
{
    /* 需要判断当前主机是否有IP项 */
    if (ui->comboBox->currentIndex() != -1) {
        qDebug()<<"start listen"<<endl;
        tcpServer->listen(IPlist[ui->comboBox->currentIndex()],ui->spinBox->value());
        /* 设置按钮与下拉列表框的状态 */
        ui->pushButton->setEnabled(false);
        ui->pushButton_5->setEnabled(true);
        ui->comboBox->setEnabled(false);
        ui->spinBox->setEnabled(false);
        /* 在文本浏览框里显示出服务端 */
        ui->textBrowser->append("服务器IP地址:"+ ui->comboBox->currentText());
        ui->textBrowser->append("正在监听端口:"+ ui->spinBox->text());
    }
}
/* 停止监听槽函数 */
void Widget::stopListen()
{
    qDebug()<<"stop listen"<<endl;
    /* 停止监听 */
    tcpServer->close();
    /* 如果是连接上了也应该断开,如果不断开客户端还能继续发送信息,
     * 因为socket未断开,还在监听上一次端口 */
    if (tcpSocket->state() == tcpSocket->ConnectedState)
        tcpSocket->disconnectFromHost();
    /* 设置按钮与下拉列表框的状态  */
    ui->pushButton_5->setEnabled(false);
    ui->pushButton->setEnabled(true);
    ui->comboBox->setEnabled(true);
    ui->spinBox->setEnabled(true);
    /* 将停止监听的信息添加到文本浏览框中 */
    ui->textBrowser->append("已停止监听端口:" + ui->spinBox->text());
}
/* 清除文本框时的内容 */
void Widget::clearTextBrowser()
{
    /* 清除文本浏览器的内容 */
    ui->textBrowser->clear();
}
 /* 接收到消息 */
void Widget::receiveMessages()
{
    /* 读取接收到的消息 */
    QString messages = "客户端:" + tcpSocket->readAll();
    ui->textBrowser->append(messages);
}
/* 发送消息 */
void Widget::sendMessages()
{
    QList <QTcpSocket *> socketList=tcpServer->findChildren<QTcpSocket *>();
    qDebug()<<"tcpSocket 数量: "<<socketList.count()<<endl;
    if(socketList.count()== 0){
        ui->textBrowser->append("请先与客户端连接!");
        return;
    }
    foreach(QTcpSocket *tmpTcpSocket,socketList){
        tmpTcpSocket->write(ui->lineEdit->text().toUtf8());
    }
    ui->textBrowser->append("服务端 "+ui->lineEdit->text());
}
/* 连接状态改变槽函数 */
void Widget::socketStateChange(QAbstractSocket::SocketState state)
{
    switch (state) {
    case QAbstractSocket::UnconnectedState:
        ui->textBrowser->append("scoket状态:客户端断开连接");
        tcpSocket->deleteLater();
        break;
    case QAbstractSocket::ConnectedState:
        ui->textBrowser->append("scoket状态:客户端已连接");
        break;
    case QAbstractSocket::ConnectingState:
        ui->textBrowser->append("scoket状态:ConnectingState");
        break;
    case QAbstractSocket::HostLookupState:
        ui->textBrowser->append("scoket状态:HostLookupState");
        break;
    case QAbstractSocket::ClosingState:
        ui->textBrowser->append("scoket状态:ClosingState");
        break;
    case QAbstractSocket::ListeningState:
        ui->textBrowser->append("scoket状态:ListeningState");
        break;
    case QAbstractSocket::BoundState:
        ui->textBrowser->append("scoket状态:BoundState");
        break;
    default:
        break;
    }
}

TCP 客户端应用实例
 
  本例大体流程:  
 
 
  
  首先获取本地  
  IP  
  地址。创建一个  
  tcpSocket  
  套接字,然后用  
  tcpSocket  
  套接字使用  
  connectToHost 函数连接服务端的主机 IP  
  地址和端口,即可相互通信。 
 
 
  
 widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>
#include <QNetworkInterface>
#include <QDebug>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
    Q_OBJECT
public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
private:
    Ui::Widget *ui;
    /* 通信套接字 */
    QTcpSocket *tcpSocket;
    /* 存储本地的ip列表地址 */
    QList<QHostAddress> IPlist;
    /* 获取本地的所有ip */
    void getLocalHostIP();
private slots:
    /* 连接 */
    void toConnect();
    /* 断开连接 */
    void toDisConnect();
    /* 已连接 */
    void connected();
    /* 已断开连接 */
    void disconnected();
    /* 清除文本框时的内容 */
    void clearTextBrowser();
    /* 接收到消息 */
    void receiveMessages();
    /* 发送消息 */
    void sendMessages();
    /* 连接状态改变槽函数 */
    void socketStateChange(QAbstractSocket::SocketState);
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    /* tcp套接字 */
    tcpSocket = new QTcpSocket(this);
    /* 设置端口号的范围,注意不要与主机的已使用的端口号冲突 */
    ui->spinBox->setRange(10000, 99999);
    /* 设置断开连接状态不可用 */
    ui->pushButton_2->setEnabled(false);
    /* 获取本地 ip */
    getLocalHostIP();
    /* 信号槽连接 */
    connect(ui->pushButton, SIGNAL(clicked()),this, SLOT(toConnect()));
    connect(ui->pushButton_2, SIGNAL(clicked()),this, SLOT(toDisConnect()));
    connect(ui->pushButton_3, SIGNAL(clicked()),this, SLOT(clearTextBrowser()));
    connect(ui->pushButton_4, SIGNAL(clicked()),this, SLOT(sendMessages()));
    connect(tcpSocket, SIGNAL(connected()),this, SLOT(connected()));
    connect(tcpSocket, SIGNAL(disconnected()),this, SLOT(disconnected()));
    connect(tcpSocket, SIGNAL(readyRead()),this, SLOT(receiveMessages()));
    connect(tcpSocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),this,
           SLOT(socketStateChange(QAbstractSocket::SocketState)));
}
Widget::~Widget()
{
    delete ui;
}
void Widget::toConnect()
{
    /* 如果连接状态还没有连接 */
    if (tcpSocket->state() != tcpSocket->ConnectedState) {
        /* 指定IP地址和端口连接 */
        tcpSocket->connectToHost(IPlist[ui->comboBox->currentIndex()],ui->spinBox->value());
    }
}
void Widget::toDisConnect()
{
    /* 断开连接 */
    tcpSocket->disconnectFromHost();
    /* 关闭socket*/
    tcpSocket->close();
}
void Widget::connected()
{
    /* 显示已经连接 */
    ui->textBrowser->append("已经连上服务端");
    /* 设置按钮与下拉列表框的状态 */
    ui->pushButton->setEnabled(false);
    ui->pushButton_2->setEnabled(true);
    ui->comboBox->setEnabled(false);
    ui->spinBox->setEnabled(false);
}
void Widget::disconnected()
{
    /* 显示已经断开连接 */
    ui->textBrowser->append("已经断开服务端");
    /* 设置按钮与下拉列表框的状态  */
    ui->pushButton_2->setEnabled(false);
    ui->pushButton->setEnabled(true);
    ui->comboBox->setEnabled(true);
    ui->spinBox->setEnabled(true);
}
/* 获取本地IP */
void Widget::getLocalHostIP()
{
    // /* 获取主机的名称 */
    // QString hostName = QHostInfo::localHostName();
    // /* 主机的信息 */
    // QHostInfo hostInfo = QHostInfo::fromName(hostName);
    // /* ip列表,addresses返回ip地址列表,注意主机应能从路由器获取到
    // * IP,否则可能返回空的列表(ubuntu用此方法只能获取到环回IP) */
    // IPlist = hostInfo.addresses();
    // qDebug()<<IPlist<<endl;
    // /* 遍历IPlist */
    // foreach (QHostAddress ip, IPlist) {
    //      if (ip.protocol() == QAbstractSocket::IPv4Protocol)
    //          comboBox->addItem(ip.toString());
    //    }
    /* 获取所有的网络接口,
     * QNetworkInterface类提供主机的IP地址和网络接口的列表 */
    QList<QNetworkInterface> list = QNetworkInterface::allInterfaces();
    /* 遍历list */
    foreach (QNetworkInterface interface, list) {
        /* QNetworkAddressEntry类存储IP地址子网掩码和广播地址 */
        QList<QNetworkAddressEntry> entryList = interface.addressEntries();
        /* 遍历entryList */
        foreach (QNetworkAddressEntry entry, entryList) {
            /* 过滤IPv6地址,只留下IPv4 */
            if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol) {
                ui->comboBox->addItem(entry.ip().toString());
                /* 添加到IP列表中 */
                IPlist<<entry.ip();
            }
        }
    }
}
/* 清除文本浏览框里的内容 */
void Widget::clearTextBrowser()
{
    /* 清除文本浏览器的内容 */
    ui->textBrowser->clear();
}
/* 客户端接收消息 */
void Widget::receiveMessages()
{
    /* 读取接收到的消息 */
    QString messages = tcpSocket->readAll();
    ui->textBrowser->append("服务端:" + messages);
}
/* 客户端发送消息 */
void Widget::sendMessages()
{
    if(NULL == tcpSocket)
        return;
    if(tcpSocket->state() == tcpSocket->ConnectedState) {
        /* 客户端显示发送的消息 */
        ui->textBrowser->append("客户端:" + ui->lineEdit->text());
        /* 发送消息 */
        tcpSocket->write(ui->lineEdit->text().toUtf8().data());
    }
}
/* 客户端状态改变 */
void Widget::socketStateChange(QAbstractSocket::SocketState state)
{
    switch (state) {
    case QAbstractSocket::UnconnectedState:
        ui->textBrowser->append("scoket状态:与服务端未连接");
        tcpSocket->deleteLater();
        break;
    case QAbstractSocket::ConnectedState:
        ui->textBrowser->append("scoket状态:与服务端已连接");
        break;
    case QAbstractSocket::ConnectingState:
        ui->textBrowser->append("scoket状态:ConnectingState");
        break;
    case QAbstractSocket::HostLookupState:
        ui->textBrowser->append("scoket状态:HostLookupState");
        break;
    case QAbstractSocket::ClosingState:
        ui->textBrowser->append("scoket状态:ClosingState");
        break;
    case QAbstractSocket::ListeningState:
        ui->textBrowser->append("scoket状态:ListeningState");
        break;
    case QAbstractSocket::BoundState:
        ui->textBrowser->append("scoket状态:BoundState");
        break;
    default:
        break;
    }
}

运行结果:
 
 



















