7-socket的實踐到內核--socket的監聽

這節我們看一下服務器端的socket監聽,還是從應用程序界面看起

listen(server_sockfd, 5);

中間的過程我們不說了,只說到達了函數sys_listen()處,不知道這個過程的朋友參考前面幾節內容。這個函數在/net/socket.c中的1370行處。

asmlinkage long sys_listen(int fd, int backlog)
{
    struct socket *sock;
    int err, fput_needed;
    int somaxconn;

    sock = sockfd_lookup_light(fd, &err, &fput_needed);
    if (sock) {
        somaxconn = sock_net(sock->sk)->core.sysctl_somaxconn;
        if ((unsigned)backlog > somaxconn)
            backlog = somaxconn;

        err = security_socket_listen(sock, backlog);
        if (!err)
            err = sock->ops->listen(sock, backlog);

        fput_light(sock->file, fput_needed);
    }
    return err;
}

sockfd_lookup_light()函數我們在前邊看到過了,我們同時比照一下sys_listen()與sys_bind()函數的差別,發現基本相同,只不同的地方就是

sock->ops->listen(sock, backlog);

這裏可以看一下我們以前提到的unix的二個結構

static const struct proto_ops unix_stream_ops

static const struct proto_ops unix_dgram_ops

這裏我們的socket是使用的第一個unix_stream_ops即tcp有連接的socket,可以看到這個結構中

    .listen =    unix_listen,

因此我們上面的sys_listen()會執行unix_listen這個鉤子函數,我們看一下,這個函數在/net/unix/Af_unix.c中的451行處

static int unix_listen(struct socket *sock, int backlog)
{
    int err;
    struct sock *sk = sock->sk;
    struct unix_sock *u = unix_sk(sk);

    err = -EOPNOTSUPP;
    if (sock->type!=SOCK_STREAM && sock->type!=SOCK_SEQPACKET)
        goto out;            /* Only stream/seqpacket sockets accept */
    err = -EINVAL;
    if (!u->addr)
        goto out;            /* No listens on an unbound socket */
    unix_state_lock(sk);
    if (sk->sk_state != TCP_CLOSE && sk->sk_state != TCP_LISTEN)
        goto out_unlock;
    if (backlog > sk->sk_max_ack_backlog)
        wake_up_interruptible_all(&u->peer_wait);
    sk->sk_max_ack_backlog    = backlog;
    sk->sk_state        = TCP_LISTEN;
    /* set credentials so connect can copy them */
    sk->sk_peercred.pid    = task_tgid_vnr(current);
    sk->sk_peercred.uid    = current->euid;
    sk->sk_peercred.gid    = current->egid;
    err = 0;

out_unlock:
    unix_state_unlock(sk);
out:
    return err;
}

從上文的註釋中我們也可以看出,這裏只支持有連接的socket,並且我們也可以看出上邊有一個sk_state用來判斷sock的狀態,同時我們也看到if (!u->addr)沒有綁定地址的socket不允許監聽,接下來,判斷一下要監聽的隊列個數,這是從我們的應用程序傳遞下來的5個連接,所以如果這個鏈接大於sock的最大連接數就要喚醒在socket中睡眠等待連接的進程,讓他們有機會與服務器端的socket連接成功。我們以前在練習中看到,listen()界面是用在服務器端的socket一側的,所以,這裏將服務器端的進程號以及狀態設置爲TCP_LISTEN,將來客戶端在connect()請求連接並經服務器端的accept()同意連接後,就會獲得這裏的服務器端的sock中關於服務進程的信息。
發佈了37 篇原創文章 · 獲贊 7 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章