一、描述

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(如果发生错误或操作超时)。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐