7.4 无连接协议
和面向连接的协议比较起来,无连接协议的行为极为不同,因此,收发数据的方式也会有所不同。由于在和面向会话的服务器比较时,无连接接收端改动不大,所以我们先谈谈接收端(如果你愿意,也可称之为服务器)。接下来再谈发送端。
7.4.1 接收端
对于在一个无连接套接字上接收数据的进程来说,步骤并不复杂。先用s o c k e t或W S A S o c k e t建立套接字。再把这个套接字和准备接收数据的接口绑定在一起。这是通过b i n d函数(和面向会话的示例一样)来完成的。和面向会话不同的是,我们不必调用l i s t e n和a c c e p t。相反,只需等待接收数据。由于它是无连接的,因此始发于网络上任何一台机器的数据报都可被接
收端的套接字接收。最简单的接收函数是r e c v f r o m。它的定义如下:

int recvfrom(
       SOCKET s,
       char FAR * buf,
       int len,
       int flags,
       struct sockaddr FAR * from,
       int FAR * fromlen
      );
前面四个参数和r e c v是一样的,其中包括标志M S G _ O O B和M S G _ P E E K。在使用无连接套接字时,和前面一样,仍然提醒大家慎用M S G _ P E E K标志。对监听套接字的具体协议来说,f r o m参数是一个S O C K A D D R结构,带有指向地址结构的长度的f r o m l e n。这个A P I调用返回数
据时,S O C K A D D R结构内便填入发送数据的那个工作站的地址。

r e c v f r o m函数的Winsock 2版本是W S A R e c v F r o m。后者的原型是:

int WSARecvFrom(
         SOCKET s,
         LPWSABUF lpBuffers,
         DWORD dwBufferCount,
         LPDWORD lpNumberOfBytesRecvd,
         LPDWORD lpFlags,
         struct sockaddr FAR * lpFrom,
         LPINT lpFromlen,
         LPWSAOVERLAPPED lpOverlapped,
         LPWSAOVERLAPPED_COMPLETTION_ROUTINE lpComplettionROUTINE
        );
两者的差别在于接收数据的W S A B U F结构的用法上。你可以利用d w B u ff e r C o u n t为W S A R e c v F r o m提供一个或多个W S A B U F缓冲。提供多个缓冲,就可用发散集合了。读取的字节总数返回在l p N u m b e r O f B y t e s R e c v d中。在调用W S A R e c v F r o m时,l p F l a g s参数可以是代表
无选项的0、M S G _ O O B、M S G _ P E E K或M S G _ PA RT I A L。这些标志还可以累加起来。如果在调用这个函数时,指定M S G _ PA RT I A L,提供者就知道返回数据,即使只收到了部分消息。调用返回之后,如果只收到部分消息,就会设置M S G _ PA RT I A L标志。再次返回之后,
W S A R e c v F r o m就会把l p F r o m参数(它是一个指向S O C K A D D R结构的指针)设为发送端的地址。再次提醒大家注意, l p F r o m L e n指向S O C K A D D R结构的长度,另外,在这个函数中,它还是一个指针,指向D W O R D。最后两个参数, l p O v e r l a p p e d和l p C o m p l e t i o n R O U T I N E,用于
重叠I / O(我们将在下一章就此展开讨论)。
在无连接套接字上接收(发送)数据的另一种方法是建立连接。听起来有些奇怪吧,但事实的确如此。无连接的套接字一旦建立,便可利用S O C K A D D R参数(它被设为准备与之通信的远程接收端地址)调用c o n n e c t或W S A C o n n e c t。但事实上并没有建立连接。投入连接函数的套接字地址是与套接字关联在一起的,如此一来,才能够用R e c v和W S A R e c v来代替
r e c v f r o m和W S A R e c v F r o m。为什么呢?其原因是数据的始发处是已知的。如果在一次应用中,只和一个端点进行通信,便能很容易地与数据报套接字建立连接。

7.4.2 发送端
要在一个无连接的套接字上发送数据,有两种选择。第一种,也是最简单的一种,便是建立一个套接字,然后调用s e n d t o或W S A S e n d To。我们先来讲解s e n d t o函数,它的定义是这样的:

 int sendto( 
        SOCKET s,
        const char FAR * buf,
        int len,
        int flags,
        const struct sockaddr FAR * to,
        int tolen
       );
 除了b u f是发送数据的缓冲, l e n指明发送多少字节外,其余参数和r e c v f r o m的参数一样。另外, t o参数是一个指向S O C K A D D R结构的指针,带有接收数据的那个工作站的目标地址。
另外,也可以用Winsock 2函数W S A S e n d To。它的定义如下:

int WSASendTo(
        SOCKET s,
        LPWSABUF lpBuffers,
        DWORD dwBufferCount,
        LPWORD lpNumberOfBytesSent,
        DWORD dwFlags,
        const  struct sockaddr FAR * lpTo,
        int iToLen,
        LPWSAOVERLAPPED lpOverlapped,
        LPWSAOVERLAPPED_COMPLETTION_ROUTINE lpComplettionROUTINE
       );
       
再次提醒大家注意, W S A S e n d To和前一版本中的S e n d To函数类似。它把指向带有发给接
收端的数据的指针当作l p B u ff e r s参数, d w B u ff e r C o u n t参数指明现在的结构是多少。我们可发送多个W S A B U F结构启用发散集合I / O。在函数返回之前,W S A S e n d To把第四个参数l p N u m b e r
O f B y t e s S e n t设为真正发到接收端的字节数。l p To参数是针对具体协议的一个S O C K A D D R结构,并带有接收端的地址。i To L e n参数是S O C K A D D R结构的长度。最后两个参数, l p O v e r l a p p e d和l p C o m p l e t i o n R O U T I N E,用于重叠I / O(将在第8章讨论)。
通过接收数据的方式,就可把一个无连接的套接字连接到一个端点地址,并可以用s e n d和W S A S e n d发送数据了。这种关联一旦建立,就不能再用带有地址的s e n d t o和W S A S e n d To,
除非这个地址是投到其中一个连接函数的地址,否则调用就会失败,出现W S A E I S C O N N错误。
要取消套接字句柄与目标地址的关联,唯一的办法是在这个套接字句柄上调用c l o s e s o c k e t,
并建立一个新的套接字。
              

Posted on 2006-09-11 17:04 艾凡赫 阅读(668) 评论(1)  编辑 收藏 引用 所属分类: 网络编程

Feedback

# re: windows网络编程十一[未登录]  回复  更多评论   

2007-04-28 19:16 by mouse522
请教一下:
我现在正在做一个udp的中转服务器,我现在正在学习网络编程。服务器的功能是中转数据包。想问一下实现的方法和进一步的设计。
谢了

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理