/* * Default Socket Callbacks */static void sock_def_wakeup(struct sock *sk){ struct socket_wq *wq; rcu_read_lock(); wq = rcu_dereference(sk->sk_wq); if (wq_has_sleeper(wq)) wake_up_interruptible_all(&wq->wait); rcu_read_unlock();}void sock_init_data(struct socket *sock, struct sock *sk){ sk->sk_state_change = sock_def_wakeup;}分割线static void __inet_hash(struct sock *sk){ struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo; struct inet_listen_hashbucket *ilb; if (sk->sk_state != TCP_LISTEN) { __inet_hash_nolisten(sk, NULL); return; } WARN_ON(!sk_unhashed(sk)); ilb = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)]; spin_lock(&ilb->lock); __sk_nulls_add_node_rcu(sk, &ilb->head); sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); spin_unlock(&ilb->lock);}void inet_hash(struct sock *sk){ if (sk->sk_state != TCP_CLOSE) { local_bh_disable(); __inet_hash(sk); local_bh_enable(); }}EXPORT_SYMBOL_GPL(inet_hash);struct proto tcp_prot = { .name = "TCP", .hash = inet_hash, .unhash = inet_unhash, .get_port = inet_csk_get_port, .h.hashinfo = &tcp_hashinfo, ......};EXPORT_SYMBOL(tcp_prot);------------------------------------------------------>分割线2/* * Move a socket into listening state. */int inet_listen(struct socket *sock, int backlog){err = inet_csk_listen_start(sk, backlog);}int inet_csk_listen_start(struct sock *sk, const int nr_table_entries){ /* There is race window here: we announce ourselves listening, * but this transition is still not validated by get_port(). * It is OK, because this socket enters to hash table only * after validation is complete. */ sk->sk_state = TCP_LISTEN; if (!sk->sk_prot->get_port(sk, inet->inet_num)) { inet->inet_sport = htons(inet->inet_num); sk_dst_reset(sk); sk->sk_prot->hash(sk); return 0; }} -----------------listen /* * This will accept the next outstanding connection. */struct sock *inet_csk_accept(struct sock *sk, int flags, int *err){ /* Find already established connection */ if (reqsk_queue_empty(queue)) { long timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); /* If this is a non blocking socket don't sleep */ error = -EAGAIN; if (!timeo) goto out_err; error = inet_csk_wait_for_connect(sk, timeo); if (error) goto out_err; }/* * Wait for an incoming connection, avoid race conditions. This must be called * with the socket locked. */static int inet_csk_wait_for_connect(struct sock *sk, long timeo){ struct inet_connection_sock *icsk = inet_csk(sk); DEFINE_WAIT(wait); int err; /* * True wake-one mechanism for incoming connections: only * one process gets woken up, not the 'whole herd'. * Since we do not 'race & poll' for established sockets * anymore, the common case will execute the loop only once. * * Subtle issue: "add_wait_queue_exclusive()" will be added * after any current non-exclusive waiters, and we know that * it will always _stay_ after any new non-exclusive waiters * because all non-exclusive waiters are added at the * beginning of the wait-queue. As such, it's ok to "drop" * our exclusiveness temporarily when we get woken up without * having to remove and re-insert us on the wait queue. */ for (;;) { prepare_to_wait_exclusive(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); release_sock(sk); if (reqsk_queue_empty(&icsk->icsk_accept_queue)) timeo = schedule_timeout(timeo); lock_sock(sk); err = 0; if (!reqsk_queue_empty(&icsk->icsk_accept_queue)) break; err = -EINVAL; if (sk->sk_state != TCP_LISTEN) break; err = sock_intr_errno(timeo); if (signal_pending(current)) break; err = -EAGAIN; if (!timeo) break; } finish_wait(sk_sleep(sk), &wait); return err;} -----------------accept/* * From tcp_input.c */int tcp_v4_rcv(struct sk_buff *skb){ struct sock *sk; sk = __inet_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest); if (!sk) goto no_tcp_socket;......no_tcp_socket: if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) goto discard_it; if (skb->len doffcsum_error: TCP_INC_STATS_BH(net, TCP_MIB_CSUMERRORS);bad_packet: TCP_INC_STATS_BH(net, TCP_MIB_INERRS); } else { tcp_v4_send_reset(NULL, skb); }discard_it: /* Discard frame. */ kfree_skb(skb); return 0;} -----------------recv------------------------------------------------------>分割线3Study总结:1.bind:绑定IP address和port num2.listen:通过sk->sk_prot->hash(sk)把绑定的IP address和port num加入tcp_hashinfo中3.accept:等待接入,休眠自己4.rcv(TCP rcv):struct sock *sk = __inet_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest),通过全局变量tcp_hashinfo,找到对应的sock对象,然后再进行其对应的其他操作5.(1)struct task_struct空间/全局变量tcp_hashinfo (2)fd/file/socket (3)tcp_hashinfo/sock (4)socket/sock6.TCP/IP的操作 socket套接字 进程空间问题:1.唤醒accept休眠的地方