◎ recvfrom():读取资料,并储存资料来源的位址。
格式: int PASCAL FAR recvfrom( SOCKET s, char FAR *buf, int len, int flags,
struct socketaddr FAR *from, int FAR *fromlen );
参数: s Socket 的识别码
buf 存放接收到的资料的暂存区
len buf 的长度
flags 此函式被呼叫的方式
from 资料来源的位址
fromlen from 的大小
传回值: 成功 - 接收到的资料长度 (若对方 Socket 已关闭,则为 0)
失败 - SOCKET_ERROR (呼叫 WSAGetLastError() 可得知原因)
说明: 此函式用来读取资料并记录资料来源的位址。对 Datagram Socket (UDP)言,一次读取一个 Datagram;对 Stream Socket (TCP)言,其作用与 recv() 相同,参数 from 及 fromlen 的值会被系统忽略。如果 Socket 为 Blocking 模式,且目前 input buffer 内没有任何资料,则 recvftom() 将 block 到有任何资料到达为止;如果为 Non-Blocking 模式,且 input buffer 无任何资料,则会马上回覆错误。
【FD_WRITE 事件】
笔者在前面介绍过 FD_READ 事件的发生时机,现在继续介绍 FD_WRITE这个较易使人混淆的事件,因为真的有相当多的人对此一事件的发生不明了。
由字面上看,FD_WRITE 应该是要求系统通知我们某个 Socket 现在是否可以呼叫 send() 或 sendto() 来传送资料?答案可以说「是」,但是它和 FD_READ却又有不同的地方。
在前面我们知道呼叫一次 recv() 後,如果 input buffer 中尚有资料未被取出的话,系统会再通知我们一次 FD_READ。那麽如果我们呼叫一次 send() 後,系统的 output buffer 仍有空间可写入的话,它是否会再通知我们一个 FD_WRITE,叫我们继续传送资料呢?这个答案就是「否定」的了!系统并不会再通知我们了。
系统会通知我们 FD_WRITE 事件的讯息,只有下列几种情况:
(1)呼叫 WSAAsyncSelect() 来设定 FD_WRITE 事件时,Socket 已经可以传送资料(TCP scoket 已经和对方连接成功了,或 UDP socket 已建立完成),且目前 output buffer 仍有空间可写入资料。
(2)呼叫 WSAAsyncSelect() 来设定 FD_WRITE 事件时,Socket 尚不能传送资料,不过一旦 Socket 与对方连接成功,马上就会收到 FD_WRITE 的通知。
(3)呼叫 send() 或 sendto() 传送资料时,系统告知错误,且错误码为10035 WSAEWOULDBLOCK (呼叫 WSAGetLastError() 得知这项错误),这时表示 output buffer 已经满了,无法再写入任何资料(此时即令呼叫再多次的 send() 也都一定失败);一旦系统将部份资料成功送抵对方,空出 output buffer 後,便会送一个 FD_WRITE 给使用者,告知可继续传送资料了。换句话说,读者在呼叫 send() 传送资料时,只要不是返回错误 10035 的话,便可一直继续呼叫 send() 来传送资料;一旦 send() 回返错误 10035,那麽便不要再呼叫 send() 传送资料,而须等收到 FD_WRITE 後,再继续传送资料。
【结语】
在这一期的文章中,笔者介绍了各位有关 TCP Socket 的资料收、送方式及FD_READ、FD_WRITE 等事件的发生时机;读者们综合前一期的文章,应该已经可以建立出一对主从架构的程式,并利用 TCP Socket 来传送资料了。
下一期,笔者将继续介绍有关如何获取网路资讯的函式,如 gethostname()、getsockname()、getpeername(),以及同步与非同步的网路资料库撷取函式 getXbyY()、WSAAsyncGetXByY()。
本文中所提到的 WinKing 试用版可自 SEEDNET 台北主机 tpts1.seed.net.tw(139.175.1.10)的 UPLOAD/WINKING 目录中取得,档名为 wkdemo.exe;WinKing 提供 Ethernet 及 PPP 连线功能,适用於一般 Ethernet 网路,亦可用来