数据传输
收发数据是网络编程的主题.要在已建立连接的套接字上接收数据,可用这两个API函数:send和WSASend.第二个函数是Winsock2中专有的.用样地,在已建立了连接的套接字上接受数据也有两个函数:recv和WSARecv.后者也是Winsock2函数.
必须牢牢记住这一点:所有关系到收发数据的缓冲都属于简单的char类型.也就是说,这些函数没有"Unicode"版本.这一点对Windows CE来说尤为重要,因为Windows CE默认使用Unicode.使用Unicode时有一种选择,即把字符串当作char*或把它造型为char*发送.需要注意的是,在利用字符串长度函数告诉Winsock API函数收发的数据有多少字符时,必须将这个值乘以2,因为每个字符占用字串组的两个字节.另一个选择是在将字串数据投给Winsock API函数之前,用WideCharToMultiByte把UNICODE转换成ASCII码.
另外,所有收发函数返回的错误代码都是SOCKET_ERROR.一旦返回错误,系统就会调用WSAGetLastError获得详细的错误信息.最常见的错误是WSAECONNABORTED和WSAECONNRESET.两者均涉及到即将关闭连接这一问题---要么通过超时,要么通过通信方关闭连接.另一个常见错误是WSAEWOULDBLOCK,一般 出现在套接字处于非暂停模式或异步状态时.这个错误主要以为着指定函数暂不能完成.
1.send 和WSASend
要在已建立连接的套接字上发送数据,第一个可用的API函数是send,其原型为:
int send(
SOCKET s,
const char FAR * buf,
int len,
int flags
);
SOCKET参数是已建立连接的套接字,将在这个套接字上发送数据.第二个参数buf,则是字符缓冲区,区内包含即将发送的数据.第三个参数len,指定即将发送的缓冲区内的字符数.最后,flags可为0、MSG_DONTROUTE或MSG_OOB.另外,flags还可以是对那些标志进行按位"或运算"的一个结果。MSG_DONTROUTE标志要求传送层不要将它发出的包路由出去.由基层的传送决定是否实现这一请求(例如,诺传送协议不支持该选项,这一请求就会被忽略).MSG_OOB标志预示数据应该被带外发送.
对返回数据而言,send返回发送的字节数;诺发生错误,就返回SOCKET_ERROR.常见的错误是WSAECONNABORTED,这一错误一般发生在虚拟回路由于超时或协议有错而中断的时候。发生这种情况时,应该关闭这个套接字,因为它不能再用了.远程主机上的应用通过执行强行关闭或意外中断操作重新设置虚拟虚路时,或远程主机重新启动时,发生的则是WSAECONNRESET错误。再次提醒大家注意,发生这一错误时,应该关闭这个套接字.最后一个常见错误是WSAETIMEOUT,它发生在连接由于网络故障或远程连接系统异常死机而引起的连接中断时.
send API函数的Winsock 2版本是WSASend,它的定义如下:
int WSASend(
SOCKET s;
LPWSABUF lpBuffers,
DWORD dwBufferCount,
LPDWORD lpNumberOfBytesSent,
DWORD dwFlags,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionROUNTINE
);
这个套接字是一个连接会话的有效句柄.第二个参数是指向一个或多个WSABUF结构的指针.它既可是一个独立的结构,又可以是一组结构.第三个参数指明准备投递的WSABUF结构数.记住,每个WSABUF结构本身就是一个字符缓冲和缓冲长度.为何打算同时发送多个缓冲呢?也许大家不太明白其中的原因.这就是我们稍后要讲的"分散集中I/O模式";但是,在一个已建立连接的套接字上利用多缓冲来发送数据时,顺序是从第一个到最后一个 WSABUF结构.lpNumberOfBytesSent是指向DWORD(是WSASend调用返回的)的指针,其中包含字节总发送数.dwFlags参数相当于它在send中的等同物.最后两个参数-----lpOverlapped和lpCompletionROUTINE----用于重叠I/O.重叠I/O是Winsock支持的异步I/O模式之一,关于这一点,我们在第8章详细讲解.
WSASend函数把lpNumberOfBytesSent设为写入的字节数.成功的话,该函数就返回0,否则就返回SOCK_ERROR,常见错误和send函数的情形一样.