热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

Proxy源代码分析--谈谈如何学习linux网络编程

文章标题:Proxy源代码分析--谈谈如何学习linux网络编程。Linux是中国IT实验室的一个技术频道。包含桌面应用,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 socket\r\n",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 port\r\n",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
推荐阅读
  • 本文介绍了在Hibernate配置lazy=false时无法加载数据的问题,通过采用OpenSessionInView模式和修改数据库服务器版本解决了该问题。详细描述了问题的出现和解决过程,包括运行环境和数据库的配置信息。 ... [详细]
  • Skywalking系列博客1安装单机版 Skywalking的快速安装方法
    本文介绍了如何快速安装单机版的Skywalking,包括下载、环境需求和端口检查等步骤。同时提供了百度盘下载地址和查询端口是否被占用的命令。 ... [详细]
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • Linux服务器密码过期策略、登录次数限制、私钥登录等配置方法
    本文介绍了在Linux服务器上进行密码过期策略、登录次数限制、私钥登录等配置的方法。通过修改配置文件中的参数,可以设置密码的有效期、最小间隔时间、最小长度,并在密码过期前进行提示。同时还介绍了如何进行公钥登录和修改默认账户用户名的操作。详细步骤和注意事项可参考本文内容。 ... [详细]
  • 本文介绍了在rhel5.5操作系统下搭建网关+LAMP+postfix+dhcp的步骤和配置方法。通过配置dhcp自动分配ip、实现外网访问公司网站、内网收发邮件、内网上网以及SNAT转换等功能。详细介绍了安装dhcp和配置相关文件的步骤,并提供了相关的命令和配置示例。 ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • Centos7.6安装Gitlab教程及注意事项
    本文介绍了在Centos7.6系统下安装Gitlab的详细教程,并提供了一些注意事项。教程包括查看系统版本、安装必要的软件包、配置防火墙等步骤。同时,还强调了使用阿里云服务器时的特殊配置需求,以及建议至少4GB的可用RAM来运行GitLab。 ... [详细]
  • Metasploit攻击渗透实践
    本文介绍了Metasploit攻击渗透实践的内容和要求,包括主动攻击、针对浏览器和客户端的攻击,以及成功应用辅助模块的实践过程。其中涉及使用Hydra在不知道密码的情况下攻击metsploit2靶机获取密码,以及攻击浏览器中的tomcat服务的具体步骤。同时还讲解了爆破密码的方法和设置攻击目标主机的相关参数。 ... [详细]
  • PHP设置MySQL字符集的方法及使用mysqli_set_charset函数
    本文介绍了PHP设置MySQL字符集的方法,详细介绍了使用mysqli_set_charset函数来规定与数据库服务器进行数据传送时要使用的字符集。通过示例代码演示了如何设置默认客户端字符集。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • 本文介绍了如何找到并终止在8080端口上运行的进程的方法,通过使用终端命令lsof -i :8080可以获取在该端口上运行的所有进程的输出,并使用kill命令终止指定进程的运行。 ... [详细]
  • 本文介绍了在Win10上安装WinPythonHadoop的详细步骤,包括安装Python环境、安装JDK8、安装pyspark、安装Hadoop和Spark、设置环境变量、下载winutils.exe等。同时提醒注意Hadoop版本与pyspark版本的一致性,并建议重启电脑以确保安装成功。 ... [详细]
  • 本文介绍了在SpringBoot中集成thymeleaf前端模版的配置步骤,包括在application.properties配置文件中添加thymeleaf的配置信息,引入thymeleaf的jar包,以及创建PageController并添加index方法。 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
author-avatar
Lucky_Leeing
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有