网络编程实战
盛延敏
前大众点评云平台首席架构师
44207 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 40 讲
网络编程实战
15
15
1.0x
00:00/00:00
登录|注册

14丨UDP也可以是“已连接”?

性能提升
获取异步错误信息的通知
主体处理
调用connect操作,将UDP套接字和客户端client_addr进行绑定
调用recvfrom等待客户端报文到达
注册信号处理函数
绑定UDP套接字和IPv4地址
创建IPv4地址
创建UDP套接字
性能提升
获取异步错误信息的通知
绑定本地地址和端口
如何使用connect进行多播或广播
可以对一个UDP套接字进行多次connect操作吗?
UDP套接字调用connect方法
UDP客户端程序通过connect可以获得一定的性能提升
服务器端程序
connect方法
思考题
总结
性能考虑
服务器端connect的例子
UDP套接字
UDP连接

该思维导图由 AI 生成,仅供参考

你好,我是盛延敏,这里是网络编程实战的第 14 讲,欢迎回来。
在前面的基础篇中,我们已经接触到了 UDP 数据报协议相关的知识,在我们的脑海里,已经深深印上了“UDP 等于无连接协议”的特性。那么看到这一讲的题目,你是不是觉得有点困惑?没关系,和我一起进入“已连接”的 UDP 的世界,回头再看这个标题,相信你就会恍然大悟。

从一个例子开始

我们先从一个客户端例子开始,在这个例子中,客户端在 UDP 套接字上调用 connect 函数,之后将标准输入的字符串发送到服务器端,并从服务器端接收处理后的报文。当然,向服务器端发送和接收报文是通过调用函数 sendto 和 recvfrom 来完成的。
#include "lib/common.h"
# define MAXLINE 4096
int main(int argc, char **argv) {
if (argc != 2) {
error(1, 0, "usage: udpclient1 <IPaddress>");
}
int socket_fd;
socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERV_PORT);
inet_pton(AF_INET, argv[1], &server_addr.sin_addr);
socklen_t server_len = sizeof(server_addr);
if (connect(socket_fd, (struct sockaddr *) &server_addr, server_len)) {
error(1, errno, "connect failed");
}
struct sockaddr *reply_addr;
reply_addr = malloc(server_len);
char send_line[MAXLINE], recv_line[MAXLINE + 1];
socklen_t len;
int n;
while (fgets(send_line, MAXLINE, stdin) != NULL) {
int i = strlen(send_line);
if (send_line[i - 1] == '\n') {
send_line[i - 1] = 0;
}
printf("now sending %s\n", send_line);
size_t rt = sendto(socket_fd, send_line, strlen(send_line), 0, (struct sockaddr *) &server_addr, server_len);
if (rt < 0) {
error(1, errno, "sendto failed");
}
printf("send bytes: %zu \n", rt);
len = 0;
recv_line[0] = 0;
n = recvfrom(socket_fd, recv_line, MAXLINE, 0, reply_addr, &len);
if (n < 0)
error(1, errno, "recvfrom failed");
recv_line[n] = 0;
fputs(recv_line, stdout);
fputs("\n", stdout);
}
exit(0);
}
我对这个程序做一个简单的解释:
9-10 行创建了一个 UDP 套接字;
12-16 行创建了一个 IPv4 地址,绑定到指定端口和 IP;
20-22 行调用 connect 将 UDP 套接字和 IPv4 地址进行了“绑定”,这里 connect 函数的名称有点让人误解,其实可能更好的选择是叫做 setpeername
31-55 行是程序的主体,读取标准输入字符串后,调用 sendto 发送给对端;之后调用 recvfrom 等待对端的响应,并把对端响应信息打印到标准输出。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

UDP协议中的“已连接”概念是本文的重点。通过具体的例子和解释,作者深入浅出地介绍了UDP connect的作用,即为了让应用程序能够接收“异步错误”的信息。文章还讨论了收发函数的使用和服务器端connect的例子。通过对UDP套接字调用connect方法的深入分析,读者可以了解到UDP使用connect的目的是为了让程序快速获取异步错误信息的通知,并获得一定性能上的提升。此外,文章还提出了两个思考题,引发读者思考和讨论。总的来说,本文通过具体案例和技术分析,帮助读者快速了解UDP协议中“已连接”的概念,以及使用connect方法的意义和优势。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《网络编程实战》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(32)

  • 最新
  • 精选
  • Geek_63bb29
    老师,面试过程中问道udp如何实现可靠性,这个怎么答呀。要求具体每部实现

    作者回复: 我能想到的: 1.udp可以增加消息编号; 2.对每个消息编号提供ACK,在udp应用层增加应答机制; 3.没有应答的增加重传机制 4.增加缓存,ACK完的才从缓存中清除

    2020-08-21
    3
    26
  • Sancho
    老师,你好。我有两个疑问: 1.不进行connect操作,UDP套接字与服务端的地址和端口就没有产生关系,那recvfrom是怎么收到对应的报文呢? 2.UDP的connect操作,会引发内核的ICMP报文发送?如果不是,ICMP是在什么时机下发送的?

    作者回复: 1.是通过sendto函数来绑定服务端地址的,之后再通过recvfrom引用到之前的socket,这样收到的报文就是指定的服务地址和端口了; 2.不是connect导致ICMP报文,而是对应的地址和端口不可达时,一个 ICMP 报文会返回。connect只是将这个信息传递变得可能了。

    2020-07-09
    16
  • GeekAmI
    问题1:亲测可以; 问题2:可以参考https://yq.aliyun.com/articles/523036。

    作者回复: 👍

    2019-10-22
    2
    9
  • 🐗Jinx
    对于广播的话,先把广播的option打开。然后再 connect 255.255.255.255 对吗?

    作者回复: 是的。UDP的广播地址是固定的为255.255.255.255。

    2020-12-20
    7
  • Liam
    按照老师的说法,只有connect才建立socket和ip地址的映射;那么,如果不进行connect,收到信息后内核又是如何把数据交给对应的socket呢

    作者回复: 在答疑篇里统一回复了。

    2019-09-02
    4
    6
  • 沉淀的梦想
    还是不太理解为什么UDP的sendto方法会有一个"连接"过程的性能损耗,直接按照目标地址发过去不就可以了吗?我的理解是操作系统会先用ICMP协议探一探目标地址是否存在,然后再用UDP协议发送具体的数据,不知道理解的对不?

    作者回复: 我不觉得会发ICMP来探一谈。ICMP是用的时候才触发的。 这里我想表达的是操作系统协议栈在每次sendto的时候都会需要一个地址初始化的过程,如果这个过程省略掉了,是可以得到一点点性能的提升的。当然,其实这个是没有那么大的。

    2019-09-04
    4
  • duckman
    connect 将一个socket绑定到一个udp的客户端进程,其他的udp客户端进程想要再次绑定该socket(4元组)发送数据的时候就会报错。所以connect起到了 "声明式"独占的作用?

    作者回复: 也可以这么说。

    2020-12-07
    2
  • 传说中的成大大
    udp 连接套接字 这个是什么过程? 断开套接字这又是什么过程呢?

    作者回复: 没有断开,这里都是一个系统调用,告诉了一些系统内核信息而已。

    2019-09-02
    2
  • 孙升
    发现在输入完goodbye之后,服务端执行exit,后面client再去请求的时候又会被阻塞而不是返回错误,是因connect是单次操作吗?

    作者回复: 是因为之前发送成功了,所以没有ICMP不可达的报文收到,因而进入了阻塞状态。

    2021-12-16
    1
  • 一个戒
    老师,请问第一个程序中,在没有开启服务端的情况下开启客户端,不会在第20行connect的时候就error报错了吗?为什么还能接收标准输入并send出去?

    作者回复: 这个是UDP哦,不是TCP。 通常在服务器端不开启的情况下,UDP客户端程序是不会报错的,程序只会阻塞在 recvfrom 上,等待返回(或者超时)。UDP的connect并不是真正的conncect操作,它只是给UDP 套接字建立了“上下文”。

    2020-11-29
    1
收起评论
显示
设置
留言
32
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部