分享
 
 
 

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

王朝system·作者佚名  2008-05-19
窄屏简体版  字體: |||超大  

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))

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))

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

continue;

/* a signal might interrupt our accept() call */

else if (newsockfd

/* 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

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有