> 文章列表 > QT里的网络通信简介

QT里的网络通信简介

QT里的网络通信简介

QTcpSocket类简介

QTcpSocket类提供了一个TCP套接字。TCP(传输控制协议)是一种可靠的、面向流的、面向连接的传输协议。它特别适合数据的连续传输。QTcpSocket是QAbstractSocket的一个子类,它允许您建立TCP连接和传输数据流。有关详细信息,请参阅QAbstractSocket文档。(注意:不能在QIODevice::Unbuffered模式下打开TCP套接字。)

header:#include
qmake: QT += network
Inherits: QAbstractSocket
Inherited By: QSctpSocket and QSslSocket

公共函数:(继承的比较多,下面就介绍它自己的以及QAbstractSocket里的)

QTcpSocket(QObject *parent = nullptr)
//创建状态为UnconnectedState的QTcpSocket对象。
virtual  ~QTcpSocket()
//销毁套接字,必要时关闭连接。
QAbstractSocket(QAbstractSocket::SocketType socketType, QObject *parent)
//创建类型为SocketType的新抽象套接字。
virtual  ~QAbstractSocket()
//销毁套接字
void  abort()
//中止当前连接并重置套接字。与disconnectFromHost()不同,此函数会立即关闭套接字,丢弃写缓冲区中的任何挂起数据。
bool  bind(const QHostAddress &address, quint16 port = 0, QAbstractSocket::BindMode mode = DefaultForPlatform)
//使用绑定模式绑定到端口端口上的地址。
//对于UDP套接字,绑定后,每当UDP数据报到达指定的地址和端口时,就会发出信号QUdpSocket::readyRead()。因此,此函数对于写入UDP服务器很有用。
//对于TCP套接字,此函数可用于指定用于传出连接的接口,这在多个网络接口的情况下很有用。
//默认情况下,套接字是使用DefaultForPlatform绑定模式绑定的。如果未指定端口,则会选择一个随机端口。
//成功后,函数返回true,套接字进入BoundState;否则返回false。此功能在Qt 5.0中引入。
bool  bind(quint16 port = 0, QAbstractSocket::BindMode mode = DefaultForPlatform)
//这是一个重载函数。
//绑定到QHostAddress:任何端口上的端口,使用BindMode模式。
//默认情况下,套接字是使用DefaultForPlatform绑定模式绑定的。如果未指定端口,则会选择一个随机端口。
virtual void connectToHost(const QString &hostName, quint16 port, QIODevice::OpenMode openMode = ReadWrite, QAbstractSocket::NetworkLayerProtocolprotocol = AnyIPProtocol)
//尝试连接到给定端口上的hostName。协议参数可用于指定要使用的网络协议(例如IPv4或IPv6)。
//套接字在给定的openMode中打开,首先进入HostLookupState,然后执行hostName的主机名查找。如果查找成功,将发出hostFound(),并且QAbstractSocket将进入ConnectingState。然后,它尝试连接到查找返回的一个或多个地址。最后,如果建立了连接,QAbstractSocket将进入ConnectedState并发出connected()。
//在任何时候,套接字都可以发出error()来发出发生错误的信号。
//hostName可以是字符串形式的IP地址(例如“43.195.83.32”),也可以是主机名(例如“example.com”)。只有在需要时,x才会进行查找。端口按本机字节顺序排列。
virtual void connectToHost(const QHostAddress &address, quint16 port, QIODevice::OpenMode openMode = ReadWrite)
//这是一个重载函数。尝试连接到端口端口上的地址。
virtual void disconnectFromHost()
//试图关闭套接字。如果有挂起的数据等待写入,QAbstractSocket将进入ClosingState并等待,直到所有数据都已写入。最终,它将进入UnconnectedState并发出disconnected()信号。
QAbstractSocket::SocketError error() const
//返回上次发生的错误类型。
bool flush()
//此函数在不阻塞的情况下,尽可能多地从内部写入缓冲区写入底层网络套接字。如果写入了任何数据,此函数将返回true;否则返回false。
//如果需要QAbstractSocket立即开始发送缓冲数据,请调用此函数。成功写入的字节数取决于操作系统。在大多数情况下,您不需要调用此函数,因为一旦控制返回到事件循环,QAbstractSocket将自动开始发送数据。如果没有事件循环,请改为调用waitForBytesWritten()。
bool isValid() const
//如果套接字有效并且可以使用,则返回true;否则返回false。
//注意:在进行读取和写入之前,套接字的状态必须为ConnectedState。
QHostAddress  localAddress() const
//返回本地套接字的主机地址(如果可用);否则返回QHostAddress::Null。
//这通常是主机的主IP地址,但对于连接到本地主机,可以是QHostAddress::LocalHost(127.0.0.1)。
quint16 localPort() const
//返回本地套接字的主机端口号(按本机字节顺序)(如果可用);否则返回0。
QAbstractSocket::PauseModes pauseMode() const
//返回此套接字的暂停模式。此功能在Qt 5.0中引入。
QHostAddress peerAddress() const
//如果套接字处于ConnectedState,则返回连接的对等方的地址;否则返回QHostAddress::Null。
QString peerName() const
//返回由connectToHost()指定的对等方的名称,如果尚未调用connectToHost(),则返回空的QString。
quint16 peerPort() const
//如果套接字处于ConnectedState,则返回已连接对等端的端口;否则返回0。
QNetworkProxy proxy() const
//返回此套接字的网络代理。默认情况下,使用QNetworkProxy::DefaultProxy,这意味着此套接字将查询应用程序的默认代理设置。此功能在Qt 4.1中引入。
qint64 readBufferSize() const
//返回内部读取缓冲区的大小。这限制了客户端在调用read()或readAll()之前可以接收的数据量。
//读取缓冲区大小为0(默认值)意味着缓冲区没有大小限制,确保不会丢失任何数据。
virtual void resume()
//在套接字上继续数据传输。只有在套接字设置为在收到通知时暂停并且收到通知后,才应使用此方法。当前支持的唯一通知是QSslSocket::sslErrors()。如果套接字未暂停,则调用此方法会导致未定义的行为。此功能在Qt 5.0中引入。
void setPauseMode(QAbstractSocket::PauseModes pauseMode)
//控制是否在收到通知时暂停。pauseMode参数指定套接字应该暂停的条件。当前支持的唯一通知是QSslSocket::sslErrors()。如果设置为PauseOnslErrors,套接字上的数据传输将暂停,并且需要通过调用resume()再次显式启用。默认情况下,此选项设置为PauseNever。在连接到服务器之前必须调用此选项,否则将导致未定义的行为。此功能在Qt 5.0中引入。
void setProxy(const QNetworkProxy &networkProxy)
//将此套接字的显式网络代理设置为networkProxy。
virtual void setReadBufferSize(qint64 size)
//将QAbstractSocket的内部读取缓冲区的大小设置为size字节。
//如果缓冲区大小被限制为某个特定的大小,那么QAbstractSocket不会缓冲超过这个大小的数据。例外情况下,缓冲区大小为0意味着读取缓冲区是不受限制的,并且缓冲所有传入数据。这是默认设置。
//如果您只在特定时间点读取数据(例如,在实时流应用程序中),或者如果您想保护套接字不接收过多数据,这可能最终导致应用程序内存不足,则此选项非常有用。
//只有QTcpSocket使用QAbstractSocket的内部缓冲区;QUdpSocket根本不使用任何缓冲,而是依赖于操作系统提供的隐式缓冲。因此,在QUdpSocket上调用此函数没有任何效果。
virtual bool setSocketDescriptor(qintptr socketDescriptor, QAbstractSocket::SocketState socketState = ConnectedState, QIODevice::OpenMode openMode = ReadWrite)
//使用本机套接字描述符socketDescriptor初始化QAbstractSocket。如果socketDescriptor被接受为有效的套接字描述符,则返回true;否则返回false。套接字以openMode指定的模式打开,并进入socketState指定的套接字状态。读取和写入缓冲区被清除,丢弃任何挂起的数据。
//注意:不可能使用相同的本机套接字描述符初始化两个抽象套接字。
virtual void setSocketOption(QAbstractSocket::SocketOption option, const QVariant &value)
//将给定option设置为由value描述的值。
//注意:在Windows运行时上,连接套接字之前必须设置QAbstractSocket::KeepAliveOption。
//此功能在Qt 4.6中引入。
virtual qintptr socketDescriptor() const
//如果QAbstractSocket对象的本地套接字描述符可用,则返回该描述符;否则返回-1。
//如果套接字使用QNetworkProxy,则返回的描述符可能无法用于本机套接字函数。
//当QAbstractSocket处于UnconnectedState时,套接字描述符不可用。
virtual QVariant socketOption(QAbstractSocket::SocketOption option)
//返回option选项的值。此功能在Qt 4.6中引入。
QAbstractSocket::SocketType socketType() const
//返回套接字类型(TCP、UDP或其他)。
QAbstractSocket::SocketState state() const
//返回套接字的状态。
virtual bool waitForConnected(int msecs = 30000)
//等待,直到套接字连接,最长可达毫秒。如果已建立连接,则此函数将返回true;否则返回false。在返回false的情况下,可以调用error()来确定错误的原因。
virtual bool waitForDisconnected(int msecs = 30000)
//等待,直到套接字断开连接,最长可达毫秒。如果连接已断开,此函数将返回true;否则返回false。在返回false的情况下,可以调用error()来确定错误的原因。

静态公共成员:
QMetaObject
包含了QObject的所谓的元数据,也就是QObject信息的一些描述信息:除了类型信息外,还包含QT中特有的signal&slot信息。

QTcpSocket类使用

// 定义套接字
QTcpServer *socket = new QTcpSocket();//取消已有的连接
socket->abort();//连接服务器
socket->connectToHost(IP, Port);//QTcpSocket类里读取和发送数据用的函数都在socket缓冲区中保存
//读取socket缓冲区数据
QString buffer = socket->readAll();
//写入socket缓冲区里数据
socket->write("将数据写入socket缓存区");
//可以以以下两个信号来添加槽函数处理操作
//连接成功和连接断开会触发 connected() 和 disconnected() 信号:
//当socket接收缓冲区有新数据到来时,会发出readRead()信号//断开连接
socket->disconnectFromHost();//关闭套接字
socket.close();

QTcpServer类简介
QTcpServer类提供了一个基于TCP的服务器。此类可以接受传入的TCP连接。可以指定端口,也可以让QTcpServer自动选择一个端口。可以监听特定的地址或所有机器的地址。调用listen()让服务器监听传入的连接。每次客户端连接到服务器时,都会发出newConnection()信号。调用nextPendingConnection()以接受挂起的连接作为已连接的QTcpSocket。该函数返回指向QAbstractSocket::ConnectedState中QTcpSocket的指针,您可以使用该指针与客户端通信。如果发生错误,serverError()将返回错误类型,并且可以调用errorString()来获得所发生事情的可读描述。在侦听连接时,服务器正在侦听的地址和端口可用作serverAddress()和serverPort()。调用close()将使QTcpServer停止侦听传入连接。尽管QTcpServer主要是为与事件循环一起使用而设计的,但也可以在没有事件循环的情况下使用它。在这种情况下,您必须使用waitForNewConnection(),它会阻塞直到连接可用或超时。

Header:#include
qmake: QT += network
Inherits: QObject
Inherited By: QSctpServer

Public Functions

QTcpServer(QObject *parent = nullptr)
//构造一个QTcpServer对象。
virtual ~QTcpServer()
//销毁QTcpServer对象。
void close()
//关闭服务器。服务器将不再侦听传入连接。
QString errorString() const
//返回上次发生的错误的可读说明。
virtual bool hasPendingConnections() const
//如果服务器有挂起的连接,则返回true;否则返回false。
bool isListening() const
//如果服务器当前正在侦听传入连接,则返回true;否则返回false。
bool listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0)
//告诉服务器侦听地址地址和端口端口上的传入连接。如果端口为0,则自动选择端口。如果地址为QHostAddress::Any,则服务器将侦听所有网络接口。成功时返回true;否则返回false。
int maxPendingConnections() const
//返回挂起的可接受连接的最大数目。默认值为30。
virtual QTcpSocket *nextPendingConnection()
//将下一个挂起的连接作为已连接的QTcpSocket对象返回。
//套接字是作为服务器的子级创建的,这意味着当QTcpServer对象被销毁时,它会被自动删除。在处理完对象后显式删除该对象仍然是一个好主意,以避免浪费内存。
//如果在没有挂起的连接时调用此函数,则返回0。
//注意:返回的QTcpSocket对象不能从另一个线程使用。如果要使用来自另一个线程的传入连接,则需要重写incomingConnection()。
void pauseAccepting()
//暂停接受新连接。排队的连接将保留在队列中。
QNetworkProxy proxy() const
//返回此套接字的网络代理。默认情况下,使用QNetworkProxy::DefaultProxy。
void resumeAccepting()
//继续接受新连接。
QHostAddress serverAddress() const
//如果服务器正在侦听连接,则返回服务器的地址;否则返回QHostAddress::Null。
QAbstractSocket::SocketError serverError() const
//返回上次发生的错误的错误代码。
quint16 serverPort() const
//如果服务器正在侦听连接,则返回服务器的端口;否则返回0。
void setMaxPendingConnections(int numConnections)
//将挂起的可接受连接的最大数量设置为numConnections。在调用nextPendingConnection()之前,QTcpServer将接受不超过numConnections的传入连接。默认情况下,限制为30个挂起的连接。
//在服务器达到其挂起连接的最大数量后,客户端仍然可以连接(即,QTcpSocket仍然可以发出connected()信号)。QTcpServer将停止接受新连接,但操作系统可能仍会将它们保留在队列中。
void setProxy(const QNetworkProxy &networkProxy)
//将此套接字的显式网络代理设置为networkProxy。
bool setSocketDescriptor(qintptr socketDescriptor)
//设置此服务器在侦听到socketDescriptor的传入连接时应使用的套接字描述符。如果套接字设置成功,则返回true;否则返回false。
//假定套接字处于侦听状态。
qintptr socketDescriptor() const
//返回服务器用于侦听传入指令的本机套接字描述符,如果服务器未在侦听,则返回-1。
//如果服务器正在使用QNetworkProxy,则返回的描述符可能无法用于本机套接字函数。
bool waitForNewConnection(int msec = 0, bool *timedOut = nullptr)
//等待时间最多为毫秒,或者直到有传入连接可用为止。如果连接可用,则返回true;否则返回false。如果操作超时且timedOut不为0,则*timedOut将设置为true。
//这是一个阻塞函数调用。它在单线程GUI应用程序中的使用是不利的,因为整个应用程序将停止响应,直到函数返回。waitForNewConnection()在没有可用的事件循环时非常有用。
//非阻塞的替代方法是连接到newConnection()信号。
//如果毫秒为-1,则此功能不会超时。此外还有31 public functions inherited from QObject 

Signals

void acceptError(QAbstractSocket::SocketError socketError)
//当接受新连接导致错误时,会发出此信号。socketError参数描述了发生的错误类型。
void newConnection()
//每当有新的连接可用时,就会发出此信号。此外还有2 signals inherited from QObject 

QTcpServer类使用

QTcpServer *server = new QTcpServer();//监听指定的地址和端口
server->listen(QHostAddress::Any, port)//获取已经连接的客户端套接字
socket = server->nextPendingConnection(); //关闭倾听服务
server->close();

小练习:
QT里的网络通信简介

//client.h
#ifndef CLIENT_H
#define CLIENT_H
#pragma execution_character_set("utf-8")
#include <QMainWindow>
#include <QTcpSocket>
#include <QKeyEvent>
#include <QWidget>namespace Ui {class client;
}class Client : public QMainWindow
{Q_OBJECTpublic:explicit Client(QWidget *parent = nullptr);~Client();private slots:void on_connect_button_clicked(bool checked);void on_send_button_clicked();void readyRead_SLOT();void connected_SLOT();private:Ui::client *ui;QTcpSocket *socket;
};#endif // CLIENT_H
//server.h
#ifndef SERVER_H
#define SERVER_H
#pragma execution_character_set("utf-8")
#include <QMainWindow>
#include <QTcpServer>
#include <QTcpSocket>
#include <QString>QT_BEGIN_NAMESPACE
namespace Ui { class Server; }
QT_END_NAMESPACEclass Server : public QMainWindow
{Q_OBJECTpublic:Server(QWidget *parent = nullptr);~Server();private slots:void on_send_button_clicked();void on_startorstop_Listen_clicked(bool checked);void readyRead_SLOT();void newConnection_SLOT();private:Ui::Server *ui;QTcpSocket *socket;QTcpServer *server;
};
#endif // SERVER_H
//client.cpp
#include "client.h"
#include "ui_client.h"
#include "stdio.h"
#include "QString"
#include <QTextCodec>
#pragma execution_character_set("utf-8")
Client::Client(QWidget *parent) :QMainWindow(parent),ui(new Ui::client)
{ui->setupUi(this);//设置clicked(bool checked)点击反转状态打开ui->connect_button->setCheckable(true);socket = new QTcpSocket();//信号:客户端申请连接成功 槽函数:允许写入数据connect(socket, SIGNAL(connected()), this, SLOT(connected_SLOT()));
}Client::~Client()
{delete ui;
}//信号:客户端申请连接成功 槽函数:允许写入数据
void Client::connected_SLOT()
{connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead_SLOT()));//如果socket中有缓存消息,触发槽函数
}//接收消息并显示到接收框
void Client::readyRead_SLOT()
{QString buffer;qDebug() << "Client Received!";//读取缓冲区数据buffer = socket->readAll();buffer = "Server: " + buffer;if (!buffer.isEmpty()){qDebug() << buffer;//刷新显示ui->receiver->appendPlainText(buffer);}
}//连接和断开按键
void Client::on_connect_button_clicked(bool checked)
{if (checked){QString IP = ui->ipnum->text();int Port = ui->portnum->text().toUInt();//取消已有的连接socket->abort();//连接服务器socket->connectToHost(IP, Port);//如果等待超过1000msif (!socket->waitForConnected(1000)){qDebug() << "Connect failed, please try again later!";//连接失败,再次点击则重新连接,将checked恢复为trueui->connect_button->toggle();return;}qDebug() << "Connect Successfully! Connect with IP:" << IP << "; port:" << Port;//修改按键文字ui->connect_button->setText("断开连接");//发送键使能ui->send_button->setEnabled(true);}else{qDebug() << "Disconnect!";//断开连接socket->disconnectFromHost();//修改按键文字&发送键静默ui->connect_button->setText("连接");ui->send_button->setEnabled(false);}
}//发送消息,写入socket缓存区
void Client::on_send_button_clicked()
{//qDebug() << "Client Send: " << ui->sender->toPlainText().toLocal8Bit();将输入框的内容写入socket缓冲区//socket->write(ui->sender->toPlainText().toLocal8Bit());qDebug() << "Client Send: " << ui->sender->toPlainText().toLatin1();ui->receiver->appendPlainText("client: " + ui->sender->toPlainText());//将输入框的内容写入socket缓冲区socket->write(ui->sender->toPlainText().toLatin1());//刷新socket缓冲区socket->flush();ui->sender->setPlainText("");
}
//server.cpp
#include "server.h"
#include "ui_server.h"
#include <QTextCodec>
Server::Server(QWidget *parent): QMainWindow(parent), ui(new Ui::Server)
{ui->setupUi(this);//设置clicked(bool checked)点击反转状态打开ui->startorstop_Listen->setCheckable(true);socket = new QTcpSocket();server = new QTcpServer();//信号:新的客户端连接建立 槽函数:获取客户端套接字,允许写入数据connect(server, SIGNAL(newConnection()), this, SLOT(newConnection_SLOT()));
}Server::~Server()
{delete ui;
}//信号:新的客户端连接建立 槽函数:获取客户端套接字,允许写入数据
void Server::newConnection_SLOT()
{socket = server->nextPendingConnection(); //获取已经连接的客户端套接字connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead_SLOT()));//如果socket中有缓存消息,触发槽函数
}//接收消息并显示到接收框
void Server::readyRead_SLOT()
{qDebug() << "Server Received!";QString buffer;//读取缓冲区数据buffer = socket->readAll();buffer = "Client:  " + buffer;if (!buffer.isEmpty()){//刷新显示ui->receiver->appendPlainText(buffer);}
}//开始监听和停止监听按键
void Server::on_startorstop_Listen_clicked(bool checked)
{if (checked){int port = ui->portnum->text().toUInt();//如果未监听到if (!server->listen(QHostAddress::Any, port)){qDebug() << server->errorString();//连接失败,再次点击则重新连接,将checked恢复为trueui->startorstop_Listen->toggle();return;}qDebug() << "Listen Successfully! Message from port:" << port;//修改按钮文字ui->startorstop_Listen->setText("停止监听");//发送键使能ui->send_button->setEnabled(true);}else{qDebug() << "Stop Listening!";//如果已经连接则断开连接if (socket->state() == QAbstractSocket::ConnectedState){//断开连接socket->disconnectFromHost();}//关闭倾听服务server->close();//修改按钮文字&发送键静默ui->startorstop_Listen->setText("开始监听");ui->send_button->setEnabled(false);}
}//发送消息,写入socket缓存区
void Server::on_send_button_clicked()
{//qDebug() << "Client Send: " << ui->sender->toPlainText().toLocal8Bit();将输入框的内容写入socket缓冲区//socket->write(ui->sender->toPlainText().toLocal8Bit());qDebug() << "Server Send: " << ui->sender->toPlainText().toLatin1();ui->receiver->appendPlainText("server: " + ui->sender->toPlainText());//将输入框的内容写入socket缓冲区socket->write(ui->sender->toPlainText().toLatin1());//刷新socket缓冲区socket->flush();ui->sender->setPlainText("");
}
//main()
#include "server.h"
#include "client.h"
#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);Server w1;Client w2;//Client窗口通过鼠标单机获得聚焦w2.setFocusPolicy(Qt::ClickFocus);//将客户端和服务端窗口移动到屏幕合适位置w1.move(320, 340);w2.move(960, 340);//打开客户端和服务端窗口w1.show();w2.show();return a.exec();
}