Proxy源代码分析 谈Linux网络编程技术

时间:2007-05-26 07:43:35  来源:站长资讯收集整理  作者:佚名
上面的绑定操作也可以使用下面的命令:

[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

文章评论

共有 位CH网友发表了评论 查看完整内容