zoukankan      html  css  js  c++  java
  • 【Linux 内核网络协议栈源码剖析】listen 函数剖析


    http://blog.csdn.net/wenqian1991/article/details/46712041


    listen 函数仅供服务器端调用,把一个未连接的套接字转换为一个被动套接字,指示内核应接受指向该套接字的连接请求。

    1、应用层——listen 函数

    1. #include <sys/socket.h>  
    2. int listen(int sockfd, int backlog);  
    3. /*sockfd是bind之后的套接口描述字,第二个参数规定了内核应该为相应套接口排队的最大连接个数*/  
    2、BSD Socket 层——sock_listen 函数
    1. /* 
    2.  *  Perform a listen. Basically, we allow the protocol to do anything 
    3.  *  necessary for a listen, and if that works, we mark the socket as 
    4.  *  ready for listening. 
    5.  */  
    6.     //服务器端监听客户端的连接请求  
    7. //fd表示bind后的套接字文件描述符,backlog表示排队的最大连接个数  
    8. //listen函数把一个未连接的套接字转换为一个被动套接字,  
    9. //指示内核应接受该套接字的连接请求  
    10. static int sock_listen(int fd, int backlog)  
    11. {  
    12.     struct socket *sock;  
    13.   
    14.     if (fd < 0 || fd >= NR_OPEN || current->files->fd[fd] == NULL)  
    15.         return(-EBADF);  
    16.     //给定文件描述符返回socket结构以及file结构指针,这里file参数为NULL,则表明对这个不感兴趣  
    17.     if (!(sock = sockfd_lookup(fd, NULL)))   
    18.         return(-ENOTSOCK);  
    19.     //前提是没有建立连接,该套接字已经是连接状态了,自然不需要  
    20.     if (sock->state != SS_UNCONNECTED)   
    21.     {  
    22.         return(-EINVAL);  
    23.     }  
    24.     //调用底层实现函数(inet_listen)  
    25.     if (sock->ops && sock->ops->listen)  
    26.         sock->ops->listen(sock, backlog);  
    27.     sock->flags |= SO_ACCEPTCON;//设置标识字段,表示正在监听  
    28.     return(0);  
    29. }  
    3、INET Socket 层——inet_listen 函数
    1. /* 
    2.  *  Move a socket into listening state. 
    3.  */  
    4.  //sock_listen的下层调用函数  
    5.  //这个函数主要是对sock结构中state字段的设置。listen函数到这层完成处理  
    6. static int inet_listen(struct socket *sock, int backlog)  
    7. {  
    8.     //获取sock数据结构  
    9.     struct sock *sk = (struct sock *) sock->data;  
    10.     //如果sock的端口号为0(未绑定任何端口号),则自动绑定一个本地端口号(新的未使用的最小的端口号)  
    11.     //如果事先已经绑定了一个端口号,那么这个代码将不会执行  
    12.     if(inet_autobind(sk)!=0)  
    13.         return -EAGAIN;  
    14.   
    15.     /* We might as well re use these. */   
    16.     /* 
    17.      * note that the backlog is "unsigned char", so truncate it 
    18.      * somewhere. We might as well truncate it to what everybody 
    19.      * else does.. 
    20.      */  
    21.      //等待的最大数.内核限制最大连接数是5  
    22.     if ((unsigned) backlog > 5)  
    23.         backlog = 5;  
    24.     sk->max_ack_backlog = backlog;//缓存的最大未应答数据包个数  
    25.     if (sk->state != TCP_LISTEN)//如果不是listen状态,则置位listen状态  
    26.     {  
    27.         sk->ack_backlog = 0;//缓存的未应答数据包个数清0  
    28.         sk->state = TCP_LISTEN;  
    29.     }  
    30.     return(0);  
    31. }  
    可以看出 inet_listen 函数主要就是设置 sock 的状态为TCP_LISTEN。tcp的三次握手以及四次挥手就是基于这样的一些状态。

    函数内部有调用 inet_autobind 函数,该函数是为没有绑定端口的sock结构自动绑定一个端口号(系统可用的最小端口号)

    1. /* 
    2.  *  Automatically bind an unbound socket. 
    3.  */  
    4.  //自动绑定一个本地端口号,一般用于客户端,实际应用层编程时,对于客户端我们并没有  
    5.  //特别去绑定某个端口号,而是由系统自动绑定  
    6. static int inet_autobind(struct sock *sk)  
    7. {  
    8.     /* We may need to bind the socket. */  
    9.     if (sk->num == 0)   
    10.     {  
    11.     //获取一个新的未使用的端口号  
    12.         sk->num = get_new_socknum(sk->prot, 0);  
    13.         if (sk->num == 0)   
    14.             return(-EAGAIN);  
    15.         put_sock(sk->num, sk);//加入到sock_array哈希表中  
    16.         //将一个无符号短整型数从网络字节顺序转换为主机字节顺序。大小端问题  
    17.         sk->dummy_th.source = ntohs(sk->num);//TCP首部中的source字段表示本地端口号  
    18.     }  
    19.     return 0;  
    20. }  
    listen 函数把一个未连接的套接字转换为一个被动套接字,指示内核应接受指向该套接字的连接请求,其内部实现归根到底就是设置 sock 结构的状态,设置其为 TCP_LISTEN。功能很简单。
    这个函数也是服务器端调用,其套接字的地址信息状态和bind函数执行之后是一样的,只绑定了本地地址信息,不知道对端的地址信息。

  • 相关阅读:
    jquery笔记
    linux的日常经常使用的命令
    IDEA设置类注解和方法注解(详解)
    java读取项目或包下面的属性文件方法
    枚举类的使用
    将一个浮点数转化为人民币大写字符串
    简单五子棋实现
    crontab 设置服务器定期执行备份工作
    linux创建日期文件名
    代码层读写分离实现
  • 原文地址:https://www.cnblogs.com/ztguang/p/12645495.html
Copyright © 2011-2022 走看看