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

📄 276.htm

📁 unix高级编程原吗
💻 HTM
📖 第 1 页 / 共 3 页
字号:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>CTerm非常精华下载</title>
</head>
<body bgcolor="#FFFFFF">
<table border="0" width="100%" cellspacing="0" cellpadding="0" height="577">
<tr><td width="32%" rowspan="3" height="123"><img src="DDl_back.jpg" width="300" height="129" alt="DDl_back.jpg"></td><td width="30%" background="DDl_back2.jpg" height="35"><p align="center"><a href="http://apue.dhs.org"><font face="黑体"><big><big>apue</big></big></font></a></td></tr>
<tr>
<td width="68%" background="DDl_back2.jpg" height="44"><big><big><font face="黑体"><p align="center">               ● UNIX网络编程                       (BM: clown)                </font></big></big></td></tr>
<tr>
<td width="68%" height="44" bgcolor="#000000"><font face="黑体"><big><big><p   align="center"></big></big><a href="http://cterm.163.net"><img src="banner.gif" width="400" height="60" alt="banner.gif"border="0"></a></font></td>
</tr>
<tr><td width="100%" colspan="2" height="100" align="center" valign="top"><br><p align="center">[<a href="index.htm">回到开始</a>][<a href="192.htm">上一层</a>][<a href="277.htm">下一篇</a>]
<hr><p align="left"><small>发信人: guru (好读书,不求甚解), 信区: UNP <br>

标  题: 一个简易的proxy程序的开发过程(1) <br>

发信站: UNIX编程 (2001年10月03日21:02:48 星期三), 站内信件 <br>

  <br>

:http://www.linuxaid.com.cn/developer/showdev.jsp?i=341 <br>

一个简易的proxy程序的开发过程(1) <br>

http://LinuxAid.com.cn 01-07-19 17:24 1445p ariesram <br>

---------------------------------------------------------------------------- <br>

---- <br>

一个简易的proxy程序的开发过程(1) <br>

1、引言 <br>

很多人都看过Eric Steven Raymond写的<<The Cathedral and the Bazaar>> (大教堂与 <br>

集市) 这篇文章吧。 <br>

这篇文章讲述了传统的开发小组开发方式和基于Internet的分散的开发方式(linux的开 <br>

发方式,GNU软件的 <br>

开发方式)的区别,并且根据自己的一个程序的开发例子来讲述了The Bazaar开发方式 <br>

的若干条重要原则。 <br>

不过,国内很多程序员,工作的时候还是采用的传统的开发方式,很难有机会在工作中 <br>

体验这些原则。那么, <br>

这个例子就给了大家又一个体验这些原则的过程。 <br>

这个例子,主要是运用了一些编程的技术,比如,socket编程,信号,进程,还有一些 <br>

unix socket编程的较 <br>

高级论题。当然,这些都不是主要的,重要的是,体验一下集市的开发方式。 <br>



2、开发这个proxy程序的背景 <br>

我工作的时候,处在一个比较封闭的网络环境中。我的机器在局域网 (LAN) 之中,与外 <br>

界的Internet相连采 <br>

用了代理的方式,有若干台unix服务器作为代理服务器,运行squid作为http的代理,运 <br>

行socks作为socks 5 <br>

代理。应该说,这样的待遇,还算不错,:-), 要浏览网站,squid够用了;要运行ICQ, <br>

 OICQ之类的程序,用 <br>

socks也够了。但是,我遇到了一个比较麻烦的问题,在这样的网络环境中,我没有办法 <br>

用Outlook等工具收取 <br>

非来自公司邮件服务器的邮件(比方说,@linuxaid.com.cn, @163.net, @sina.com.cn <br>

 等等);也没有办法用 <br>

Gravity等工具来收取USENET上的讨论。当然,折衷的办法还是有,我可以用linux下的 <br>

一些支持socks的邮件 <br>

客户端软件和新闻组阅读软件。但是,这样势必造成一些麻烦( 实际上我也这样做过 <br>

),当我需要收取邮件 <br>

或者阅读新闻组的时候,我必须重新启动机器转换到linux操作系统中去,而当我要办公 <br>

的时候,我又不得不 <br>

重新启动机器再转换到windows操作系统中来 ( 我不得不说,linux作为办公的桌面还是 <br>

不如windows, 虽然这 <br>

句话肯定会惹恼很多linux fan :-) )。作为一个程序员,我当然不能忍受这种麻烦。我 <br>

必须想办法来解决这 <br>

个问题。经过考虑,我有了一个好的想法。 <br>



这体现了The Bazaar原则一: <br>

Every good work of software starts by scratching a developer's personal itch <br>

. <br>

每一个软件的开发都是带有开发者自己的烙印。 <br>

3、初期设计 <br>

我需要的是一个程序,他能够做"二传手"的工作。他自身处在能同时连通外界目标服务 <br>

器和我的机器的位置上。 <br>

我的机器把请求发送给他,他接受请求,把请求原封不动的抄下来发送给外界目标服务 <br>

器;外界目标服务器 <br>

响应了请求,把回答发送给他,他再接受回答,把回答原封不动的抄下来发送给我的机 <br>

器。这样,我的机器 <br>

实际上是把他当作了目标服务器( 由于是原封不动的转抄,请求和回答没有被修改 ) <br>

。而他则是外界目标 <br>

服务器的客户端( 由于是原封不动的转抄,请求和回答没有被修改 )。我把这种代理 <br>

服务程序叫做"二传手"。 <br>

原理图如下: <br>

|--------------| |-----------------| |--------------------| <br>

| |------------------>| |---------------->| | <br>

| 我的机器 | | 代理服务程序 | | 目标服务器 | <br>

| |<------------------| |<----------------| | <br>

|--------------| |-----------------| |--------------------| <br>

4、例子重用 <br>

4、例子重用 <br>

The Bazaar原则二: <br>

Good programmers know what to write. Great ones know what to rewrite (and re <br>

use). <br>

好的程序员知道写什么。而伟大的程序员知道重写和重用什么。 <br>

基于这个原则,我当然不会从头来写这个程序(其实,这个程序是一个很小的程序,没 <br>

有必要一定要这么做。 <br>

但是,为了给大家,同时也是给我自己一个集市化的开发方式的体验,我还是这么做了 <br>

,我先是写出来了一个 <br>

简单的程序---附在本文最后----然后才想起来去找找有没有类似的程序 :-), 结果浪费 <br>

了很多时间)。 <br>

在网上找了找,花了大概半个小时( 和我写出第一个简单程序所花的时间差不多 :-) <br>

),找到了这个程序。 <br>

程序如下: <br>

---------------------------------------------------------------------------- <br>

-------------------- <br>

/*************************************************************************** <br>

* <br>

  program: proxyd <br>

  module: proxyd.c <br>

  summary: provides proxy tcp service for a host on an isolated network. <br>

  programmer: Carl Harris (ceharris@vt.edu) <br>

  date: 22 Feb 94 <br>



  description: <br>

        This code implements a daemon process which listens for tcp connec- <br>

        tions on a specified port number. When a connection is established, <br>

        a child is forked to handle the new client. The child then estab- <br>

        lishes a tcp connection to a port on the isolated host. The child <br>

        then falls into a loop in which it writes data to the isolated host <br>

        for the client and vice-versa. Once a child has been forked, the <br>

        parent resumes listening for additional connections. <br>

        The name of the isolated host and the port to serve as proxy for, <br>

        as well as the port number the server listen on are specified as <br>

        command line arguments. <br>

 *************************************************************************** <br>

*/ <br>

#include <stdio.h> <br>

#include <ctype.h> <br>

#include <errno.h> <br>

#include <signal.h> <br>

#include <sys/types.h> <br>

#include <sys/socket.h> <br>

#include <sys/file.h> <br>

#include <sys/ioctl.h> <br>

#include <sys/wait.h> <br>



#include <netinet/in.h> <br>

#include <netdb.h> <br>

#define TCP_PROTO "tcp" <br>

int proxy_port; /* port to listen for proxy connections on */ <br>

struct sockaddr_in hostaddr; /* host addr assembled from gethostbyname() */ <br>

extern int errno; /* defined by libc.a */ <br>

extern char *sys_errlist[]; /* defined by libc.a */ <br>

void parse_args (int argc, char **argv); <br>

void daemonize (int servfd); <br>

void do_proxy (int usersockfd); <br>

void reap_status (void); <br>

void errorout (char *msg); <br>

/*************************************************************************** <br>

* <br>

  function: main <br>

  description: Main level driver. After daemonizing the process, a socket <br>

                 is opened to listen for connections on the proxy port, <br>

                 connections are accepted and children are spawned to handle <br>

  <br>

                 each new connection. <br>

  arguments: <br>

    argc,argv you know what those are. <br>



  return value: none. <br>

  calls: parse_args, do_proxy. <br>

  globals: reads proxy_port. <br>

 *************************************************************************** <br>

*/ <br>

main (argc,argv) <br>

int argc; <br>

char **argv; <br>

{ <br>

  int clilen; <br>

  int childpid; <br>

  int sockfd, newsockfd; <br>

  struct sockaddr_in servaddr, cliaddr; <br>

  parse_args(argc,argv); <br>

  /* prepare an address struct to listen for connections */ <br>

  bzero((char *) &servaddr, sizeof(servaddr)); <br>

  servaddr.sin_family = AF_INET; <br>

  servaddr.sin_addr.s_addr = htonl(INADDR_ANY); <br>

  servaddr.sin_port = proxy_port; <br>

  /* get a socket... */ <br>

  if ((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0) { <br>

    fputs("failed to create server socket <br>



",stderr); <br>

    exit(1); <br>

  } <br>

  /* ...and bind our address and port to it */ <br>

  if (bind(sockfd,(struct sockaddr_in *) &servaddr,sizeof(servaddr)) < 0) { <br>

    fputs("faild to bind server socket to specified port <br>

",stderr); <br>

    exit(1); <br>

  } <br>

  /* get ready to accept with at most 5 clients waiting to connect */ <br>

  listen(sockfd,5); <br>

  /* turn ourselves into a daemon */ <br>

  daemonize(sockfd); <br>

  /* fall into a loop to accept new connections and spawn children */ <br>

  while (1) { <br>

    /* accept the next connection */ <br>

    clilen = sizeof(cliaddr); <br>

    newsockfd = accept(sockfd, (struct sockaddr_in *) &cliaddr, &clilen); <br>

    if (newsockfd < 0 && errno == EINTR) <br>

      continue; /* a signal might interrupt our accept() call */ <br>

    else if (newsockfd < 0) <br>

      /* something quite amiss -- kill the server */ <br>



      errorout("failed to accept connection"); <br>

    /* fork a child to handle this connection */ <br>

    if ((childpid = fork()) == 0) { <br>

      close(sockfd); <br>

      do_proxy(newsockfd); <br>

      exit(0); <br>

    } <br>

    /* if fork() failed, the connection is silently dropped -- oops! */ <br>

    close(newsockfd); <br>

  } <br>

} <br>

/*************************************************************************** <br>

* <br>

  function: parse_args <br>

  description: parse the command line args. <br>

  arguments: <br>

    argc,argv you know what these are. <br>

  return value: none. <br>

  calls: none. <br>

  globals: writes proxy_port, writes hostaddr. <br>

 *************************************************************************** <br>

*/ <br>

*/ <br>

void parse_args (argc,argv) <br>

int argc; <br>

char **argv; <br>

{ <br>

  int i; <br>

  struct hostent *hostp; <br>

  struct servent *servp; <br>

  unsigned long inaddr; <br>

  struct { <br>

    char proxy_port [16]; <br>

    char isolated_host [64]; <br>

    char service_name [32]; <br>

  } pargs; <br>

  if (argc < 4) { <br>

    printf("usage: %s <proxy-port> <host> <service-name|port-number> <br>

", <br>

           argv[0]); <br>

    exit(1); <br>

  } <br>

  strcpy(pargs.proxy_port,argv[1]); <br>

  strcpy(pargs.isolated_host,argv[2]); <br>

  strcpy(pargs.service_name,argv[3]); <br>



  for (i = 0; i < strlen(pargs.proxy_port); i++) <br>

    if (!isdigit(*(pargs.proxy_port + i))) <br>

      break; <br>

  if (i == strlen(pargs.proxy_port)) <br>

    proxy_port = htons(atoi(pargs.proxy_port)); <br>

  else { <br>

    printf("%s: invalid proxy port <br>

",pargs.proxy_port); <br>

    exit(0); <br>

  } <br>

  bzero(&hostaddr,sizeof(hostaddr)); <br>

  hostaddr.sin_family = AF_INET; <br>

  if ((inaddr = inet_addr(pargs.isolated_host)) != INADDR_NONE) <br>

    bcopy(&inaddr,&hostaddr.sin_addr,sizeof(inaddr)); <br>

  else if ((hostp = gethostbyname(pargs.isolated_host)) != NULL) <br>

    bcopy(hostp->h_addr,&hostaddr.sin_addr,hostp->h_length); <br>

  else { <br>

    printf("%s: unknown host <br>

",pargs.isolated_host); <br>

    exit(1); <br>

  } <br>

  if ((servp = getservbyname(pargs.service_name,TCP_PROTO)) != NULL) <br>



    hostaddr.sin_port = servp->s_port; <br>

  else if (atoi(pargs.service_name) > 0) <br>

    hostaddr.sin_port = htons(atoi(pargs.service_name)); <br>

  else { <br>

    printf("%s: invalid/unknown service name or port number <br>

", <br>

           pargs.service_name); <br>

    exit(1); <br>

  } <br>

} <br>

/*************************************************************************** <br>

* <br>

  function: daemonize <br>

  description: detach the server process from the current context, <br>

                 creating a pristine, predictable environment in which it <br>

                 will execute. <br>

  arguments: <br>

    servfd file descriptor in use by server. <br>

  return value: none. <br>

  calls: none. <br>

  globals: none. <br>

 *************************************************************************** <br>



*/ <br>

void daemonize (servfd) <br>

int servfd; <br>

{ <br>

  int childpid, fd, fdtablesize; <br>

  /* ignore terminal I/O, stop signals */ <br>

  signal(SIGTTOU,SIG_IGN); <br>

  signal(SIGTTIN,SIG_IGN); <br>

  signal(SIGTSTP,SIG_IGN); <br>

  /* fork to put us in the background (whether or not the user <br>

     specified '&' on the command line */ <br>

  if ((childpid = fork()) < 0) { <br>

    fputs("failed to fork first child <br>

",stderr); <br>

    exit(1); <br>

  } <br>

  else if (childpid > 0) <br>

    exit(0); /* terminate parent, continue in child */ <br>

  /* dissociate from process group */ <br>

  if (setpgrp(0,getpid()) < 0) { <br>

    fputs("failed to become process group leader <br>

",stderr); <br>

",stderr); <br>

    exit(1); <br>

  } <br>

  /* lose controlling terminal */ <br>

  if ((fd = open("/dev/tty",O_RDWR)) >= 0) { <br>

    ioctl(fd,TIOCNOTTY,NULL); <br>

    close(fd); <br>

  } <br>

  /* close any open file descriptors */ <br>

  for (fd = 0, fdtablesize = getdtablesize(); fd < fdtablesize; fd++) <br>

    if (fd != servfd) <br>

      close(fd); <br>

  /* set working directory to / to allow filesystems to be unmounted */ <br>

  chdir("/"); <br>

  /* clear the inherited umask */ <br>

  umask(0); <br>

  /* setup zombie prevention */ <br>

  signal(SIGCLD,reap_status); <br>

} <br>

/*************************************************************************** <br>

* <br>

  function: do_proxy <br>

⌨️ 快捷键说明

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