本文的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的确实比较复杂。