T i p^TTnlsfiToti Ipu H
11 i .Li
I
n«Cif ri I
■
ep rJCPoH
i
cp.interrupt
ip^queue.xait
iIp^output
图2 TCP 协议栈在Linux 上的实现
(以下文件路径都是在2628.7内核之下,在其它内核下有可能源码的位置不一样)
输岀过程:
1、(sock_sendmsg 在 kemel/net/socket.c)
int sock_sendmsg(struct socket * sock, struct msghdr *msg, size_t size) {
struct kiocb iocb; struct sock_iocb siocb; int ret;
init_sync_kiocb(&iocb, NULL); iocb.private = & siocb; ret = —sock_sendmsg(&iocb, sock, msg, size); 讦(-EIOCBQUEUED == ret)
t
write
■
Sys^write
Sock_readv_wri tev .
read
i i recv
1
♦
Sya.recv
Sock.sendaBK
sock.recvBsg
•
-T --------- Tcp^sendasg
tcp.recvasg ]
[
tc
p
.rev. established
▼
r
tcp^vi.do^rcv1 ”
tcp rcv -it«te proc«if 1 ! tcp^transait^skb
tcp^v4^rcv
Ipjrcv
netif^receive.skb
|| cp.Btert^iBit !
ldev queue.i»it
ret = wait_on_s yn c_kiocb (&iocb); return ret;
}
2、tcp_sendmsg 在kernel/net/ipv4/tcp.c T
int tcp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t size)
{
struct sock *sk = sock->sk;
struct iovec *iov;
struct tcp_sock *tp = tcp_sk(sk);
struct sk_buff *skb;
int iovlen、flags;
int mss_now, size_goal;
int err, copied;
long timeo;
lock_sock(sk);
TCP_CHECK_TIMER(sk);
flags = msg->msg_flags;
timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
/* Wait for a connection to finish. */
讦((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_now = tcp_current_mss(sk, !(flags&MSG_OOB)); size_goal = tp->x mi t_s ize_goal;
/* 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 do_error;
while (—iovlen >= 0) {
int seglen = iov->iov_len;
unsigned char —user *from = iov->iov_base;
iov++;
while (seglen > 0) {
int copy;
skb = tcp_write_queue_tail(sk);
if (!tcp_send_head(sk) ||
(copy = size_goal - skb->len) <= 0) {
new_segment:
/* Allocate new segment. If the interface is SG
*allocate skb fitting to single page・
*/
if (!sk_stream_memory_free(sk)) goto wait_fbr_sndbuf;
skb = sk_stream_alloc_skb(sk, select_size(sk), sk->sk_allocation);
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_entail(sk, skb);
copy = size_goal;
1
/* Try to append data to the end of skb. */ if (copy > seglen)
copy = seglen;
/* Where to copy to? */ if (skb_tailroom(skb) > 0) { /* We have some space in skb
head. Superb! */ if (copy > skb_tailroom(skb)) copy = skb_tailroom(skb);
if ((err = skb_add_data(skb, from, copy)) != 0) goto do_fault;
} else {
int merge = 0;
int i = skb_shinfo(skb)->nr_frags; struct page *page = TCP_PAGE(sk);
int off=TCP_OFF(sk);
if (skb_can_coalesce(skb, i, page, off) && off != PAGE_SIZE) {
/* We can extend the last page
*fragment. */ merge = I;