博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
18-UDP的connect函数
阅读量:2042 次
发布时间:2019-04-28

本文共 2427 字,大约阅读时间需要 8 分钟。

1. 面向连接的UDP

 

在上一篇中遗留了一个问题:sendto函数产生的异步错误一般是不会返回给udp套接字的(主要是因为udp是无连接的原因),如果这个错误要返回给udp套接字,那么就需要调用connect函数。

是的,你没看错,udp也可以调用connect函数达到面向连接,但是这并不意味着udp也会产生三次握手的过程。udp调用connect函数最主要的目的只是记录对端的ip地址和端口,并让内核检查是否存在错误(例如端口不可达等),然后把该错误再返回给调用connect的进程。

 

这里我们来区分一下面向连接和面向无连接的udp套接字的:

1. 对于面向无连接的udp套接字,也就是调用socket函数创建的套接字。而面向连接的udp套接字就是调用了connect函数。

 

2. 对于面向无连接的udp套接字,我们可以通过sendto函数向指定的目的ip地址和端口号发送数据,而对于面向连接的udp套接字来说,则是使用write或send函数向connect函数指定的目的ip地址和端口号发送数据。

需要注意的是,由于已连接的udp套接字调用了connect函数绑定了目的ip地址和端口,所以在调用sendto函数就不能指定目的地址了,即忽略第五,六参数(指定为null)。同理,在接收数据时,因为udp套接字只接收connect函数绑定的目的ip地址和端口的数据报,所以也不用调用recvfrom函数了,而是调用read或recv函数。

3. 面向连接的udp套接字会把错误返回给当前进程,未连接的套接字则不会返回错误,另外POSIX规定:未连接的udp套接字调用sendto函数发送数据时如果不指定目的地址会返回ENOTCONN错误,需要注意的是,对于不同的linux实现可能返回的错误也不尽相同的,例如4.4BSD实现会返回EDESTADDRREQ错误,而不是ENOTCONN错误。

 

 

修改udp客户端程序:

#include 
#include
#include
#include
#include
#include
#include
#include
#define MAXLINE 1024#define SERV_PORT 10001int main(int argc, char *argv[]){ struct sockaddr_in servaddr; int sockfd, n; char buf[MAXLINE]; sockfd = socket(AF_INET, SOCK_DGRAM, 0); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; inet_pton(AF_INET, "192.168.1.22", &servaddr.sin_addr); servaddr.sin_port = htons(SERV_PORT); //调用connect函数 int ret = connect(sockfd , (struct sockaddr *)&servaddr , sizeof(servaddr)); if(ret != 0){ perror("connect error:"); } while(fgets(buf, MAXLINE, stdin) != NULL){ n = sendto(sockfd, buf, strlen(buf), 0, NULL, 0); if(errno == ENOTCONN){ perror("sendto error:"); } n = recvfrom(sockfd, buf, MAXLINE, 0, NULL, 0); if (n == -1) perror("recvfrom error"); write(STDOUT_FILENO, buf, n); } close(sockfd); return 0;}

 

程序执行结果如下:

当udp客户端调用connect函数后,通过tcpdump抓包我们可以看到客户端和服务端双方并没有三次握手的过程。

 

此时停止服务端,再运行客户端,我们发现udp客户端的recvfrom函数返回了错误。

 

2. 多次调用connect

对于一个udp客户端来说,是可能会有多次调用connect需求的,例如:

  1. 指定新的目的ip地址和端口
  2. 断开套接字连接。

 

先说第一个需求,在tcp套接字中只能调用一次connect函数,但是在udp套接字中可以多次调用connect函数,例如当我们需要绑定新的目的ip地址和端口时就可以再次调用connect函数。

 

然后再说第二个需求,对于一个已连接的udp套接字来说,如果要断开连接可以调用connect函数并指定套接字地址结构的地址族成员为AF_UNSPEC,需要注意的是这会返回EAFNOSUPPORT错误,但是我们可以忽略这个错误,另外断开套接字连接的方式在其他linux版本中存在差异,同样的方式在某些linux系统中可能并不适用,为了便于移植,通常会将一个套接字地址结构清零并设置地址族成员为AF_UNSPEC,然后再调用connect断开一个udp套接字连接。 

struct sockaddr_in servaddr;memset(&servaddr, 0, sizeof(servaddr));//设置套接字地址族成员为AF_UNSPECservaddr.sin_family = AF_UNSPEC;//调用connect断开连接connect(sockfd, &servaddr, sizeof(servaddr));

 

转载地址:http://xpiof.baihongyu.com/

你可能感兴趣的文章
39. Combination Sum
查看>>
剑指Offer 1.二维数组中的查找
查看>>
剑指offer 2.重建二叉树
查看>>
剑指offer 3.二叉树中和为某一值的路径
查看>>
剑指offer 4.替换空格
查看>>
剑指offer 5.从尾到头打印链表
查看>>
剑指offer 6.用两个栈实现队列
查看>>
剑指offer 7.旋转数组的最小数字
查看>>
剑指offer 8-11.斐波那契数列 跳台阶 变态跳台阶 矩形覆盖
查看>>
剑指offer 12.二进制中1的个数
查看>>
剑指offer 13.数值的整数次方
查看>>
剑指offer 14.调整数组顺序使奇数位于偶数前面
查看>>
剑指offer 15.链表中倒数第k个节点
查看>>
剑指offer 16.反转链表
查看>>
剑指offer 17.合并两个排好序的链表
查看>>
剑指offer 18.树的子结构
查看>>
剑指offer 19.二叉树的镜像
查看>>
剑指offer 20.顺时针打印矩阵
查看>>
剑指offer 21.包含min函数的栈
查看>>
剑指offer 23.从上往下打印二叉树
查看>>