(1)确保连接状态: 当调用发送函数(如 tcp_sendmsg_locked )时,如果调用的时候套接字没有完全建立完成。那这个函数就会阻塞当前进程 (2)另外就是处理连接建立中的异常情况:在等待连接的过程中,如果检测到错误(如网络故障)或者进程收到信号, sk_stream_wait_connect 会及时返回错误码,通知上层调用者进行相应的处理...
继续追查tcp_sendmsg_locked函数: inttcp_sendmsg_locked(structsock *sk,structmsghdr *msg,size_tsize){structtcp_sock*tp=tcp_sk(sk);structubuf_info*uarg=NULL;structsk_buff*skb;structsockcm_cookiesockc;intflags, err, copied =0;intmss_now =0, size_goal, copied_syn =0;boolprocess_backlog ...
TCP 调用 tcp_sendmsg 函数, UDP调用send()/sendto()/sendmsg() 三个 system call 中的任意一个来发送 UDP message,它们最终都会调用内核中的 udp_sendmsg() 函数。 3.3.2 传输层 tcp_sendmsg实际上调用的是tcp_sendmsg_locked函数。 在tcp_sendmsg_locked中,完成的是将所有的数据组织成发送队列,这个发送队列...
首先在分配发送skb之前,判断发送缓存是否可用,不可用的话,跳转到wait_for_sndbuf标签,虽然字面上是等待缓存变得可用,但是如果用户设置了MSG_DONTWAIT标志,不执行等待直接返回。详细信息将函数sk_stream_wait_memory。此处设置了套接口的SOCK_NOSPACE标志。 int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg...
先调用tcp_sendmsg 函数,把用户层的数据填充到skb中。在tcp_sendmsg_locked中,将数据整理成发送队列,每个队列中的元素就是skb。 计算校验和和顺序号,保证数据的可靠传输。 数据创建之后调用tcp_push()来发送,tcp_push函数调用tcp_write_xmit()函数,它又将调用发送函数tcp_transmit_skb,所有的SKB都经过该函数进行发...
所以,在我们第二次调用write时,当执行到tcp_sendmsg_locked方法时,就直接跳到了do_error,即:返回err给用户。 至此,就完美解释了,为什么会有上述奇怪的现象。 其实,我们不用看代码,仔细想想tcp的细节,也是可以理解,操作系统为什么会有这样的行为。 在第一次write之前,我们的socket收到fin包,进入到CLOSE_WAIT状态,...
EXPORT_SYMBOL_GPL(tcp_sendmsg_locked); 该方法就是tcp发消息的方法。 由上可见,只有当socket发生错误时,或者我们关闭了socket的send端,上面的write方法才会返回错误,其他情况下,write的数据都会正常发送。 由tcp的相关知识我们可以知道,当服务端发送fin消息给客户端时,客户端的socket进入了CLOSE_WAIT状态,即:等待客...
所以,在我们第二次调用write时,当执行到tcp_sendmsg_locked方法时,就直接跳到了do_error,即:返回err给用户。 至此,就完美解释了,为什么会有上述奇怪的现象。 其实,我们不用看代码,仔细想想tcp的细节,也是可以理解,操作系统为什么会有这样的行为。 在第一次write之前,我们的socket收到fin包,进入到CLOSE_WAIT状态,...
在tcp_sendmsg_locked中,完成的是将所有的数据组织成发送队列,这个发送队列是struct sock结构中的一个域sk_write_queue,这个队列的每一个元素是一个skb,里面存放的就是待发送的数据。然后调用了tcp_push()函数。结构体struct sock如下: struct sock{
先调用tcp_sendmsg 函数,把用户层的数据填充到skb中。在tcp_sendmsg_locked中,将数据整理成发送队列,每个队列中的元素就是skb。 计算校验和和顺序号,保证数据的可靠传输。 数据创建之后调用tcp_push()来发送,tcp_push函数调用tcp_write_xmit()函数,它又将调用发送函数tcp_transmit_skb,所有的SKB都经过该函数进行发...