zoukankan      html  css  js  c++  java
  • Proxy源代码分析 谈Linux收集编程身手

      来历:网海拾贝  




    Linux是一个可靠性特别很是高的把持系统,但是扫数效过Linux的友人都市觉获得,Linux和Windows多么的"傻瓜"把持系统(这里丝毫没有抬高Windows的意思,相反这应该是Windows的利益)比拟,后者无疑在易把持性上更胜一筹。但是为什么又有那么多的乐趣者钟情于Linux呢,当然自由是最吸惹人的一点,别的Linux强盛的功用也是一个特别很是次要的缘由,尤其是Linux强盛的收集功用更是惹人瞩目。放眼今天的WAP营业、银行收集营业和已经红透半边天的电子商务,都越来越倚重基于Linux的处置方案。因此Linux收集编程是特别很是次要的,而且当我们一构兵到Linux收集编程,我们就会发现这是一件特别很是有心思的事变,因为畴昔一些关于收集通信观念貌同实异的处所,在这一段段代码面前即速就豁然沉闷了。在刚下手着手学习编程的时分总是让人以为有点理不清眉目,不过只需多读几段代码,很快我们就能体会到其中的乐趣了。下面我就从一段Proxy源代码下手着手,谈谈如何休止Linux收集编程。

    首先声明,这段源代码不是我编写的,让我们谢谢这位名叫Carl Harris的大年夜虾,是他编写了这段代码并将其散播到网上供大家学习商洽。这段代码固然只是刻画了最复杂的proxy把持,但它的确是经典,它不但清楚地刻画了客户机/效劳器系统的观念,而且的确包含了Linux收集编程的方方面面,特别很是适合Linux收集编程的初学者学习。

    这段Proxy法式的用法是多么的,我们可以运用这个proxy登录别的主机的效劳端口。假定编译后生成了名为Proxy的可实行文件,那么号令及其参数的刻画为:

    ./Proxy

    其中参数proxy_port是指由我们指定的代庖署理效劳器端口。参数remote_host是指我们停留衔接的长途主机的主机名,IP地点也异常无效。这个主机名在收集上应该是独一的,假定您不确定的话,可以在长途主机上运用uname -n号令查察一下。参数service_port是长途主机可供给的效劳名,也可直接键入效劳对应的端口号。这个号令的相应把持是将代庖署理效劳器的proxy_port端口绑定到remote_host的service_port端口。然后我们就可以经由代庖署理效劳器的proxy_port端口拜访remote_host了。譬喻一台较量争论机,收集主机名是legends,IP地点为10.10.8.221,假定在我的较量争论机上实行:

    [root@lee /root]#./proxy 8000 legends telnet

    那么我们就可以经由下面这条号令拜访legends的telnet端口。

      [root@lee /root]#telnet legends 8000
      Trying 10.10.8.221...
      Connected to legends(10.10.8.221).
      Escape character is '^]'
      Red Hat Linux release 6.2(Zoot)
      Kernel 2.2.14-5.0 on an i686
      Login:

    下面的绑定把持也可以运用下面的号令:

    [root@lee /root]#./proxy 8000 10.10.8.221 23

    23是telnet效劳的榜样楷模端口号,别的效劳的对应端口号我们可以在/etc/services中查察。

    下面我就从这段代码动身谈谈我对Linux收集编程的一些深刻的熟悉,舛错的处所还请各位大年夜虾多多批评匡正。

    ◆main()函数
      #include 
      #include 
      #include 
      #include 
      #include 
      #include 
      #include 
      #include 
      #include 
      #include 
      #include 
      #define TCP_PROTO   "tcp" 
      int proxy_port;    /* port to listen for proxy connections on */ 
    struct sockaddr_in hostaddr;   /* host addr assembled from gethostbyname() */ 
      extern int errno;   /* defined by libc.a */ 
      extern char *sys_myerrlist[]; 
      void parse_args (int argc, char **argv); 
      void daemonize (int servfd); 
      void do_proxy (int usersockfd); 
      void reap_status (void); 
      void errorout (char *msg);
      /*This is my modification. 
      I'll tell you why we must do this later*/
      typedef void Signal(int);
      /指点指点指点指点指点指点指点指点指点指点****
      function:    main 
      description:
    Main level driver. After daemonizing the process,
     a socket is opened to listen for connections on the proxy port,
     connections are accepted and children are spawned to
    handle each new connection. 
      arguments:    argc,argv you know what those are. 
      return value:  none. 
      calls:      parse_args, do_proxy. 
      globals:     reads proxy_port. 
      指点指点指点指点指点指点指点指点指点指点****/
      main (argc,argv) 
      int argc; 
      char **argv; 
      { 
         int clilen; 
         int childpid; 
         int sockfd, newsockfd; 
         struct sockaddr_in servaddr, cliaddr; 
         parse_args(argc,argv); 
         /* prepare an address struct to listen for connections */ 
         bzero((char *) &servaddr, sizeof(servaddr)); 
         servaddr.sin_family = AF_INET; 
         servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 
         servaddr.sin_port = proxy_port; 
         /* get a socket... */ 
         if ((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0) { 
           fputs("failed to create server socketrn",stderr); 
           exit(1); 
         } 
         /* ...and bind our address and port to it */ 
         if   (bind(sockfd,(struct sockaddr_in *) &servaddr,sizeof(servaddr)) < 0) { 
           fputs("faild to bind server socket to specified portrn",stderr); 
           exit(1); 
          } 
         /* get ready to accept with at most 5 clients waiting to connect */ 
         listen(sockfd,5); 
        /* turn ourselves into a daemon */ 
        daemonize(sockfd); 
        /* fall into a loop to accept new connections and spawn children */ 
        while (1) {
          /* accept the next connection */ 
          clilen = sizeof(cliaddr); 
          newsockfd = accept(sockfd, (struct sockaddr_in *) &cliaddr, &clilen); 
          if (newsockfd < 0 && errno == EINTR) 
            continue; 
          /* a signal might interrupt our accept() call */ 
          else if (newsockfd < 0) 
            /* something quite amiss -- kill the server */ 
          errorout("failed to accept connection");
          /* fork a child to handle this connection */ 
          if ((childpid = fork()) == 0) { 
            close(sockfd); 
            do_proxy(newsockfd); 
            exit(0); 
           } 
          /* if fork() failed, the connection is silently dropped -- oops! */ 
           lose(newsockfd); 
           } 
         }

    下面便是Proxy源代码的主法式部分,大年夜概您在网上也已经看到过这段代码,不过仔细的您会发现在下面这段代码中我批改了两个处所,都是在预编译部分。一个处所是在定义内部字符型指针数组时,我将原代码中的

    extern char *sys_errlist[];

    批改为

    extern char *sys_myerrlist[];缘由是在我的Linux景象下头文件"stdio.h"已经对sys_errlist[]休止了如下定义:

    extern __const char *__const sys_errlist[];

    大年夜概Carl Harris在94年编写这段代码时系统还没有定义sys_errlist[],不过现在我们不批改一下的话,编译时系统就会告诉我们sys_errlist发生了定义争辩。

    别的我添加了一个函数榜样楷模定义:

    typedef void Sigfunc(int);

    详细缘由我将在背面向大家评释。

    套接字和套接字地点机关定义

    这段主法式是一段典型的效劳器法式。收集通信最次要的便是套接字的运用,在法式的一下手着手就对套接字刻画符sockfd和newsockfd休止了定义。接上去定义客户机/效劳器的套接字地点机关cliaddr和servaddr,存储客户机/效劳器的有关通信信息。然后挪用parse_args(argc,argv)函数措置赏罚号令参数。关于这个parse_args()函数我们待会儿再做引见。

    树立通信套接字

    下面便是设立设置装备摆设一个效劳器的详细进程。效劳器法式的第一个把持是树立一个套接字。这是经由挪用函数socket()来完成的。socket()函数的详细刻画为:

    #include

    #include

    int soc




    版权声明: 原创作品,容许转载,转载时请务必以超链接情势标明文章 原始情由 、作者信息和本声明。不然将清查法令责任。

  • 相关阅读:
    ls命令设计思想
    Collection框架
    Yosemite 的问题
    mac vim的alt键无法正常映射
    Word Ladder
    vim自动补全
    Clone Graph
    C# 关于接口与基类的理解(二者的区别)
    C# 操作Excel基础篇(读取Excel、写入Excel)
    C# 随机数 Radom 循环生成同一的数字
  • 原文地址:https://www.cnblogs.com/zgqjymx/p/1976141.html
Copyright © 2011-2022 走看看