简单的 Winsock 应用程式设计(2)
在前一期的文章中,笔者为大家介绍了如何在 Winsock 环境下,建立主从架构(Client/Server)的 TCP socket 的连接建立与关闭;今天笔者将继续为大家介绍如何利用 TCP socket 来收送资料,并详细解说 WSAAsyncSelect 函式中的FD_READ 及FD_WRITE 事件(笔者曾发现有相当多人对这两个事件甚不了解)。
相信读者们已经知道 TCP socket 的连接是在 Client 端呼叫 connect 函式成功,Server 端呼叫 accept 函式後,才算完全建立成功;当连接建立成功後,Client 及 Server 也就可以利用这个连接成功的 socket 来传送资料到对方,或是收取对方送过来的资料了。
(图 1. TCP socket 的资料收送)
在介绍资料的收送前,笔者先介绍一下 TCP socket 与 UDP socket 在传送资料时的特性:
Stream (TCP) Socket 提供「双向」、「可靠」、「有次序」、「不重覆」之资料传送。
Datagram (UDP) Socket 则提供「双向」之沟通,但没有「可靠」、「有次序」、「不重覆」等之保证; 所以使用者可能会收到无次序、重覆之资料,甚至资料在传输过程中也可能会遗漏。
由於 UDP Socket 在传送资料时,并不保证资料能完整地送达对方,所以我们常用的一些应用程式(如 telnet、mail、ftp、news等)都是采用 TCP Socket,以保证资料的正确性。(TCP 及 UDP 封包的传送协定不在我们讨论□围,想要了解的读者们,请自行参考相关书籍)
TCP 及 UDP Socket 都是双向的,所以我们是利用同一个 Socket 来做传送及收取资料的动作;一般言 TCP Socket 的资料送、收是呼叫 send() 及 recv()这两个函式来达成,而 UDP Socket 则是用 sendto() 及 recvfrom() 这两个函式。不过 TCP Socket 也可用 sendto() 及 recvfrom() 函式,UDP Socket 同样可用 send() 及 recv() 函式;这一点我们稍後再加以解释。
现在我们先看一下 send() 及 recv() 的函式说明,并回到我们的前一期程式。
◎ send():使用连接式(connected)的 Socket 传送资料。
格式: int PASCAL FAR send(SOCKET s, const char FAR *buf,int len, int flags );
参数: s Socket 的识别码
buf 存放要传送的资料的暂存区
len buf 的长度
flags 此函式被呼叫的方式
传回值: 成功 - 送出的资料长度
失败 - SOCKET_ERROR (呼叫 WSAGetLastError() 可得知原因)
说明: 此函式适用於连接式的 Datagram 或 Stream Socket 来传送资料。 对 Datagram Socket 言,若是 datagram 的大小超过限制,则将不会送出任何资料,并会传回错误值。对 Stream Socket 言,Blocking 模式下,若是传送 (transport) 系统内之储存空间(output buffer)不够存放这些要传送的资料,send() 将会被 block住,直到资料送完为止;如果该 Socket 被设定为 Non-Blocking 模式,那麽将视目前的 output buffer 空间有多少,就送出多少资料,并不会被 block 住。使用者亦须注意 send()函式执行完成,并不