同样地,资料全部送收完毕後,我们也呼叫 closesocket() 来将 Socket 关闭。
◎ WSACancelBlockingCall():取消目前正在进行中的 blocking 动作。
格式: int PASCAL FAR WSACancelBlockingCall( void );
参数: 无
传回值: 成功 - 0
失败 - SOCKET_ERROR (呼叫 WSAGetLastError() 可得知原因)
说明: 此函式用来取消该应用程式正在进行中的 blocking 动作。通常的使用时机有:(a) Blocking 动作正在进行中,该应用程式又收到某一讯息(Mouse、Keyboard、Timer 等),则可在处理该讯息的段落中呼叫此函式。(b)Blocking 动作正在进行中,而 Windows Sockets 又呼叫回应用程式的「blocking hook」函式时,在该函式内可呼叫此函式来取消 blocking 动作。使用者必须注意,在某一 Winsock blocking 函式动作进行时,除了WSAIsBlocking() 及 WSACancelBlockingCall() 外,不可以再呼叫其它任何Windows Sockets DLL 提供的函式,否则会产生错误。另外若取消的 blocking 动作不是 accept() 或 select() 的话,那麽该 Socket 可能会处於未定状态,使用者最好是呼叫 closesocket() 来关闭该 Socket,而不该再对它做任何动作。
(图 2.)demoserv 与 democlnt 在资策会 WinKing 上收送资料的画面
(图 3.)demoserv 与 democlnt 在资策会 WinKing 上关闭 Socket 後的画面
介绍完了 TCP Socket 的资料收送,笔者接著为读者介绍 sendto() 及 recvfrom() 这两个函式,以及许多人可能很容易搞错的 FD_WRITE 事件。
【sendto 及 recvfrom 函式】
一般言,TCP Socket 使用的是 send() 及 recv() 这两个函式;而 UDP Socket用的是 sendto() 及 recvfrom() 函式。这是因为 TCP 是 Connection-oriented,必须做完 Socket 真正的连接程序後,才可以开始收送资料,此时系统已经知道了连接的对方,所以我们不用再指定资料要送到哪里。而 UDP 是 Connectionless,收送资料的双方并没有建立真正的连接,所以我们要利用 sendto() 及 recvfrom()来指定收资料的对方及获知是谁送资料给我们。
TCP Socket 也可以用 sendto() 及 recvfrom()来送收资料,只是此时这两个函式的最後两个参数没有作用,会被系统所忽略。而 UDP Socket 如果呼叫了connect() 函式来指定对方的位址(这个 connect 并不会真的和对方做连接的动作,而是告知我们本身的系统说我们只想收、送何方的资料),那麽也可以利用 send() 及 recv() 来送收资料。
◎ sendto():将资料送到使用者指定的目的地。
格式: int PASCAL FAR sendto( SOCKET s, const char FAR *buf, int len, int flags, const struct sockaddr FAR *to, int tolen );
参数: s Socket 的识别码
buf 存放要传送的资料的暂存区
len buf 的长度
flags 此函式被呼叫的方式
to 资料要送达的位址
tolen to 的大小
传回值: 成功 - 送出的资料长度
失败 - SOCKET_ERROR (呼叫 WSAGetLastError() 可得知原因)
说明: 此函式适用於 Datagram 或 Stream Socket 来传送资料到指定的
位址。 对 Datagram Socket 言,若是 datagram 的大小超过限制,则将不会 送出任何资料,并会传回错误值。对 Stream Socket 言,其作用与 send() 相同;参数 to 及 tolen 的值将被系统所忽略。 若是传送 (transport) 系统内之储存空间不够存放这些要传送的资料,sendto() 将会被 block 住,直到资料都被送出;除非该 Socket 被设定为 non-blocking 模式。使用者亦须注意 sendto() 函式执行完成,并不表示资料已经成功地送抵对方了,而可能仍在系统的 output buffer 中