QTcpSocket、QTcpServer实现TCP通信

1、主机信息查询

查询一个主机的MAC地址和IP地址是网络应用程序中经常用到的功能,Qt提供了QHostInfo和QNetworkInterface类用于此类信息的查询。

QHostInfo类

  • localHostName()可获取本机的主机名;
  • fromName()通过主机名获取IP地址;

QNetworkInterface类

  • allInterfaces返回主机上所有的网络接口列表(每个网络接口可能包含多个IP地址)
  • QList allInterfaces(); 返回主机上所有的IP地址的列表
  • QList allInterfaces(); 返回主机上所有的网络接口列表

2、TCP通信

TCP(Tansmission Control Protocol)是一种被大多数Internet网络协议(如HTTP或FTP)用于数据传输的低级网络协议,它是可靠地、面向流、面向连接的传输协议,特别适合用于连续数据传输

TCP通信必须先建立TCP连接,通信分为客户端和服务器端。Qt提供QTcpSocket类和QTcpServer类用于建立TCP通信应用程序。服务器端程序必须使用QTcpServer用于端口监听,建立服务器;QTcpSocket用于建立连接后使用套接字进行通信

下面的例子实现:服务器端一直监听端口,一旦有客户端连接请求到达,便建立连接,连接建立好后向客户端发送一个字符串,客户端收到该字符串并显示出来

服务器端
server.h

#ifndef SERVER_H
#define SERVER_H
 
#include 
class QTcpServer;
 
namespace Ui {
class Server;
}
 
class Server : public QDialog
{
    Q_OBJECT
 
public:
    explicit Server(QWidget *parent = 0);
    ~Server();
 
private:
    Ui::Server *ui;
    QTcpServer *tcpServer;
 
private slots:
    void sendMessage(); 
};
 
#endif // SERVER_H

server.cpp

#include "server.h"
#include "ui_server.h"
#include 
 
Server::Server(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Server)
{
    ui->setupUi(this);
 
    tcpServer = new QTcpServer(this);
    // 使用了IPv4的本地主机地址,等价于QHostAddress("127.0.0.1")
    // 服务器端首先要用listen开始服务器监听,可指定监听的IP地址和端口,一般一个服务器程序只监听某个端口的网络连接
    if (!tcpServer->listen(QHostAddress::LocalHost, 6666)) 
    {
        qDebug() << tcpServer->errorString();
        close();
    }
    // 当有新的客户端接入时,QTcpServer内部会创建一个与客户端链接的QTcpServer对象,然后发射newConnection()信号
    connect(tcpServer, &QTcpServer::newConnection,this, &Server::sendMessage);
}
 
Server::~Server()
{
    delete ui;
}
 
void Server::sendMessage()
{
    // 用于暂存要发送的数据
    QByteArray block;
    QDataStream out(&block, QIODevice::WriteOnly);
 
    // 设置数据流的版本,客户端和服务器端使用的版本要相同
    out.setVersion(QDataStream::Qt_5_6);
    out << (quint16)0;
    out << tr("hello TCP!!!");
    out.device()->seek(0);
    out << (quint16)(block.size() - sizeof(quint16));
 
    // 获取已经建立的连接的套接字
    // 用nextPendingConnection接受客户端的连接,然后使用QTcpSocket与客户端通信
    QTcpSocket *clientConnection = tcpServer->nextPendingConnection();
    connect(clientConnection, &QTcpSocket::disconnected,clientConnection,&QTcpSocket::deleteLater);
    clientConnection->write(block);
    clientConnection->disconnectFromHost();
 
    // 发送数据成功后,显示提示
    ui->label->setText(tr("发送数据成功!!!"));
}

客户端
client.h

#ifndef CLIENT_H
#define CLIENT_H
 
#include 
#include 
class QTcpSocket;
 
namespace Ui {
class Client;
}
 
class Client : public QDialog
{
    Q_OBJECT
 
public:
    explicit Client(QWidget *parent = 0);
    ~Client();
 
private:
    Ui::Client *ui;
    QTcpSocket *tcpSocket;
    QString message;
    // 用来存放数据的大小信息
    quint16 blockSize;
 
private slots:
    void newConnect();
    void readMessage();
    void displayError(QAbstractSocket::SocketError);
 
 
    void on_connectButton_clicked();
};
 
#endif // CLIENT_H

client.cpp

#include "client.h"
#include "ui_client.h"
#include 
 
Client::Client(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Client)
{
    ui->setupUi(this);
 
    tcpSocket = new QTcpSocket(this);
    connect(tcpSocket, &QTcpSocket::readyRead, this, &Client::readMessage);
    connect(tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)),
            this, SLOT(displayError(QAbstractSocket::SocketError)));
 
}
 
Client::~Client()
{
    delete ui;
}
 
void Client::newConnect()
{
    // 初始化数据大小信息为0
    blockSize = 0;
 
    // 取消已有的连接
    tcpSocket->abort();
    tcpSocket->connectToHost(ui->hostLineEdit->text(),
                             ui->portLineEdit->text().toInt());
}
 
void Client::readMessage()
{
    QDataStream in(tcpSocket);
    // 设置数据流版本,这里要和服务器端相同
    in.setVersion(QDataStream::Qt_5_6);
 
    // 如果是刚开始接收数据
    if (blockSize == 0) {
        //判断接收的数据是否大于两字节,也就是文件的大小信息所占的空间
        //如果是则保存到blockSize变量中,否则直接返回,继续接收数据
        if(tcpSocket->bytesAvailable() < (int)sizeof(quint16)) return;
        in >> blockSize;
    }
    // 如果没有得到全部的数据,则返回,继续接收数据
    if(tcpSocket->bytesAvailable() < blockSize) return;
    // 将接收到的数据存放到变量中
    in >> message;
    // 显示接收到的数据
    ui->messageLabel->setText(message);
}
 
void Client::displayError(QAbstractSocket::SocketError)
{
    qDebug() << tcpSocket->errorString();
}
 
void Client::on_connectButton_clicked()
{
    newConnect();
}

你可能感兴趣的:(Qt之美)