深入理解TCP/IP协议的实现之listen(基于linux1.2.13)

2020-03-12 00:28:28 浏览数 (1)

listen函数的逻辑比bind还简单。bind主要是校验和绑定ip、端口。listen则是修改socket的状态,并记录一些设置。

代码语言:javascript复制
static int sock_listen(int fd, int backlog)
{
    struct socket *sock;

    if (fd < 0 || fd >= NR_OPEN || current->files->fd[fd] == NULL)
        return(-EBADF);
    if (!(sock = sockfd_lookup(fd, NULL))) 
        return(-ENOTSOCK);

    if (sock->state != SS_UNCONNECTED) 
    {
        return(-EINVAL);
    }

    if (sock->ops && sock->ops->listen)
        sock->ops->listen(sock, backlog);
    // 设置socket的监听属性,accept函数时用到    
    sock->flags |= SO_ACCEPTCON;
    return(0);
}

static int inet_listen(struct socket *sock, int backlog)
{
    struct sock *sk = (struct sock *) sock->data;
    // 如果没有绑定端口则绑定一个,并把sock加到sock_array中
    if(inet_autobind(sk)!=0)
        return -EAGAIN;

    if ((unsigned) backlog > 128)
        backlog = 128;
    // tcp接收队列的长度上限,不同系统实现不一样,具体参考tcp.c的使用
    sk->max_ack_backlog = backlog;
    // 修改socket状态,防止多次调用listen
    if (sk->state != TCP_LISTEN)
    {   
        sk->ack_backlog = 0;
        sk->state = TCP_LISTEN;
    }
    return(0);
}

// 绑定一个随机的端口,更新sk的源端口字段,并把sk挂载到端口对应的队列中,见bind函数的分析
static int inet_autobind(struct sock *sk)
{
    /* We may need to bind the socket. */
    if (sk->num == 0) 
    {
        sk->num = get_new_socknum(sk->prot, 0);
        if (sk->num == 0) 
            return(-EAGAIN);
        put_sock(sk->num, sk);
        sk->dummy_th.source = ntohs(sk->num);
    }
    return 0;
}

0 人点赞