来历:网海拾贝
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
版权声明:
原创作品,容许转载,转载时请务必以超链接情势标明文章 原始情由 、作者信息和本声明。不然将清查法令责任。