Qt网络编程:QAbstractSocket

一、描述

QAbstractSocket 类提供所有Socket类型通用的基本功能。

QAbstractSocket 是 QTcpSocket QUdpSocket 的基类,包含这两个类的所有通用功能。

 如果您需要一个Socket,可以:

  • 子类化 QTcpSocket 或QUdpSocket。
  • 创建一个原生Socket,实例化QAbstractSocket,并调用setSocketDescriptor()来包装原生Socket。

TCP(传输控制协议)是一种可靠的、面向流的、面向连接的传输协议。

UDP(用户数据报协议)是一种不可靠、面向数据报的无连接协议。

TCP 更适合连续传输数据,而在可靠性不重要时可以使用更轻量级的 UDP。 

QAbstractSocket 的 API 统一了两种协议之间的大部分差异。例如,尽管 UDP 是无连接的,但 connectToHost() 为 UDP Socket建立了一个虚拟连接,能够以或多或少相同的方式使用    QAbstractSocket,而不管底层协议如何。

二、类型成员

1、QAbstractSocket::BindFlag:此枚举描述了QAbstractSocket::bind() (绑定)行为不同标志。

  • ShareAddress:允许其他服务(其他进程的)绑定到相同的地址和端口。通过将此选项与 ReuseAddressHint 结合使用,将允许您的服务重新绑定现有的共享地址。
  • DontShareAddress:将地址和端口进行独占绑定,不允许其他服务重新绑定。
  • ReuseAddressHint:向 QAbstractSocket 提供提示,即使地址和端口已经被另一个Socket绑定,它也应该尝试重新绑定服务。
  • DefaultForPlatform:当前平台的默认选项。在 Unix 和 macOS 上,这相当于 (DontShareAddress + ReuseAddressHint),在 Windows 上,它相当于 ShareAddress。

2、QAbstractSocket::NetworkLayerProtocol:网络层协议。

  • IPv4Protocol:IPv4
  • IPv6Protocol:IPv6
  • AnyIPProtocol:IPv4 或 IPv6
  • UnknownNetworkLayerProtocol:除了 IPv4 和 IPv6

3、QAbstractSocket::PauseMode:暂停模式。此枚举描述了Socket何时应阻止继续数据传输的行为。当前支持的唯一通知是 QSslSocket::sslErrors()。

  • PauseNever:不要暂停Socket上的数据传输。
  • PauseOnSslErrors:收到 SSL 错误通知后暂停Socket上的数据传输。

4、QAbstractSocket::SocketError:此枚举描述了可能发生的Socket错误。

  • ConnectionRefusedError:连接被对等方拒绝(或超时)。
  • RemoteHostClosedError:远程主机关闭了连接。请注意,客户端Socket将在发送远程关闭通知后关闭。
  • HostNotFoundError:找不到主机地址。
  • SocketAccessError:Socket操作失败,因为应用程序缺少所需的权限。
  • SocketResourceError:本地系统资源不足(例如,Socket过多)。
  • SocketTimeoutError:Socket操作超时。
  • DatagramTooLargeError:数据报大于操作系统的限制。
  • NetworkError:网络出现错误(例如,网现被拔出)。
  • AddressInUseError:指定给 bind() 的地址已在使用中并设置为独占。
  • SocketAddressNotAvailableError:指定给 bind() 的地址不属于主机。
  • UnsupportedSocketOperationError:本地操作系统不支持请求的Socket操作(例如,缺乏 IPv6 支持)。
  • ProxyAuthenticationRequiredError:Socket正在使用代理,并且代理需要身份验证。
  • SslHandshakeFailedError:SSL/TLS 握手失败,因此连接被关闭(仅在 QSslSocket 中使用)
  • UnfinishedSocketOperationError:上次尝试的操作尚未完成(仍在后台进行)。
  • ProxyConnectionRefusedError:无法联系代理服务器,因为与该服务器的连接被拒绝
  • ProxyConnectionClosedError:在与最终对等方的连接建立之前,与代理服务器的连接意外关闭
  • ProxyConnectionTimeoutError:与代理服务器的连接超时或代理服务器在身份验证阶段停止响应。
  • ProxyNotFoundError:未找到使用 setProxy()(或应用程序代理)设置的代理地址。
  • ProxyProtocolError:与代理服务器的连接协商失败,因为无法理解来自代理服务器的响应。
  • OperationError:当Socket处于不允许的状态时尝试进行操作。
  • SslInternalError:正在使用的 SSL 库报告了一个内部错误。这可能是库安装错误或配置错误的结果。
  • SslInvalidUserDataError:提供了无效数据(证书、密钥、密码等),其使用导致 SSL 库中出现错误。
  • TemporaryError:发生临时错误(例如,操作会阻塞而Socket是非阻塞的)。
  • UnknownSocketError:发生不明错误。

4、QAbstractSocket::SocketOption:此枚举表示可以在Socket上设置的选项。

  • LowDelayOption:尝试优化Socket以实现低延迟。对于 QTcpSocket,这将设置 TCP_NODELAY 选项并禁用 Nagle 算法。设置为 1 启用选项。(可参考:神秘的40毫秒延迟与 TCP_NODELAY - wajika - 博客园
  • KeepAliveOptionSO_KEEPALIVE 选项。设置为 1 启用选项。(可参考:网络编程:SO_KEEPALIVE和心跳机制 - 知乎
  • MulticastTtlOption:将此设置为整数值以设置 IP_MULTICAST_TTL(多播数据报的 TTL(TTL:路由跳数))选项。
  • MulticastLoopbackOption:将此设置为 1 以启用 IP_MULTICAST_LOOP(多播环回)选项。
  • TypeOfServiceOption:Windows 不支持此选项。IP_TOS 选项。见:IPv4头部结构_友善啊,朋友的博客-CSDN博客_ipv4头部结构 8位服务类型。
  • SendBufferSizeSocketOption:在操作系统级别设置Socket发送缓冲区大小(以字节为单位)。这映射到 SO_SNDBUF 选项。 
  • ReceiveBufferSizeSocketOption:在操作系统级别设置Socket接收缓冲区大小(以字节为单位)。 这映射到 SO_RCVBUF 选项。
  • PathMtuSocketOption:检索最大传输单元 (PMTU) 值(如果有)。

5、QAbstractSocket::SocketType:此枚举描述了传输层协议。

  • TcpSocket:TCP
  • UdpSocket:UDP
  • SctpSocket:SCTP
  • UnknownSocketType:除了 TCP、UDP 和 SCTP之外的协议

6、QAbstractSocket::SocketState:此枚举描述了Socket可以处于的不同状态。

  • UnconnectedState:未连接。
  • HostLookupState:正在查找主机。
  • ConnectingState:已开始建立连接。
  • ConnectedState:已建立连接。
  • BoundState:已绑定到地址和端口。
  • ClosingState:即将关闭(数据可能仍在等待写入)。

三、成员函数

1、[signal] void connected()

调用 connectToHost() 并成功建立连接后发出此信号。

2、[signal] void disconnected()

当Socket已断开连接时发出此信号。警告:如果需要在与其连接的插槽中删除此信号的 sender(),请使用 deleteLater() 函数。

3、[signal] void errorOccurred(QAbstractSocket::SocketError socketError)

发生错误后发出此信号。 socketError 参数描述发生的错误类型。

发出此信号时,Socket可能尚未准备好进行重新连接尝试。 在这种情况下,应该从事件循环中尝试重新连接。 例如使用 QTimer::singleShot() 超时设置超时后尝试重新连接。

QAbstractSocket::SocketError 不是注册的元类型,因此对于Qt::QueuedConnection信号槽连接类型,必须使用 Q_DECLARE_METATYPE() 和 qRegisterMetaType() 注册它。

4、[signal] void hostFound()

在调用 connectToHost() 并且主机查找成功后发出此信号。

5、[signal] void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator)

当使用需要身份验证的代理时,可以发出此信号。然后可以使用所需的详细信息填充身份验证器对象以允许身份验证并继续连接。

注意:无法使用 Qt::QueuedConnection 连接到此信号,因为如果在信号返回时验证器未填充新信息,则连接将失败。

6、[signal] void stateChanged(QAbstractSocket::SocketState socketState)

只要 QAbstractSocket 的状态发生变化,就会发出这个信号。socketState 参数是新状态。

QAbstractSocket::SocketState 不是注册的元类型,因此对于Qt::QueuedConnection信号槽连接类型,必须使用 Q_DECLARE_METATYPE() 和 qRegisterMetaType() 注册它。

7、void abort()

中止当前连接并重置Socket。会立即关闭Socket,丢弃写入缓冲区中的任何挂起数据。

8、bool atEnd()

如果当前没有更多数据可供读取,则返回 true; 否则返回false。

此函数最常用于循环从Socket读取数据。 例如:

  // This slot is connected to QAbstractSocket::readyRead()
  void SocketClass::readyReadSlot()
  {
      while (!socket.atEnd()) {
          QByteArray data = socket.read(100);
          ....
      }
  }

9、bool bind(const QHostAddress &address, quint16 port = 0, QAbstractSocket::BindMode mode = DefaultForPlatform) 

使用 BindMode 模式绑定Socket要连接的端口和地址。

  • 对于 UDP Socket,绑定后,只要 UDP 数据报到达指定的地址和端口,就会发出信号 QUdpSocket::readyRead()。
  • 对于 TCP Socket,此函数可用于指定用于传出连接的接口,这在多个网络接口的情况下很有用。

如果未指定端口,则选择随机端口。

成功时,函数返回 true,Socket进入 BoundState状态。

10、bool bind(quint16 port = 0, QAbstractSocket::BindMode mode = DefaultForPlatform)

使用 BindMode 模式绑定到Socket要连接的QHostAddress:Any地址。 如果未指定端口,则选择随机端口。

11、qint64 bytesAvailable()

返回等待读取的传入字节数。

12、qint64 bytesToWrite() 

返回等待写入的字节数。(当控制返回到事件循环或调用 flush() 时写入字节。)

13、bool canReadLine()

是否可以从Socket读取一行数据。

14、void close()

关闭Socket的 I/O 设备并调用 disconnectFromHost() 关闭Socket的连接。

15、void connectToHost(const QString &hostName, quint16 port, QIODevice::OpenMode openMode = ReadWrite, QAbstractSocket::NetworkLayerProtocol protocol = AnyIPProtocol)

尝试在给定端口上建立到 hostName 的连接。protocol 参数可用于指定要使用的网络协议(例如 IPv4 或 IPv6)。

连接过程:

  1. Socket在给定的 openMode 中打开
  2. 进入 HostLookupState状态
  3. 执行 hostName 的主机名查找。
  4. 如果查找成功,则发出 hostFound()信号 并进入 ConnectingState状态。然后尝试连接到查找返回的一个或多个地址。 最后,如果建立了连接则进入 ConnectedState状态 并发出 connected()信号。

在任何时候,Socket都可以发出 errorOccurred() 来表示发生了错误。

hostName 可以是字符串形式的 IP 地址(例如“43.195.83.32”),也可以是主机名(例如“example.com”)。

16、void connectToHost(const QHostAddress &address, quint16 port, QIODevice::OpenMode openMode = ReadWrite)

重载函数。

17、void disconnectFromHost()

尝试关闭Socket。 如果有待写入的数据等待写入,将进入 ClosingState状态 并等待所有数据写入完毕。 最终,它将进入 UnconnectedState 并发出 disconnected() 信号。

18、QAbstractSocket::SocketError error()

返回上次发生的错误类型。

19、bool flush()

该函数尽可能多地从内部写缓冲区写入底层网络Socket,不阻塞。如果有任何数据被写入则返回true。

如果需要立即开始发送缓冲数据,请调用此函数。成功写入的字节数取决于操作系统。 在大多数情况下不需要调用此函数,因为一旦控制权返回到事件循环,QAbstractSocket 将自动开始发送数据。如果没有事件循环,则应该调用 waitForBytesWritten()。

20、bool isValid()

Socket是否有效并且可以使用。(Socket的状态必须是 ConnectedState状态 才能进行读写)

21、QHostAddress localAddress()

如果可用,返回本地Socket的主机地址; 否则返回 QHostAddress::Null

22、quint16 localPort()

如果可用,返回本地Socket的主机端口号。

23、QHostAddress peerAddress()

如果Socket处于 ConnectedState状态 中,则返回已连接对等方的地址;否则返回 QHostAddress::Null

24、QString peerName()

返回由 connectToHost() 指定的对等方的名称。

25、quint16 peerPort()

如果Socket处于 ConnectedState 状态中,则返回已连接对等方的端口。

26、void resume()

继续在Socket上传输数据。 只有在Socket设置为暂停通知并且收到通知后,才应使用此方法。 当前支持的唯一通知是 QSslSocket::sslErrors()。 如果Socket未暂停,则调用此方法会导致未定义的行为。

27、void setProxy(const QNetworkProxy &networkProxy)

设置网络代理。

28、void setReadBufferSize(qint64 size)

设置QAbstractSocket 的内部读取缓冲区的大小。

如果缓冲区大小限制在特定大小,则 QAbstractSocket 将不会缓冲超过此大小的数据。默认情况下,缓冲区大小为 0 意味着读取缓冲区是无限的,并且所有传入的数据都将被缓冲。

只有 QTcpSocket 使用 QAbstractSocket 的内部缓冲区;QUdpSocket 根本不使用任何缓冲,而是依赖于操作系统提供的隐式缓冲。 因此,在 QUdpSocket 上调用此函数无效。

29、bool waitForBytesWritten(int msecs = 30000)

此函数会阻塞,直到至少一个字节已写入Socket并已发出 bytesWritten() 信号。 该函数将在 msecs 毫秒后超时。

如果发出 bytesWritten() 信号,则该函数返回 true; 否则返回 false(如果发生错误或操作超时)。

30、bool waitForConnected(int msecs = 30000)

等待Socket连接,最多 msecs 毫秒。如果连接已经建立,这个函数返回true;否则返回false。 在返回false的情况下,可以调用error()来确定错误的原因。如果 msecs 为 -1,则此函数不会超时(一直等待)。例:

 socket->connectToHost("imap", 143);
 if (socket->waitForConnected(1000))
     qDebug("Connected!");

31、bool waitForDisconnected(int msecs = 30000)

等待直到Socket断开连接,最多 msecs 毫秒。 如果连接成功断开,此函数返回true; 否则返回 false(如果操作超时、发生错误或此 QAbstractSocket 已断开连接)。 在返回false的情况下,可以调用error()来确定错误的原因。如果 msecs 为 -1,则此函数不会超时。例:

 socket->disconnectFromHost();
 if (socket->state() == QAbstractSocket::UnconnectedState
     || socket->waitForDisconnected(1000)) {
         qDebug("Disconnected!");
 }

32、bool waitForReadyRead(int msecs = 30000)

此函数会阻塞,直到有新数据可供读取且 readyRead() 信号已发出。 该函数将在 msecs 毫秒后超时; 默认超时为 30000 毫秒。如果发出 readyRead() 信号并且有新数据可供读取,则该函数返回 true; 否则返回 false(如果发生错误或操作超时)。

  • 14
    点赞
  • 122
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 在Qt中,可以使用QTcpSocket类来编写TCP客户端程序发送中文。 首先,需要在项目文件中引入QTcpSocket头文件和Qt网络模块: ``` #include <QTcpSocket> #include <QtNetwork> ``` 然后,可以创建一个QTcpSocket对象,并连接到服务器: ``` QTcpSocket* socket = new QTcpSocket(this); socket->connectToHost("服务器IP地址", 端口号); ``` 接下来,我们可以通过socket对象的write()函数来发送中文数据。由于中文字符是Unicode编码,需要将QString转换为QByteArray,并使用UTF-8编码发送: ``` QString chineseStr = "中文内容"; QByteArray data = chineseStr.toUtf8(); socket->write(data); ``` 最后,可以通过调用socket对象的flush()函数来确保数据已经发送: ``` socket->flush(); ``` 需要注意的是,通过socket发送中文数据时,接收方也必须使用相应的解码方式(如UTF-8)来正确解析接收到的数据。 ### 回答2: 在Qt中编写TCP客户端程序发送中文需要进行以下几个步骤: 1. 创建TCP客户端对象:使用`QTcpSocket`类或者`QSslSocket`类创建一个TCP客户端对象。 2. 连接到服务器:使用`connectToHost()`函数将客户端连接到指定的服务器的IP地址和端口号。 3. 发送数据:在连接成功后,可以使用`write()`函数发送数据。对于中文字符,需要将其转换为字节流发送,可以使用`toUtf8()`函数将中文字符转换为UTF-8编码的字节流再发送。 以下是一个简单的例子: ```cpp #include <QtNetwork> int main() { QTcpSocket client; client.connectToHost("127.0.0.1", 1234); if (client.waitForConnected(3000)) // 等待连接建立 { QByteArray data; QString chineseText = "你好世界"; data = chineseText.toUtf8(); // 将中文字符转换为UTF-8编码的字节流 client.write(data); // 发送中文字符数据 client.waitForBytesWritten(3000); // 等待数据发送完成 client.close(); // 关闭连接 } } ``` 以上是一个简单的示例,连接建立成功后,将中文字符“你好世界”转换为UTF-8编码的字节流发送给服务器端。在实际的开发中,可能需要添加错误处理、数据读取和接收的逻辑等。 ### 回答3: 在Qt中编写TCP客户端程序发送中文,可以按照以下步骤进行: 1. 首先,在Qt项目中添加Qt网络模块,在.pro文件中添加`QT += network`语句。 2. 创建一个TCP客户端类,继承自QTcpSocket或者QTcpSocket的子类,用于建立与服务器的连接和发送数据。 3. 在客户端类中,使用`connectToHost()`函数连接到服务器的IP地址和端口号。 4. 记得在连接建立后,使用`waitForConnected()`函数等待连接成功。 5. 使用`write()`函数向服务器发送数据,将要发送的中文数据转换为字节流格式。可以使用QString的toUtf8()函数进行转换。 例如: ```cpp // TCPClient类中的发送函数 void TCPClient::sendData(const QString& data) { QByteArray byteData = data.toUtf8(); // 将中文转换为字节流 if (this->state() == QAbstractSocket::ConnectedState) { this->write(byteData); this->waitForBytesWritten(); } } ``` 6. 关闭连接时,可以使用`disconnectFromHost()`函数断开与服务器的连接。 请注意,发送和接收中文数据时,需要确保服务器和客户端使用相同的字符编码,例如UTF-8。 以上是一个简单的示例,可以根据具体的应用场景来进行修改和扩展。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值