设为首页 加入收藏

TOP

域套接字sendto errno -11分析(一)
2023-09-09 10:25:43 】 浏览:222
Tags:sendto errno -11分析

sendto errno -11代码分析

errno -11在内核代码中代表EAGAIN(再试?次),域套接字sendto过程中 sendto->sock_sendmsg->unix_dgram_sendmsg,在unix_dgram_sendmsg中有两处会返回 EAGAIN:
第1处:sock_alloc_send_pskb
第2处:
other!=sk&&unlikely(unix_peer(other)!=sk&&unix_recvq_full_lockless(other))
unix_peer(sk)!=other||unix_dgram_peer_wake_me(sk,other)
当以上两个条件都满?时也会返回 EAGAIN。
另外需要注意的是unix_dgram_sendmsg中直接通过skb_queue_tail(&other->sk_receive_queue,skb)将数据放?了对端的接收队列中。
image

第1处
sock_alloc_send_pskb函数中当socket发送缓冲区满时( sk_wmem_alloc_get(sk)>=sk->sk_sndbuf)将返回 EAGAIN。
image
第2处

在 Linux 内核源代码中,unix_peer(other) != sk 表?另?个 Unix 域套接字( other )的对端套接字(peer socket)不等于当前套接字( sk )本?。
在 Unix 域套接字通信中,每个发起连接的进程(或线程)都必须创建两个?件描述符,?个?于客?端(client),称为客?端套接字(client socket),另?个?于服务器端
(server),称为服务器套接字(server socket)。这两个套接字通过 Unix 域?件系统中的某个路径名进?连接(bind)。
当对等?成功建?连接后,两个套接字中的?个将?动成为对?的对端套接字(peer socket)。这意味着两个对等?都有?个指向对?套接字的结构体,也就是所谓的“peer
socket”。
因此,unix_peer(other) != sk 表?当前套接字( sk )不是另?个 Unix 域套接字( other )的对端套接字。如果这个条件成?,那么就不能向 other 套接字发送数据,因为 other 并不是当前套接字的对端套接字,这种情况下发送数据可能会引发错误或者产?不确定的结果

unix_peer() 函数尝试返回指向当前 Unix Domain 套接字的对端套接字的指针,如果当前套接字不是连接状态或者没有对端套接字则返回空指针。该函数通常?于判断当前
Unix Domain 套接字是否有对端套接字,以决定是否可以进?数据发送。

  1. other!=sk, 因为 other=unix_peer_get(sk)(其实就是other=sk->peer) ,该条件意味着 sk->peer!=sk,在域套接字中 sk代表通信的?端,sk->peer代表通信的另?端,该条件是为了避免循环引?。本?档中默认 sk是客?端,other是服务端。
  2. unlikely(unix_peer(other)!=sk&&unix_recvq_full_lockless(other)),?先 unix_peer(other)!=sk意味着 sk->peer->peer!=sk说明 sk客?端所指向的服务端发?了变化(?如在客?端发送的过程中?有?个新的客?端与服务端建?了连接),其次是 unix_recvq_full_lockless(other)如下?代码所?,当条件满?时代表着 other服务端接收队列深度?于sk_max_ack_backlog
af_unix.c:
static inline int unix_recvq_full_lockless(conststructsock*sk)
{
	return skb_queue_len_lockless(&sk->sk_receive_queue)>
		READ_ONCE(sk->sk_max_ack_backlog);
}
  1. unix_peer(sk)!=other||unix_dgram_peer_wake_me(sk,other)unix_peer(sk)!=other?于判断当前 Unix Domain 套接字( sk )是否为另?个 Unix Domain 套接字(other )的对端套接字,这?只能是other发?了变化 ;在 unix_dgram_peer_wake_me中只有other端接收队列深度?于 sk_max_ack_backlog时才会 return 1
af_unix.c:
static inline int unix_recvq_full(conststructsock*sk)
{
	return skb_queue_len(&sk->sk_receive_queue) > sk->sk_max_ack_backlog;
}
static int unix_dgram_peer_wake_me(structsock*sk, structsock*other)
{
	int connected;
	connected = unix_dgram_peer_wake_connect(sk,other);
	if(unix_recvq_full(other))
		return 1;
	if(connected)
		unix_dgram_peer_wake_disconnect(sk,other);
	return 0;
}

总结

域套接字sendto errno -11存在以下可能:

  1. socket发送缓冲区满(可复现)。
  2. other的对端不是sk(本客?端)并且 unix_recvq_full_lockless成?
    2.1 sk(本客?端)的对端也不是other。
    2.2 other接收队列深度?于 sk_max_ack_backlog(可复现)。

条件2中 unix_recvq_full_lockless,代表other接收队列深度?于 sk_max_ack_backlog,不过这? unix_recvq_full_lockless调?的是 skb_queue_len_lockless是不加锁的,因此这?存在不确定性,但?少内核得到的信息是other接收队列深度?于 sk_max_ack_backlog

条件2.1和2.2成?的前提是条件2先成?。
针对条件2.1成?的可能性:
1)sk 与 other 建链,此时 sk->peer==other,other==sk->peer
2)new_sk(新的客?端)与other建链,此时 sk->peer==other,other->peer!=sk,other->peer==new_sk,new_sk->peer==other
3)new_sk?速发消息到other使 unix_recvq_full_lockless条件满?。
4)sk发消息进?unix_dgram_sendmsg内部并到达unlikely(unix_peer(other)!=sk&&unix_r

首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Java环境配置与常见问题 下一篇一台服务器上部署 Redis 伪集群

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目