UNIX网络编程——UDP 的connect函数(改进版)--good

UNIX网络编程——UDP 的connect函数(改进版)

My: 此文总结到位

1、获取对端地址是否可达?不可达,则直接返回icmp err msg消息。

2、提高性能,能把对端地址和端口信息直接写入内核缓存,减少路由操作时间。同时,减少套接字的连接操作。


=======

http://blog.csdn.net/ctthuangcheng/article/details/9470063

上一篇我们提到,除非套接字已连接,否则异步错误是不会返回到UDP套接字的。我们确实可以给UDP套接字调用connect,然而这样做的结果却与TCP连接大相径庭:没有三次握手。内核只是检查是否存在立即可知的错误(例如一个显然不可达的目的地),记录对端的IP地址和端口号(取自传递给connect的套接字地址结构),然后立即返回到调用进程。

     

     有了这个能力后,我们必须区分:

(1)未连接UDP套接字,新创建UDP套接字默认如此;

(2)已连接UDP套接字,对UDP套接字调用connect的结果。


     对于已连接UDP套接字,与默认的未连接UDP套接字相比,发生了三个变化:

(1)我们再也不能给输出操作指定目的IP地址和端口号。也就是说,我们不使用sendto,而改用write或send。写到已连接UDP套接字上的任何内容都自动发送到由connect指定的协议地址(例如IP地址和端口号)。(其实我们可以给已连接UDP套接字调用sendto,但是不能指定目的地址。sendto的第五个参数必须为空,第六个参数应该为0)。

                                         

     后面有在ubuntu 10.04系统下的验证。

(2)我们不必使用recvfrom以获悉数据报的发送者,而改用read,recv或recvmsg。在一个已连接UDP套接字上,由内核为输入操作返回的数据报只有那些来自connect所指定协议地址的数据报。确切的说,一个已连接的UDP套接字仅仅与一个IP地址交换数据报,因为connect到多播或广播地址是可能的)。

(3)由已连接的UDP套接字引发的异步错误会返回给他们所在的进程,而未连接UDP套接字不接受任何异步错误

                           

     应用进程首先调用connect指定对端的IP地址和端口号,然后使用read和write与对端进程交换数据。来自任何其他IP地址或端口的数据报(上中我们用“???”表示)不投递给这个已连接套接字,因为他们要么源IP地址要么源UDP端口不与该套接字connect到的协议地址相匹配。这些数据报可能投递给同一个主机上的其他某个UDP套接字。如果没有相匹配的其他套接字,UDP将丢弃他们并生成相应的ICMP端口不可达错误

 

1.给一个UDP套接字多次调用connect

   拥有一个已连接UDP套接字的进程可出于下列两个目的之一再次调用connect:

  • 指定新的IP地址和端口号;
  • 断开套接字。

      第一个目的(即给一个已连接UDP套接字指定新的对端)不同于TCP套接字中的connect的使用:对于TCP套接字,connect只能调用一次

      为了断开一个已UDP套接字连接,我们再次调用connect时把套接字地址结构的地址族成员(sin_family)设置为AF_UNSPEC使套接字断开连接的是在已连接UDP套接字上调用connect的进程。

 

2.性能

       在一个未连接的UDP套接字上给两个数据报调用sendto函数于是涉及内核执行下列6个步骤:

(1)连接套接字;

(2)输出第一个数据报;

(3)断开套接字连接;

(4)连接套接字;

(5)输出第二个数据报;

(6)断开套接字连接。

      调用connect后调用两次write涉及内核执行3个步骤:

(1)连接套接字;

(2)输出第一个数据报;

(3)输出第二个数据报。

 

客户端程序:

  1. #include <unistd.h>  
  2. #include <sys/types.h>  
  3. #include <sys/socket.h>  
  4. #include <netinet/in.h>  
  5. #include <arpa/inet.h>  
  6. #include <stdlib.h>  
  7. #include <stdio.h>  
  8. #include <errno.h>  
  9. #include <string.h>  
  10.   
  11. #define SERV_PORT 3333  
  12. #define MAXLINE 1024  
  13. #define ERR_EXIT(m) \  
  14.         do \  
  15.         { \  
  16.                 perror(m); \  
  17.                 exit(EXIT_FAILURE); \  
  18.         } while(0)  
  19.   
  20. typedef struct sockaddr SA;  
  21. void dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen)  
  22. {  
  23.     int     n;    
  24.     char    sendline[MAXLINE], recvline[MAXLINE + 1];  
  25. /  
  26.     struct sockaddr_in  servaddr;  
  27.     bzero(&servaddr, sizeof(servaddr));  
  28.     servaddr.sin_family = AF_INET;  
  29.     servaddr.sin_port = htons(SERV_PORT);  
  30.     inet_pton(AF_INET, "192.168.2.103", &servaddr.sin_addr);      
  31. /    
  32.     connect(sockfd, (SA *) pservaddr, servlen);    
  33.     
  34.     while (fgets(sendline, MAXLINE, fp) != NULL) {    
  35.     
  36.         n = write(sockfd, sendline, strlen(sendline));   
  37.         //n = sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);  
  38.         //n = sendto(sockfd, sendline, strlen(sendline), 0, &servaddr, sizeof(servaddr));         
  39.         //n = sendto(sockfd, sendline, strlen(sendline), 0, NULL, 0);  
  40.         if (n == -1)    
  41.         {    
  42.             if (errno == EISCONN)    
  43.                 ERR_EXIT("sendto");    
  44.             else  
  45.                 perror("sendto huangcheng");              
  46.         }         
  47.           
  48.           
  49.         //struct sockaddr_in preply_addr;  
  50.         //socklen_t addrlen;  
  51.         n = read(sockfd, recvline, MAXLINE);  
  52.         //n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL);  
  53.         //n = recvfrom(sockfd, recvline, MAXLINE, 0, (SA*)&preply_addr, &addrlen);        
  54.         if (n == -1)    
  55.         {    
  56.             if (errno == EINTR)    
  57.                 continue;    
  58.             ERR_EXIT("recvfrom");    
  59.         }   
  60.         //printf("reply from %s \n",inet_ntoa(preply_addr.sin_addr));  
  61.         recvline[n] = 0;    /* null terminate */    
  62.         fputs(recvline, stdout);  
  63.     }  
  64. }  
  65.   
  66. int main(int argc, char **argv)  
  67. {  
  68.     int                 sockfd;  
  69.     struct sockaddr_in  servaddr;  
  70.   
  71.     if (argc != 2)  
  72.         ERR_EXIT("usage: udpcli <IPaddress>");  
  73.   
  74.     bzero(&servaddr, sizeof(servaddr));  
  75.     servaddr.sin_family = AF_INET;  
  76.     servaddr.sin_port = htons(SERV_PORT);  
  77.     inet_pton(AF_INET, argv[1], &servaddr.sin_addr);  
  78.   
  79.     sockfd = socket(AF_INET, SOCK_DGRAM, 0);  
  80.   
  81.     dg_cli(stdin, sockfd, (SA *) &servaddr, sizeof(servaddr));  
  82.   
  83.     exit(0);  
  84. }  

运行结果:

  1. huangcheng@ubuntu:~$ ./cli 127.0.0.1  
  2. huangcheng  
  3. recvfrom: Connection refused  


虚拟机:

  1. huangcheng@ubuntu:~$ ifconfig  
  2. eth0      Link encap:以太网  硬件地址 00:0c:29:88:e0:1f  
  3.           inet 地址:192.168.2.103  广播:192.168.2.255  掩码:255.255.255.0  
  4.           inet6 地址: fe80::20c:29ff:fe88:e01f/64 Scope:Link  
  5.           UP BROADCAST RUNNING MULTICAST  MTU:1500  跃点数:1  
  6.           接收数据包:43472 错误:0 丢弃:0 过载:0 帧数:0  
  7.           发送数据包:19785 错误:0 丢弃:0 过载:0 载波:0  
  8.           碰撞:0 发送队列长度:1000  
  9.           接收字节:52561935 (52.5 MB)  发送字节:1925585 (1.9 MB)  
  10.           中断:19 基本地址:0x2000  
  11.   
  12. lo        Link encap:本地环回  
  13.           inet 地址:127.0.0.1  掩码:255.0.0.0  
  14.           inet6 地址: ::1/128 Scope:Host  
  15.           UP LOOPBACK RUNNING  MTU:16436  跃点数:1  
  16.           接收数据包:396 错误:0 丢弃:0 过载:0 帧数:0  
  17.           发送数据包:396 错误:0 丢弃:0 过载:0 载波:0  
  18.           碰撞:0 发送队列长度:0  
  19.           接收字节:38912 (38.9 KB)  发送字节:38912 (38.9 KB)  
  20.   
  21. huangcheng@ubuntu:~$  


验证UDP套接字,已连接:

write或send:可以

不指定目的地址的sendto:可以

指定目的地址的send:

(1)connect指定的IP地址是:127.0.0.1,sendto指定的IP地址为:127.0.0.1或者192.168.2.103  均正常。

(2)connect指定的IP地址是:127.0.0.1,sendto指定的IP地址为:192.168.4.103 即不为虚拟机的IP地址时,运行结果sendto huangcheng:Invalid argument,即出错。


注意:在<<UNIX网络编程——基于UDP协议的网络程序>>中也有UDP connect的介绍。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值