深入理解TCP/IP协议的实现之listen(基于linux1.2.13)
- 2020 年 3 月 12 日
- 筆記
listen函数的逻辑比bind还简单。bind主要是校验和绑定ip、端口。listen则是修改socket的状态,并记录一些设置。
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; }