缓冲区满时send 阻塞分析
来源:互联网 发布:分区数据恢复 编辑:程序博客网 时间:2024/06/08 14:44
1. Send 缓冲区满时阻塞代码:
Send底层调用函数tcp_sendmsg:
tcp_sendmsg:
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
new_segment:
/* Allocate new segment. If the interface is SG,
* allocate skb fitting to single page.
*/
if (!sk_stream_memory_free(sk))
goto wait_for_sndbuf;
。。。。。。。。。。。。。。。。。。。。。
wait_for_sndbuf:
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
wait_for_memory:
if (copied)
tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH);
if ((err = sk_stream_wait_memory(sk, &timeo)) != 0)
goto do_error;
mss_now = tcp_send_mss(sk, &size_goal, flags);
}
}
out:
if (copied)
tcp_push(sk, flags, mss_now, tp->nonagle);
TCP_CHECK_TIMER(sk);
release_sock(sk);
return copied;
do_fault:
if (!skb->len) {
tcp_unlink_write_queue(skb, sk);
/* It is the one place in all of TCP, except connection
* reset, where we can be unlinking the send_head.
*/
tcp_check_send_head(sk, skb);
sk_wmem_free_skb(sk, skb);
}
do_error:
if (copied)
goto out;
out_err:
err = sk_stream_error(sk, flags, err);
TCP_CHECK_TIMER(sk);
release_sock(sk);
return err;
}
sk_stream_wait_memory:
/**
* sk_stream_wait_memory - Wait for more memory for a socket
* @sk: socket to wait for memory
* @timeo_p: for how long
*/
int sk_stream_wait_memory(struct sock *sk, long *timeo_p)
{
int err = 0;
long vm_wait = 0;
long current_timeo = *timeo_p;
DEFINE_WAIT(wait);
if (sk_stream_memory_free(sk))
current_timeo = vm_wait = (net_random() % (HZ / 5)) + 2;
while (1) {
set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN)) //如果调用close时,会唤醒调用send的任务,send会在此处返回
goto do_error;
if (!*timeo_p)
goto do_nonblock;
if (signal_pending(current))
goto do_interrupted;
clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
if (sk_stream_memory_free(sk) && !vm_wait)
break;
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
sk->sk_write_pending++;
sk_wait_event(sk, ¤t_timeo, sk->sk_err ||
(sk->sk_shutdown & SEND_SHUTDOWN) ||
(sk_stream_memory_free(sk) &&
!vm_wait));
sk->sk_write_pending--;
if (vm_wait) {
vm_wait -= current_timeo;
current_timeo = *timeo_p;
if (current_timeo != MAX_SCHEDULE_TIMEOUT &&
(current_timeo -= vm_wait) < 0)
current_timeo = 0;
vm_wait = 0;
}
*timeo_p = current_timeo;
}
out:
finish_wait(sk->sk_sleep, &wait);
return err;
do_error:
err = -EPIPE;
goto out;
do_nonblock:
err = -EAGAIN;
goto out;
do_interrupted:
err = sock_intr_errno(*timeo_p);
goto out;
2. 链路出现故障时网络超时重传
2.1. Close 调用
Sock_close -> sock_release -> inet_release -> tcp_close
Tcp_close
void tcp_close(struct sock *sk, long timeout)
调用tcp_send_fin ,启动超时定时器
2.2. 超时定时器超时处理:
tcp_retransmit_timer -> tcp_retransmit_timer -> tcp_write_timeout
/* A write timeout has occurred. Process the after effects. */
static int tcp_write_timeout(struct sock *sk)
{
struct inet_connection_sock *icsk = inet_csk(sk);
int retry_until;
bool do_reset;
if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) {
if (icsk->icsk_retransmits)
dst_negative_advice(&sk->sk_dst_cache);
retry_until = icsk->icsk_syn_retries ? : sysctl_tcp_syn_retries;
} else {
if (retransmits_timed_out(sk, sysctl_tcp_retries1)) {
/* Black hole detection */
tcp_mtu_probing(icsk, sk);
dst_negative_advice(&sk->sk_dst_cache);
}
retry_until = sysctl_tcp_retries2;
if (sock_flag(sk, SOCK_DEAD)) {
const int alive = (icsk->icsk_rto < TCP_RTO_MAX);
retry_until = tcp_orphan_retries(sk, alive);
do_reset = alive ||
!retransmits_timed_out(sk, retry_until);
if (tcp_out_of_resources(sk, do_reset))
return 1;
}
}
if (retransmits_timed_out(sk, retry_until)) {
/* Has it gone just too far? */
tcp_write_err(sk); //超时次数到
return 1;
}
return 0;
}
tcp_write_err -》tcp_done
void tcp_done(struct sock *sk)
{
if (sk->sk_state == TCP_SYN_SENT || sk->sk_state == TCP_SYN_RECV)
TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_ATTEMPTFAILS);
tcp_set_state(sk, TCP_CLOSE);
tcp_clear_xmit_timers(sk);
sk->sk_shutdown = SHUTDOWN_MASK;
if (!sock_flag(sk, SOCK_DEAD))
sk->sk_state_change(sk); //调用sock_def_wakeup唤醒此socket的任务,如send任务会被唤醒
else
inet_csk_destroy_sock(sk);
}
调用close 没有马上关闭,且在客户端起来后一段时间自动关闭:
1. 网络出现问题,进入超时重传阶段,超时重传最大时间 一般对应13~30min
2.客户端起来后,服务器超时重传又发送了一次报文,超时时间到或者对端收到后发送reset (给已经重启的客户端发送报文,客户端回复reset 报文)
- 缓冲区满时send 阻塞分析
- C++ Socket编程(二) send与recv 缓冲区与阻塞
- 非阻塞 socket 在send之后返回 WSAEWOULDBLOCK分析
- 非阻塞 socket 在send之后返回 WSAEWOULDBLOCK分析
- 非阻塞 socket 在send之后返回 WSAEWOULDBLOCK分析
- 非阻塞 socket 在send之后返回 WSAEWOULDBLOCK分析
- C# Socket.send阻塞
- send函数阻塞
- recv send 阻塞和非阻塞
- recv send 阻塞和非阻塞
- recv send 阻塞和非阻塞
- recv send 阻塞和非阻塞
- recv send 阻塞和非阻塞
- recv send 阻塞和非阻塞
- recv send 阻塞和非阻塞
- recv send 阻塞和非阻塞
- send()/recv()阻塞与非阻塞
- recv send 阻塞和非阻塞
- ButterKnife基本使用
- 天线隔离度
- C# get set 使用
- 快速排序算法的实现
- 数据库三大范式
- 缓冲区满时send 阻塞分析
- C++中命名空间
- libdvbtee
- 并查集的链表优化
- Linux命令之"wget"
- Android实现拍照、选择图片并裁剪图片功能
- ButterKnife使用详解
- TCP/IP四层协议
- 单片机==AD-DA_调整电池(27)