⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 3-3.txt

📁 嵌入式LINUX9应用程序开发详解中第三章编程实例
💻 TXT
字号:
int                                                                        
   server_mode (const char *pidfile, struct sockaddr_in *phis_addr)           
   {                                                                          
     int ctl_sock, fd;                                                        
     struct servent *sv;                                                      
     int port;                                                                
     static struct  sockaddr_in server_addr;  /* Our address.  */             
     /*声明了该函数用到的一些局部变量,包括用于ftp控制链接的插口ctl_sock、使用accept函
数返回的socket链接的文件描述符、服务器环境sv、端口地址prot和服务器地址server_addr
等。*/                                                                         
     /* Become a daemon.  */                                                  
   #ifdef HAVE_DAEMON                                                         
    if (daemon(1,1) < 0)  /*调用daemon系统调用,将当前进程设置为精灵进程,因为作为一个服
务器程序,ftpd服务进程不需要控制终端。这也是绝大多数网络服务器
采取的方式。*/                                                   
  #endif                                                                     
      {                                                                      
       syslog (LOG_ERR, "failed to become a daemon");  /*如果设置精灵程序不成功,输出错误
记录到系统日志*/                     
       return -1;                                                           
      }                                                                      
    (void) signal (SIGCHLD, reapchild);  /*安装SIGCHLD信号的处理程序,以便在其子进程(具
体处理每一个客户链接的进程)结束之后,收集子进程
的退出信息。关于信号的操作,将在以后详细介绍。*/                                    
                                                                             
    /* Get port for ftp/tcp.  */                                             
    sv = getservbyname ("ftp", "tcp");  /*为了能在正确的端口上建立ftp服务,使用getservbyname
系统调用,试图取得ftp/tcp服务的端口地址,并将结构保
存到sv结构中,*/                                     
    port = (sv == NULL) ? DEFPORT : sv->s_port;  /*检查sv的值,如果sv为空,说明getservbyname
没有成功,则使用缺省的端口(ftp服务的控
制链接缺省端口号为21)。否则使用sv->sport
作为端口地址。*/                           
                                                                              
    /* Open socket, bind and start listen.  */                               
    ctl_sock = socket (AF_INET, SOCK_STREAM, 0); /*调用socket系统调用打开了网络插口,并
将新创建的插口号返回给ctl_sock。Socket
调用的第一个参数AF_INET,代表使用
IPV4协议,第二个参数SOCK_STREAM,
代表使用串行,基于流的、可靠的有连接协
议,该协议支持带外数据传输机制。*/                            
    if (ctl_sock < 0)                                                        
      {                                                                      
        syslog (LOG_ERR, "control socket: %m");                              
        return -1;                                                           
      }   /*检查socket调用是否成功执行,如果不成功,则输出错误记录到系统日志*/                                                                   
                                                                              
    /* Enable local address reuse.  */                                       
    {                                                                        
      int on = 1;                                                            
      if (setsockopt (ctl_sock, SOL_SOCKET, SO_REUSEADDR,                    
  		    (char )&on, sizeof(on)) < 0)   /* 调用setsockopt系统调用,设置本地地址可以重用*/,                      
        syslog (LOG_ERR, "control setsockopt: %m"); /*如果出错,输出错误信息*/                         
    }                                                                        
     /*下面设置服务器地址*/                                                                        
    memset (&server_addr, 0, sizeof server_addr);  /*清零该数据结构*/                          
    server_addr.sin_family = AF_INET;  /*设置使用的协议*/                                
    server_addr.sin_port = htons (port);  /*设置使用的端口*/                                    
                                                                              
    if (bind (ctl_sock, (struct sockaddr )&server_addr, sizeof server_addr))/* 将前面创建的插口绑
定到服务器地址*/
      {                                                                      
        syslog (LOG_ERR, "control bind: %m");                                
        return -1;     /*如果绑定失败,输出错误信息,返回*/                                                      
      }                                                                      
    if (listen (ctl_sock, 32) < 0)  /*开始侦听(帧听,请确认这两个哪个是正确的)客户端的链接请
求,参数32,指定了同时最多能接受的链接数*/                                         
      {                                                                      
        syslog (LOG_ERR, "control listen: %m");                              
        return -1;    /*如果出错,记录错位信息,返回。*/                                                       
}   






    /*下面,将当前进程的pid保存到pidfle文件中,并修改该文件的执行权限。*/                                                                         
    /* Stash pid in pidfile.  */                                             
    {                                                                        
     FILE pid_fp = fopen (pidfile, "w");  /*以可写方式打开pidfle文件*/                                
      if (pid_fp == NULL)                                                    
        syslog (LOG_ERR, "can't open %s: %m", PATH_FTPDPID);  /*如果打开不成功,记录错误
信息。*/                
      else                                                                   
        {                                                                    
  	fprintf (pid_fp, "%d\n", getpid());  /*使用fprintf函数,将使用getpid()系统调用取得的进程ID
写入pidfile文件*/                              
  	fchmod (fileno(pid_fp), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); /*62行调用fchmod系统调用
设置pidfle文件的权限为,
拥有者可读写,组用户和其
他用户都只能读*/         
  	fclose (pid_fp);  /*关闭该文件*/                                                 
        }                                                                    
    }                                                                        
   /*下面是一个无限循环,在循环体中,一旦侦听到有客户端链接请求后,调用fork或是vfork
创建一个新的子进程处理该客户请求,而父进程则继续侦听新的客户端链接请求。*/                                                                          
    /* Loop forever accepting connection requests and forking off            
       children to handle them.  */                                          
    while (1)                                                                
      {                                                                      
        int addrlen = sizeof (*phis_addr);                                   
        fd = accept (ctl_sock, (struct sockaddr )phis_addr, &addrlen); /*在socket上侦听客户端链接
情况。该函数是阻塞型函数,
知道有新的链接请求到了,
该函数调用才返回。下面就
是创建子进程处理该请求。
因为uCLinux中,使用vfork
替代fork函数。*/     
  #ifdef HAVE_WORKING_FORK                                                   
        if (fork () == 0) /* child */                                        
  #else                                                                      
        if (vfork () == 0) /* child */                                       
  #endif     /*根据宏HAVE_WORKING_FORK判断使用fork还是vfork来创建子进程*/                                                                
  	  {  /*下面是子进程的执行代码*/                                                                
  	  (void) dup2 (fd, 0);  /*把接受到的客户连接插口文件描述符,复制到子进程的标准输入上*/                                           
  	  (void) dup2 (fd, 1);  /*把接受到的客户连接插口文件描述符,复制到子进程的标准输出上*/                                          
  	  close (ctl_sock);   /*关闭了控制链接的插口的文件描述符ctl_sock。这样做既可以方便子进
程的操作,又可以防止子进程错误的操作标准输入输出,而引起其他安全
问题。*/                                               
  	  break;                                                           
  	   }                                                                
        close (fd);  /*父进程代码,该代码关闭了刚接受到的客户连接插口文件描述符,为继续接
受新的客户链接做好了准备。*/   
     /*父进程代码到此为止,父进程将一直在此循环接受新的客户链接,然后创建新的子进程来处
理。因为在前面设置了SIG_CHLD信号的处理函数。因此,当父进程收到SIG_CHLD信号,
父进程将调用reapchild收集子进程的退出状态。另外,当父进程收到退出信号时,则结束整
个程序的运行。 */                                                     
      }                                                                      
   /*从现在开始,以后的代码都在子进程空间执行*/                                                                         
  #ifdef WITH_WRAP                                                           
    /* In the child.  */                                                     
    if (!check_host ((struct sockaddr *)phis_addr))                          
      return -1;                                                             
  #endif   /*对客户端地址进行检查*/                                                                  
    return fd;    /*关闭fd文件描述符,因为前面已经复制了该描述符*/                                                           
  }   

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -