Chinaunix首页 | 论坛 | 博客
  • 博客访问: 517185
  • 博文数量: 91
  • 博客积分: 9223
  • 博客等级: 中将
  • 技术积分: 1777
  • 用 户 组: 普通用户
  • 注册时间: 2007-04-02 17:37
个人简介

!!!!!!!!!!!!

文章分类

全部博文(91)

文章存档

2013年(3)

2012年(4)

2011年(37)

2010年(36)

2009年(9)

2008年(2)

分类: LINUX

2009-08-12 15:33:18

基本UDP套接口编程

 

【摘要】

本文主要说明了一些关于UDP的基本套接口函数。

【关键词】

网络编程

一、问题的提出

 有关UDP的套接口编程函数了解的比较浅,需要详细了解一下。

二、解决思路

1int recvfrom(int s, void *buf, int len, unsigned int flags, struct sockaddr *from, int *fromlen)

recv()用来接口收远程主机经指定socket传来的数据,并把数据存到由参数buf指向的内存空间,参数len为接收数据的最大长度。参数flags一般设0。参数from用来指定欲传送的网络地址。参数fromlensockaddr的结构的长度,它是值-结果参数。

成功则返回接收到的字符数,失败返回-1,错误原因存于errno中。

如果from参数是一个空指针,那么相应的长度参数fromlen也必须是一个空指针,表示我们并不关心数据发送者的协议地址。

  2int sendto(int s, const void *msg, int len, unsigned int flags, const struct sockaddr *to, int tolen)

  sendto()用来将数据由指定的socket传给对方主机。参数s为已建立好连接的socket,如果利用udp协议则不需经过连接操作。参数msg指向欲连线的数据内容,参数len则为数据长度。参数flags一般设0。参数to用来指定欲传送的网络地址。参数tolensockaddr的结果长度。

成功则返回实际传送出去的字符数,失败返回-1,错误原因存于errno中。

下面客户-服务器程序中的客户端程序中的一部分。

void dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen)

{

  int n;

  char sendline[MAXLINE], recvline[MAXLINE+1];

  socklen_t len;

  struct sockaddr *preply_addr;

 

  preply_addr = Malloc(servlen);

  while(Fgets(sendline, MAXLINE, fp) != NULL)

  {

         Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);

         len = servlen;

         n = Recvfrom(sockfd, recvline, MAXLINE, 0, preply_addr, len);

         if(len!=servlen || memcmp(pservaddr, preply_addr, len)!=0)

         {

                printf("reply form %s (ignored)\n", sock_ntop(preply_addr, len));

                contiue;

         }

         recvline[n] = 0;

         Fputs(recvline, stdout);

  } 

}

如果服务器运行在一个单个IP地址的主机上,那么这个新版本的客户工作正常。然而如果服务器主机是多宿的,该客户就有可能失败。

大多数IP实现接受宿地址为本主机任一IP地址的数据报,而不管数据报到达的接口。这样成之为弱端系统模型。如果一个系统实现的是强端系统模型,那么它将只接受到达接口和宿地址一致的数据报。

Recvfrom返回的ip地址(UDP数据报的源ip地址)不是我们所发送数据报的宿ip地址。当服务器发送应答时,宿ip地址是172.24.37.94。主机内核中的路由功能为之选择172.24.37.94作为外出接口。既然服务器没有在其套接口上绑定一个实际的ip地址,因此内核将为封装这些应答的ip数据报选择源地址。选为源地址的是外出接口的主ip地址。还有,既然它是外出接口的主ip地址,如果我们指定发送数据报到该接口的某个非主ip地址,将导致上面的程序的失败。

一个解决办法是:得到有recvfrom返回的ip地址后,客户通过dns中查找服务器主机的名字来验证该主机的域名而不是它的ip地址。另外一个解决办法:udp服务器给服务器主机上配置的每个IP地址创建一个套接口,bind每个ip地址到各自的套接口,然后在所有这些套接口上使用select,再从可读的套接口给出应答。既然用于给出应答的套接口上绑定的ip地址就是客户请求的宿ip地址,这就保证应答的源地址与请求的宿地址相同。

客户的临时端口是在第一次调用sendto时一次性选定的,不能改变;然而客户的ip地址却可以随客户发送的每个udp数据报而变动(假设客户没有捆绑一个具体的ip地址到其套接口上)。如果客户捆绑了一个ip地址到其套接口上,但是内核决定外出数据报必须从另一个数据链路发出,这种情况下,ip数据报将包含一个不同于外出链路ip地址的源ip地址。

3)已连接udp套接口

对于已连接udp套接口(调用过connect),与缺省的未连接udp套接口相比,发生了三个变化:

1.不能给输出操作指定宿ip地址和套接口。也就是说,不能使用sendto(),而改写writesend。写到已连接udp套接口上的任何内容都自动发送到connect指定的协议地址。

2.不能使用recvfrom以获悉数据报的发送者,而改用readrecvrecvmsg。在一个已连接udp套接口上由内核为输入操作返回的数据报仅仅是那些来自connect所指定协议地址的数据报。目的地为这个已连接udp套接口的本地协议,发源地却不是该套接口早先connect到的协议地址的数据报,不会投递到该套接口。这样就限制一个已连接udp套接口能且仅能与一个对端交换数据报。

3.由已连接udp套接口引发的异步错误返回给它们所在的进程。相反,未连接udp套接口不接受任何异步错误。

拥有一个已连接udp套接口的进程可为下列两个目的之一再次调用connect

A.指定新的ip地址和端口号

B.断开套接口。

为了断开一个已连接udp套接口,再次调用connect时把套接口地址结构的地址族成员设置为AF_UNSPEC。这么做可能返回一个EAFNOSUPPORT错误,不过没关系。使得套接口断开连接的是在已连接udp套接口上调用connect的进程。

已连接udp套接口还可用来确定用于某个特定目的地的外出接口。这是有connect函数应用到udp套接口时的一个副作用造成的:内核选择本地ip地址(假设其进程未曾调用bind显式指派它)。这个本地ip地址通过为宿ip地址搜索路由表得到外出接口,然后选用该接口的主ip地址而选定。在udp套接口上调用connect并不给对端主机发送任何信息,它完全是一个本地操作,只是保存对端的ip地址和端口号。在一个未绑定端口号的udp套接口上调用connect同时也给该套接口指派一个临时端口。

三、总结

主要介绍了基本udp网络编程。

四、效果评价

希望对udp编程有些帮助。

阅读(2088) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~