udp 调用connect 后切换网络会出现什么情况

本文探讨了在UDP调用connect后,网络切换导致的发包失败问题。通过分析Linux内核源码,揭示了UDP连接的目的IP绑定、连接状态及路由缓存等特性,并提出了解决网络切换后无法继续发包的方法。同时,文章提出了TCP和UDP在服务器异常关闭时的连接断开感知机制,为提高业务质量提供思考。
摘要由CSDN通过智能技术生成

Udp client端快速感知服务端异常如挂掉,udp 调用connect 后切换网络会出现什么情况

最近有点想法,有点像溜溜球的赶脚,来回总结了一下,发现以前忙忙碌碌地学习,学的也不少但是能记住不多,平时做的笔记也比较随意,很散,现在梳理感觉有点吃力,莫名的感觉到一味地瞎搞没有认真总结是一种非常不明智做法,效率真心不高。从此刻无论如何只要有新知识必须上了梳理一波,想变强必须严格要求,别懒死啊,兄弟~~~注意学习方法,积累知识,进入正题。。。

背景

最近和一个兄弟在搞可靠udp相关开发,具体实现仿照quic实现,不过做了化简,只取其可靠传输和拥塞控制相关东西,木有证书加密,木有流量控制,木有多流(这个应该是支持,没业务上啊,也算没有)。这位兄弟测试quic时发现网络切换的时候无法做连接迁移而是直接发包失败关闭链接(因为没有实现平台层网络监控,无法感知网络变化进行调整),引发了我的深思为啥我们的udp是私有协议可以做到网络切换仍然可以呢?(也没监控平台网络)比较发现quic 网络库创建socket后会去调 connect函数这样后面的发送就可以使用 send/recv 不需要sendto/recvfrom了,那到底为啥网络切换后发包会失败呢?第一步马上去百度,当也没搜出啥,只能自己玩了,直接上内核源码呗!

正题

直接跳过系统调用过程,来到 net/socket.c 文件,这里就有我们经常使用的socket编程所对应的函数,名字都一样,只不过套了宏:

SYSCALL_DEFINE3(connect, int, fd, struct sockaddr __user *, uservaddr,
		int, addrlen)
{
   
	struct socket *sock;
	struct sockaddr_storage address;
	int err, fput_needed;
    // 根据fd获取socket函数创建的socket实例
	sock = sockfd_lookup_light(fd, &err, &fput_needed);
	if (!sock)
		goto out;
	// 将用户态的远端地址考到内核
	err = move_addr_to_kernel(uservaddr, addrlen, &address);
	if (err < 0)
		goto out_put;

	err =
	    security_socket_connect(sock, (struct sockaddr *)&address, addrlen);
	if (err)
		goto out_put;
    // 调用inet_dgram_connect(ops赋值在socket创建的时候,这里不做展开)
	err = sock->ops->connect(sock, (struct sockaddr *)&address, addrlen,
				 sock->file->f_flags);
out_put:
    // 减小socket引用计数
	fput_light(sock->file, fput_needed);
out:
	return err;
}

// net/ipv4/af_inet.c
int inet_dgram_connect(struct socket *sock, struct sockaddr *uaddr,
		       int addr_len, int flags)
{
   
	struct sock *sk = sock->sk;

	if (addr_len < sizeof(uaddr->sa_family))
		return -EINVAL;
	if (uaddr->sa_family == AF_UNSPEC)
		return sk->sk_prot->disconnect(sk, flags);
    // 如果没有bind绑定端口,这里随机绑定一个,不展开
	if (!inet_sk(sk)->inet_num && inet_autobind(sk))
		return -EAGAIN;
	// ip4_datagram_connect
	return sk->sk_prot->connect(sk, uaddr, addr_len);
}

// net/ipv4/udp.c
// udp_prot->ip4_datagram_connect->__ip4_datagram_connect
int __ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
{
   
	struct inet_sock *inet = inet_sk(sk);
	struct sockaddr_in *usin = (struct sockaddr_in *) uaddr;
	struct flowi4 *fl4;
	struct rtable *rt;
	__be32 saddr;
	int oif;
	int err;


	if (addr_len < sizeof(*usin))
		return -EINVAL;

	if (usin->sin_family != AF_INET)
		return -EAFNOSUPPORT;
    // 重置路由缓存
	sk_dst_reset(sk);
    // 出口设备号,本地出口IP,即bind的地址
	oif = sk->sk_bound_dev_if;
	saddr = inet->inet_saddr;
	// 绕过
	if (ipv4_is_multicast(usin->sin_addr.s_addr)) {
   
		if (!oif)
			oif = inet->mc_index;
		if (!saddr)
			saddr = inet->mc_addr;
	}
	// 去路由表查找下一跳
	fl4 = &inet->cork.fl.u.ip4;
	rt = ip_route_connect(fl4, usin->sin_addr.s_addr, saddr,
			      RT_CONN_FLAGS(sk), oif,
			      sk->sk_protocol,
			      inet->inet_sport, usin->sin_port, sk);
	if (IS_ERR(rt)) {
   
		err = PTR_ERR(rt)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值