发送和接收 PGM 数据

发送和接收 PGM 数据类似于在任何套接字上发送或接收数据。 以下段落概述了 PGM 的注意事项。

发送 PGM 数据

创建 PGM 发送方会话后,将使用各种 Windows 套接字发送函数发送数据: sendsendtoWSASendWSASendTo。 由于 Windows 套接字句柄是文件系统句柄,其他函数(如 WriteFile 和 CRT 函数)也可以传输数据。 以下代码片段演示 PGM 发送方操作:

LONG        error;
    //:
error = send (s, pSendBuffer, SendLength, 0);
if (error == SOCKET_ERROR)
{
    fprintf (stderr, "send() failed: Error = %d\n",
             WSAGetLastError());
}

使用消息模式 (SOCK_RDM) 时,每次调用 send 函数都会导致离散消息,有时这是不可取的:应用程序可能需要发送包含多个调用的 2 兆字节消息。 在这种情况下,发送方可以设置 RM_SET_MESSAGE_BOUNDARY 套接字选项以指示以下消息的大小。

如果发送窗口已满,则在高级窗口之前,不会接受来自应用程序的新发送。 尝试在非阻塞套接字上发送失败,WSAEWOULDBLOCK;阻塞套接字只是阻止,直到窗口前进到可以缓冲和发送请求的数据的点。 在重叠 I/O 中,在窗口前进到足以容纳新数据之前,操作不会完成。

接收 PGM 数据

创建 PGM 接收器会话后,将使用各种 Windows 套接字接收函数接收数据: recvrecvfromWSARecvWSARecvFrom。 由于 Windows 套接字句柄也是文件句柄, 因此 ReadFile 和 CRT 函数也可用于接收 PGM 会话数据。 只要数据按顺序到达,传输会将数据转发到接收方。 传输保证返回的数据是连续的且没有重复项。 以下代码片段演示 PGM 接收操作:

LONG        BytesRead;
    //:
BytesRead = recv (sockR, pTestBuffer, MaxBufferSize, 0);
if (BytesRead == 0)
{
    fprintf(stdout, "Session was terminated\n");
}
else if (BytesRead == SOCKET_ERROR)
{
    fprintf(stderr, "recv() failed: Error = %d\n",
            WSAGetLastError());
}

使用消息模式 (SOCK_RDM) 时,传输指示何时收到部分消息(出现 WSAEMSGSIZE 错误),或者在从 WSARecv 和 WSARecvFrom 函数返回时设置MSG_PARTIAL标志。 当完整消息的最后一个片段返回到客户端时,不会指示错误或标志。

正常终止会话时,接收操作失败,WSAEDISCON。 当传输中发生数据丢失时,PGM 会暂时缓冲不按顺序的数据包,并尝试恢复丢失的数据。 如果数据丢失不可恢复,则接收操作失败并显示 WSAECONNRESET,会话将终止。 由于多种情况,会话可以重置,包括:

  • 接收方或传入连接速率太慢,无法跟上传入数据速率的步伐。
  • 由于暂时性网络状况(例如路由问题、网络不稳定等)而导致过多的数据丢失。
  • 发件人上发生不可恢复的错误。
  • 本地计算机上资源利用率过高,例如超过允许的最大内部缓冲区存储,或遇到资源不足的情况。
  • 发生数据一致性检查错误。
  • 组件 PGM 中的故障取决于,例如 TCP/IP 或 Windows 套接字。

上述列表中的第一项和第二项都可能导致接收方在资源耗尽之前或最终超出发送方的窗口之前执行过多的缓冲。

终止 PGM 会话

PGM 发送方或接收方可以通过调用 closesocket 停止发送或接收数据。 接收方必须在侦听和接收套接字上调用 closesocket ,以防止句柄泄漏。 在调用 closesocket 之前对发送方调用关闭可确保发送所有数据,并确保维护修复数据,直到发送窗口超过最后一个数据序列,即使应用程序本身终止也是如此。