握手6

当服务器端接收到该报文后,处理流程和上边一样,会唤醒阻塞在该sock 上的接口,通知进程可以对该文件进行读写。

下面服务器端会调用 accept 函数,该函数的主要作用是从已经实现过三次握手的sock 中取出一个sock,来进行通信。

/*
 * This will accept the next outstanding connection.
 */
struct sock *inet_csk_accept(struct sock *sk, int flags, int *err)
{
    struct inet_connection_sock *icsk = inet_csk(sk);
    struct request_sock_queue *queue = &icsk->icsk_accept_queue;
    struct sock *newsk;
    struct request_sock *req;
    int error;

    lock_sock(sk);

    /* We need to make sure that this socket is listening,
     * and that it has something pending.
     */
    error = -EINVAL;
    if (sk->sk_state != TCP_LISTEN)
        goto out_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;
    }
    req = reqsk_queue_remove(queue);// 从已完成的连接队列中移除。
    newsk = req->sk;

    sk_acceptq_removed(sk);
    if (sk->sk_protocol == IPPROTO_TCP && queue->fastopenq != NULL) {
        spin_lock_bh(&queue->fastopenq->lock);
        if (tcp_rsk(req)->listener) {
            /* We are still waiting for the final ACK from 3WHS
             * so can't free req now. Instead, we set req->sk to
             * NULL to signify that the child socket is taken
             * so reqsk_fastopen_remove() will free the req
             * when 3WHS finishes (or is aborted).
             */
            req->sk = NULL;
            req = NULL;
        }
        spin_unlock_bh(&queue->fastopenq->lock);
    }
out:
    release_sock(sk);
    if (req)
        __reqsk_free(req);
    return newsk;// 返回一个用于通信的 sock
out_err:
    newsk = NULL;
    req = NULL;
    *err = error;
    goto out;
}

至此双方的 sock 都处于 TCP_ESTABLISHED 状态,可以用于通信喽。

原文地址:https://www.cnblogs.com/guoyu1024/p/10597167.html