本文的copyleft归gfree.wind@gmail.com所有,使用GPL发布,可以自由拷贝,转载。但转载请保持文档的完整性,注明原作者及原链接,严禁用于任何商业用途。
作者:gfree.wind@gmail.com
博客:linuxfocus.blog.chinaunix.net
作者:gfree.wind@gmail.com
博客:linuxfocus.blog.chinaunix.net
- int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
- size_t size)
- {
- struct iovec *iov;
- /*
- 从通用的struct sock *sk得到struct tcp_sock *tp
- 其实只是一个强制类型转换,因为strcut sock为所有其它socket类型的第一个成员,所有可以直接对指针进行 强制类型转换
- */
- struct tcp_sock *tp = tcp_sk(sk);
- struct sk_buff *skb;
- int iovlen, flags;
- int mss_now, size_goal;
- int sg, err, copied;
- long timeo;
-
- lock_sock(sk);
- TCP_CHECK_TIMER(sk);
-
- flags = msg->msg_flags;
- /*
- 设置发送等待时间,如果设置了DONTWAIT,则timeo为0.
- 如果没有该标志,则timeo就为sock->sk_sndtimeo
- */
- timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
-
- /* Wait for a connection to finish. */
- /* 等到直到连接完成 */
- if ((1 sk->sk_state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT))
- if ((err = sk_stream_wait_connect(sk, &timeo)) != 0)
- goto out_err;
-
- /* This should be in poll */
- clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
/* 计算当前的MSS, size_goal为可发送数据的大小 */
- mss_now = tcp_send_mss(sk, &size_goal, flags);
-
- /* Ok commence sending. */
- iovlen = msg->msg_iovlen;
- iov = msg->msg_iov;
- copied = 0;
-
- err = -EPIPE;
- if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN))
- goto out_err;
-
- sg = sk->sk_route_caps & NETIF_F_SG;
/* 开始发送数据 */
- while (--iovlen >= 0) {
- size_t seglen = iov->iov_len;
- unsigned char __user *from = iov->iov_base;
-
- iov++;
-
- while (seglen > 0) {
- int copy = 0;
- int max = size_goal;
-
- skb = tcp_write_queue_tail(sk);
- /* 计算需要复制的字节数为copy */
- if (tcp_send_head(sk)) {
- if (skb->ip_summed == CHECKSUM_NONE)
- max = mss_now;
- copy = max - skb->len;
- }
-
- if (copy = 0) {
- /* 已复制完以前的数据了 */
- new_segment:
- /* Allocate new segment. If the interface is SG,
- * allocate skb fitting to single page.
- */
/* 检验是否还有空闲send buffer,若没有则跳到wait_for_sndbuf */ - if (!sk_stream_memory_free(sk))
- goto wait_for_sndbuf;
/* 申请新的skb buffer */
- skb = sk_stream_alloc_skb(sk,
- select_size(sk, sg),
- sk->sk_allocation);
- /* 若分配失败,则跳转到wait_for_memory */
- if (!skb)
- goto wait_for_memory;
-
- /*
- * Check whether we can use HW checksum.
- */
- if (sk->sk_route_caps & NETIF_F_ALL_CSUM)
- skb->ip_summed = CHECKSUM_PARTIAL;
/* 将新分配的skb添加到sk上 */
- skb_entail(sk, skb);
- copy = size_goal;
- max = size_goal;
- }
/* 下面开始复制数据,未完待续 */
今天学习的代码不多,一方面是今天的空闲时间不多,家里有不少事情,另一方面,tcp的确实比较复杂。