📄 50.htm
字号:
<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>123</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="20.htm">上一层</a>][<a href="51.htm">下一篇</a>]
<hr><p align="left"><small>发信人: fist (星仔迷), 信区: LINUX <br>
标 题: Linux 网络编程入门教程 <br>
发信站: 武汉白云黄鹤站 (2001年02月20日11:51:46 星期二), 转信 <br>
<br>
章摘要: <br>
Linux网络编程是非常重要的,而且当我们一接触到Linux网络编程,我们就会发现 <br>
这是一件非常有意思的事情,因为以前一些关于网络通信概念似是而非的地方,在这一 <br>
段段代码面前马上就豁然开朗了。在刚开始学习编程的时候总是让人感觉有点理不清头 <br>
绪,不过只要多读几段代码,很快我们就能体会到其中的乐趣了。下面我就从一段Prox <br>
y源代码开始,谈谈如何进行Linux网络编程。 <br>
---------------------------------------------------------------------------- <br>
---- <br>
正文: <br>
Proxy源代码分析 <br>
--谈谈如何学习linux网络编程 <br>
Linux是一个可靠性非常高的操作系统,但是所有用过Linux的朋友都会感觉到,Li <br>
nux和Windows这样的"傻瓜"操作系统(这里丝毫没有贬低Windows的意思,相反这应该是 <br>
Windows的优点)相比,后者无疑在易操作性上更胜一筹。但是为什么又有那么多的爱好 <br>
者钟情于Linux呢,当然自由是最吸引人的一点,另外Linux强大的功能也是一个非常重 <br>
要的原因,尤其是Linux强大的网络功能更是引人注目。放眼今天的WAP业务、银行网络 <br>
业务和曾经红透半边天的电子商务,都越来越倚重基于Linux的解决方案。因此Linux网 <br>
络编程是非常重要的,而且当我们一接触到Linux网络编程,我们就会发现这是一件非常 <br>
有意思的事情,因为以前一些关于网络通信概念似是而非的地方,在这一段段代码面前 <br>
马上就豁然开朗了。在刚开始学习编程的时候总是让人感觉有点理不清头绪,不过只要 <br>
多读几段代码,很快我们就能体会到其中的乐趣了。下面我就从一段Proxy源代码开始, <br>
谈谈如何进行Linux网络编程。 <br>
首先声明,这段源代码不是我编写的,让我们感谢这位名叫Carl Harris的大虾,是 <br>
他编写了这段代码并将其散播到网上供大家学习讨论。这段代码虽然只是描述了最简单 <br>
的proxy操作,但它的确是经典,它不仅清晰地描述了客户机/服务器系统的概念,而且 <br>
几乎包括了Linux网络编程的方方面面,非常适合Linux网络编程的初学者学习。 <br>
这段Proxy程序的用法是这样的,我们可以使用这个proxy登录其它主机的服务端口 <br>
。假如编译后生成了名为Proxy的可执行文件,那么命令及其参数的描述为: <br>
./Proxy <proxy_port> <remote_host> <service_port> <br>
其中参数proxy_port是指由我们指定的代理服务器端口。参数remote_host是指我们 <br>
希望连接的远程主机的主机名,IP地址也同样有效。这个主机名在网络上应该是唯一的 <br>
,如果您不确定的话,可以在远程主机上使用uname -n命令查看一下。参数service_po <br>
rt是远程主机可提供的服务名,也可直接键入服务对应的端口号。这个命令的相应操作 <br>
是将代理服务器的proxy_port端口绑定到remote_host的service_port端口。然后我们就 <br>
可以通过代理服务器的proxy_port端口访问remote_host了。例如一台计算机,网络主机 <br>
名是legends,IP地址为10.10.8.221,如果在我的计算机上执行: <br>
[root@lee /root]#./proxy 8000 legends telnet <br>
那么我们就可以通过下面这条命令访问legends的telnet端口。 <br>
----------------------------------------------------------------- <br>
[root@lee /root]#telnet legends 8000 <br>
Trying 10.10.8.221... <br>
Connected to legends(10.10.8.221). <br>
Escape character is '^]' <br>
Red Hat Linux release 6.2(Zoot) <br>
Kernel 2.2.14-5.0 on an i686 <br>
Login: <br>
----------------------------------------------------------------- <br>
上面的绑定操作也可以使用下面的命令: <br>
[root@lee /root]#./proxy 8000 10.10.8.221 23 <br>
23是telnet服务的标准端口号,其它服务的对应端口号我们可以在/etc/service <br>
s中查看。 <br>
下面我就从这段代码出发谈谈我对Linux网络编程的一些粗浅的认识,不对的地方还 <br>
请各位大虾多多批评指正。 <br>
◆main()函数 <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 <sys/types.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>
*/ <br>
extern int errno; /* defined by libc.a */ <br>
extern char *sys_myerrlist[]; <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>
/*This is my modification. <br>
I'll tell you why we must do this later*/ <br>
typedef void Signal(int); <br>
/**************************************************************** <br>
function: main <br>
description: Main level driver. After daemonizing the process, a socket i <br>
s opened to listen for connections on the proxy port, connec <br>
tions are accepted and children are spawned to handle each n <br>
ew connection. <br>
arguments: argc,argv you know what those are. <br>
return value: none. <br>
calls: parse_args, do_proxy. <br>
globals: reads proxy_port. <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\r\n",stderr); <br>
exit(1); <br>
} <br>
/* ...and bind our address and port to it */ <br>
if (bind(sockfd,(struct sockaddr_in *) &servaddr,sizeof(servaddr)) <br>
< 0) { <br>
fputs("faild to bind server socket to specified port\r\n",stderr); <br>
<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>
; <br>
if (newsockfd < 0 && errno == EINTR) <br>
continue; <br>
/* 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>
lose(newsockfd); <br>
} <br>
} <br>
----------------------------------------------------------------- <br>
上面就是Proxy源代码的主程序部分,也许您在网上也曾经看到过这段代码,不过细 <br>
心的您会发现在上面这段代码中我修改了两个地方,都是在预编译部分。一个地方是在 <br>
定义外部字符型指针数组时,我将原代码中的 <br>
extern char *sys_errlist[]; <br>
修改为 <br>
extern char *sys_myerrlist[];原因是在我的Linux环境下头文件"stdio.h"已经对 <br>
sys_errlist[]进行了如下定义: <br>
extern __const char *__const sys_errlist[]; <br>
也许Carl Harris在94年编写这段代码时系统还没有定义sys_errlist[],不过现在 <br>
我们不修改一下的话,编译时系统就会告诉我们sys_errlist发生了定义冲突。 <br>
另外我添加了一个函数类型定义: <br>
typedef void Sigfunc(int); <br>
具体原因我将在后面向大家解释。 <br>
套接字和套接字地址结构定义 <br>
这段主程序是一段典型的服务器程序。网络通讯最重要的就是套接字的使用,在程 <br>
序的一开始就对套接字描述符sockfd和newsockfd进行了定义。接下来定义客户机/服务 <br>
器的套接字地址结构cliaddr和servaddr,存储客户机/服务器的有关通信信息。然后调 <br>
用parse_args(argc,argv)函数处理命令参数。关于这个parse_args()函数我们待会儿再 <br>
做介绍。 <br>
创建通信套接字 <br>
下面就是建立一个服务器的详细过程。服务器程序的第一个操作是创建一个套接字 <br>
。这是通过调用函数socket()来实现的。socket()函数的具体描述为: <br>
----------------------------------------------------------------- <br>
#include <sys/types.h> <br>
#include <sys/socket.h> <br>
int socket(int domain, int type, int protocol); <br>
----------------------------------------------------------------- <br>
参数domain指定套接字使用的协议族,AF_INET表示使用TCP/IP协议族,AF_UNIX表 <br>
示使用Unix协议族,AF_ISO表示套接字使用ISO协议族。type指定套接字类型,一般的面 <br>
向连接通信类型(如TCP)设置为SOCK_STREAM,当套接字为数据报类型时,type应设置 <br>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -