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

📄 00000006.htm

📁 一份很好的linux入门资料
💻 HTM
📖 第 1 页 / 共 5 页
字号:
&nbsp;&nbsp;&nbsp;&nbsp;网络层&nbsp;(Network)&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;数据链路层&nbsp;(Data&nbsp;Link)&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;物理层&nbsp;(Physical)&nbsp;<BR>物理层是硬件(串口,以太网等等)。应用层是和硬件层相隔最远的--他是用户和网络交&nbsp;<BR>互的地方。&nbsp;<BR>这个模型如此通用,如果你想,你可以把他作为修车指南。把他应用到&nbsp;Unix,结果是:&nbsp;<BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;应用层&nbsp;(Application&nbsp;Layer)&nbsp;(telnet,&nbsp;ftp,&nbsp;等等)&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;传输层&nbsp;(Host-to-Host&nbsp;Transport&nbsp;Layer)&nbsp;(TCP,&nbsp;UDP)&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;Internet&nbsp;层&nbsp;(Internet&nbsp;Layer)&nbsp;(IP&nbsp;和路由)&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;网络访问层&nbsp;(Network&nbsp;Access&nbsp;Layer)&nbsp;(网络层,数据链路层和物理层)&nbsp;<BR>现在,你可能看到这些层次如何协调来封装原始的数据了。&nbsp;<BR>看看建立一个简单的数据包有多少工作?哎呀,你将不得不使用&nbsp;&quot;cat&quot;&nbsp;来完成他们!简&nbsp;<BR>直是笑话。对于流式套接口你要作的是&nbsp;send()&nbsp;<BR>发送数据。对于数据报式套接口你按照你选择的方式封装数据然后用&nbsp;sendto()。内核将&nbsp;<BR>为你建立传输层和&nbsp;Internet&nbsp;<BR>层,硬件完成网络访问层。这就是现代科技。&nbsp;<BR>现在结束我们的网络理论速成班。哦,忘记告诉你关于路由的事情了。但是我不准备谈&nbsp;<BR>他。如果你真的想知道,那么参考&nbsp;IP&nbsp;<BR>RFC。如果你从来不曾了解他,也没有关系,你还活着不是吗。&nbsp;<BR>structs&nbsp;<BR>终于到达这里了,终于谈到编程了。在这章,我将谈到被套接口用到的各种数据类型。&nbsp;<BR>因为他们中的一些太重要了。&nbsp;<BR>首先是简单的一个:socket&nbsp;descriptor。他是下面的类型:&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;<BR>仅仅是一个常见的&nbsp;int。&nbsp;<BR>从现在起,事情变得不可思议了。请跟我一起忍受苦恼吧。注意这样的事实:有两种字&nbsp;<BR>节排列顺序:重要的字节在前面(有时叫&nbsp;<BR>&quot;octet&quot;),或者不重要的字节在前面。前一种叫“网络字节顺序&nbsp;(Network&nbsp;Byte&nbsp;<BR>Order)”。有些机器在内部是按照这个顺序储存数据,而另外一些则不然。当我说某数&nbsp;<BR>据必须按照&nbsp;NBO&nbsp;顺序,那么你要调用函数(例如&nbsp;htons()&nbsp;<BR>)来将他从本机字节顺序&nbsp;(Host&nbsp;Byte&nbsp;Order)&nbsp;转换过来。如果我没有提到&nbsp;NBO,&nbsp;那么就&nbsp;<BR>让他是本机字节顺序吧。&nbsp;<BR>我的第一个结构(TM)--struct&nbsp;sockaddr.&nbsp;这个数据结构为许多类型的套接口储存套接口&nbsp;<BR>地址信息:&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;sockaddr&nbsp;{&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;short&nbsp;&nbsp;&nbsp;&nbsp;sa_family;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;address&nbsp;family,&nbsp;AF_xxx&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sa_data[14];&nbsp;&nbsp;/*&nbsp;14&nbsp;bytes&nbsp;of&nbsp;protocol&nbsp;address&nbsp;*/&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;};&nbsp;<BR>sa_family&nbsp;能够是各种各样的事情,但是在这篇文章中是&nbsp;&quot;AF_INET&quot;。&nbsp;sa_data&nbsp;为套接&nbsp;<BR>口储存目标地址和端口信息。看上去很笨拙,不是吗。&nbsp;<BR>为了对付&nbsp;struct&nbsp;sockaddr,程序员创造了一个并列的结构:&nbsp;struct&nbsp;sockaddr_in&nbsp;(&quot;&nbsp;<BR>in&quot;&nbsp;代表&nbsp;&quot;Internet&quot;.)&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;sockaddr_in&nbsp;{&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;short&nbsp;int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sin_family;&nbsp;&nbsp;/*&nbsp;Address&nbsp;family&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;short&nbsp;int&nbsp;sin_port;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;Port&nbsp;number&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;in_addr&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sin_addr;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;Internet&nbsp;address&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;char&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sin_zero[8];&nbsp;/*&nbsp;Same&nbsp;size&nbsp;as&nbsp;struct&nbsp;sockaddr&nbsp;*/&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;};&nbsp;<BR>这个数据结构让可以轻松处理套接口地址的基本元素。注意&nbsp;sin_zero&nbsp;(他被加入到这个&nbsp;<BR>结构,并且长度和&nbsp;struct&nbsp;sockaddr&nbsp;一样)&nbsp;应该使用函数&nbsp;<BR>bzero()&nbsp;或&nbsp;memset()&nbsp;来全部置零。&nbsp;Also,&nbsp;and&nbsp;this&nbsp;is&nbsp;the&nbsp;important&nbsp;bit,&nbsp;a&nbsp;poin&nbsp;<BR>ter&nbsp;to&nbsp;a&nbsp;<BR>struct&nbsp;sockaddr_in&nbsp;can&nbsp;be&nbsp;cast&nbsp;to&nbsp;a&nbsp;pointer&nbsp;to&nbsp;a&nbsp;struct&nbsp;sockaddr&nbsp;and&nbsp;vice-ve&nbsp;<BR>rsa.&nbsp;<BR>这样的话即使&nbsp;socket()&nbsp;想要的是&nbsp;struct&nbsp;sockaddr&nbsp;*,你仍然可以使用&nbsp;struct&nbsp;sock&nbsp;<BR>addr_in,and&nbsp;cast&nbsp;it&nbsp;at&nbsp;<BR>the&nbsp;last&nbsp;minute!&nbsp;同时,注意&nbsp;sin_family&nbsp;和&nbsp;struct&nbsp;sockaddr&nbsp;中的&nbsp;sa_family&nbsp;一致&nbsp;<BR>并能够设置为&nbsp;<BR>&quot;AF_INET&quot;。最后,&nbsp;sin_port&nbsp;和&nbsp;sin_addr&nbsp;必须是网络字节顺序&nbsp;(Network&nbsp;Byte&nbsp;Orde&nbsp;<BR>r)!&nbsp;<BR>你也许会反对道:&quot;但是,怎么让整个数据结构&nbsp;struct&nbsp;in_addr&nbsp;sin_addr&nbsp;按照网络字&nbsp;<BR>节顺序呢?&quot;&nbsp;<BR>要知道这个问题的答案,我们就要仔细的看一看这个数据结构:&nbsp;struct&nbsp;in_addr,&nbsp;有这&nbsp;<BR>样一个联合&nbsp;(unions):&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;Internet&nbsp;address&nbsp;(a&nbsp;structure&nbsp;for&nbsp;historical&nbsp;reasons)&nbsp;*/&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;in_addr&nbsp;{&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;long&nbsp;s_addr;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;};&nbsp;<BR>他曾经是个最坏的联合,但是现在那些日子过去了。如果你声明&nbsp;&quot;ina&quot;&nbsp;是数据结构&nbsp;st&nbsp;<BR>ruct&nbsp;sockaddr_in&nbsp;的实例,那么&nbsp;<BR>&quot;ina.sin_addr.s_addr&quot;&nbsp;就储存4字节的&nbsp;IP&nbsp;地址(网络字节顺序)。如果你不幸的系统使&nbsp;<BR>用的还是恐怖的联合&nbsp;struct&nbsp;in_addr&nbsp;<BR>,你还是可以放心4字节的&nbsp;IP&nbsp;地址是和上面我说的一样(这是因为&nbsp;#define。)&nbsp;<BR>Convert&nbsp;the&nbsp;Natives!&nbsp;<BR>我们现在到达下个章节。我们曾经讲了很多网络到本机字节顺序,现在是采取行动的时&nbsp;<BR>刻了!&nbsp;<BR>你能够转换两种类型:&nbsp;short&nbsp;(两个字节)和&nbsp;long&nbsp;(四个字节)。这个函数对于变量类型&nbsp;<BR>&nbsp;unsigned&nbsp;也适用。假设你想将&nbsp;short&nbsp;<BR>从本机字节顺序转换为网络字节顺序。用&nbsp;&quot;h&quot;&nbsp;表示&nbsp;&quot;本机&nbsp;(host)&quot;,接着是&nbsp;&quot;to&quot;,然&nbsp;<BR>后用&nbsp;&quot;n&quot;&nbsp;表示&nbsp;&quot;网络&nbsp;(network)&quot;,最后用&nbsp;&quot;s&quot;&nbsp;<BR>表示&nbsp;&quot;short&quot;:&nbsp;h-to-n-s,&nbsp;或者&nbsp;htons()&nbsp;(&quot;Host&nbsp;to&nbsp;Network&nbsp;Short&quot;)。&nbsp;<BR>太简单了...&nbsp;<BR>如果不是太傻的话,你一定想到了组合&nbsp;&quot;n&quot;,&quot;h&quot;,&quot;s&quot;,和&nbsp;&quot;l&quot;。但是这里没有&nbsp;stolh&nbsp;<BR>()&nbsp;(&quot;Short&nbsp;to&nbsp;Long&nbsp;Host&quot;)&nbsp;<BR>函数,但是这里有:&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;htons()--&quot;Host&nbsp;to&nbsp;Network&nbsp;Short&quot;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;htonl()--&quot;Host&nbsp;to&nbsp;Network&nbsp;Long&quot;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;ntohs()--&quot;Network&nbsp;to&nbsp;Host&nbsp;Short&quot;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;ntohl()--&quot;Network&nbsp;to&nbsp;Host&nbsp;Long&quot;&nbsp;<BR>现在,你可能想你已经知道他们了。你也可能想:&quot;如果我改变&nbsp;char&nbsp;的顺序会怎么样呢&nbsp;<BR>?&nbsp;我的&nbsp;68000&nbsp;机器已经使用了网络字节顺序,我没有必要去调用&nbsp;<BR>htonl()&nbsp;转换&nbsp;IP&nbsp;地址。&quot;&nbsp;你可能是对的,但是当你移植你的程序到别的机器上的时候&nbsp;<BR>,你的程序将失败。可移植性!这里是&nbsp;Unix&nbsp;<BR>世界!记住:在你将数据放到网络上的时候,确信他们是网络字节顺序。&nbsp;<BR>最后一点:为什么在数据结构&nbsp;struct&nbsp;sockaddr_in&nbsp;中,&nbsp;sin_addr&nbsp;和&nbsp;sin_port&nbsp;需要&nbsp;<BR>转换为网络字节顺序,而&nbsp;sin_family&nbsp;<BR>不需要呢?&nbsp;答案是:sin_addr&nbsp;和&nbsp;sin_port&nbsp;分别封装在包的&nbsp;IP&nbsp;和&nbsp;UDP&nbsp;层。因此,他&nbsp;<BR>们必须要是网络字节顺序。但是&nbsp;sin_family&nbsp;<BR>域只是被内核&nbsp;(kernel)&nbsp;使用来决定在数据结构中包含什么类型的地址,所以他应该是&nbsp;<BR>本机字节顺序。也即&nbsp;sin_family&nbsp;没有&nbsp;<BR>发送到网络上,他们可以是本机字节顺序。&nbsp;<BR>IP&nbsp;地址和如何处理他们&nbsp;<BR>现在我们很幸运,因为我们有很多的函数来方便地操作&nbsp;IP&nbsp;地址。没有必要用手工计算&nbsp;<BR>他们,也没有必要用&nbsp;&lt;&lt;&nbsp;操作符来操作&nbsp;long。&nbsp;<BR>首先,假设你用&nbsp;struct&nbsp;sockaddr_in&nbsp;ina,你想将&nbsp;IP&nbsp;地址&nbsp;&quot;132.241.5.10&quot;&nbsp;储存到其&nbsp;<BR>中。你要用的函数是&nbsp;<BR>inet_addr(),转换&nbsp;numbers-and-dots&nbsp;格式的&nbsp;IP&nbsp;地址到&nbsp;unsigned&nbsp;long。这个工作可&nbsp;<BR>以这样来做:&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;ina.sin_addr.s_addr&nbsp;=&nbsp;inet_addr(&quot;132.241.5.10&quot;);&nbsp;<BR>注意:inet_addr()&nbsp;返回的地址已经是按照网络字节顺序的,你没有必要再去调用&nbsp;hto&nbsp;<BR>nl()。&nbsp;<BR>上面的代码可不是很健壮&nbsp;(robust),因为没有错误检查。inet_addr()&nbsp;在发生错误的时&nbsp;<BR>候返回-1。记得二进制数吗?&nbsp;在&nbsp;IP&nbsp;地址为&nbsp;<BR>255.255.255.255&nbsp;的时候返回的是&nbsp;(unsigned)-1!这是个广播地址!记住正确的使用错&nbsp;<BR>误检查。&nbsp;<BR>好了,你现在可以转换字符串形式的&nbsp;IP&nbsp;地址为&nbsp;long&nbsp;了。那么你有一个数据结构&nbsp;str&nbsp;<BR>uct&nbsp;in_addr,该如何按照&nbsp;numbers-and-dots&nbsp;<BR>格式打印呢?&nbsp;在这个时候,也许你要用函数&nbsp;inet_ntoa()&nbsp;(&quot;ntoa&quot;&nbsp;意思是&nbsp;&quot;network&nbsp;t&nbsp;<BR>o&nbsp;ascii&quot;):&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;printf(&quot;%s&quot;,inet_ntoa(ina.sin_addr));&nbsp;<BR>他将打印&nbsp;IP&nbsp;地址。注意的是:函数&nbsp;inet_ntoa()&nbsp;的参数是&nbsp;struct&nbsp;in_addr,而不是&nbsp;<BR>&nbsp;<BR>long。同时要注意的是他返回的是一个指向字符的指针。在&nbsp;inet_ntoa&nbsp;内部的指针静态&nbsp;<BR>地储存字符数组,因此每次你调用&nbsp;inet_ntoa()&nbsp;<BR>的时候他将覆盖以前的内容。例如:&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;*a1,&nbsp;*a2;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;.&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;.&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;a1&nbsp;=&nbsp;inet_ntoa(ina1.sin_addr);&nbsp;&nbsp;/*&nbsp;this&nbsp;is&nbsp;198.92.129.1&nbsp;*/&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;a2&nbsp;=&nbsp;inet_ntoa(ina2.sin_addr);&nbsp;&nbsp;/*&nbsp;this&nbsp;is&nbsp;132.241.5.10&nbsp;*/&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;printf(&quot;address&nbsp;1:&nbsp;%s\n&quot;,a1);&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;printf(&quot;address&nbsp;2:&nbsp;%s\n&quot;,a2);&nbsp;<BR>运行结果是:&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;address&nbsp;1:&nbsp;132.241.5.10&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;address&nbsp;2:&nbsp;132.241.5.10&nbsp;<BR>如果你想保存地址,那么用&nbsp;strcpy()&nbsp;保存到自己的字符数组中。&nbsp;<BR>这就是这章的内容了。以后,我们将学习转换&nbsp;&quot;whitehouse.gov&quot;&nbsp;形式的字符串到正确&nbsp;<BR>的&nbsp;IP&nbsp;地址(请看后面的&nbsp;DNS&nbsp;一章。)&nbsp;<BR>socket()--得到文件描述符!&nbsp;<BR>我猜我不会再扯远了--我必须讲&nbsp;socket()&nbsp;这个系统调用了。这里是详细的定义:&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;#include&nbsp;&lt;sys/types.h&gt;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;#include&nbsp;&lt;sys/socket.h&gt;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;socket(int&nbsp;domain,&nbsp;int&nbsp;type,&nbsp;int&nbsp;protocol);&nbsp;<BR>但是他们的参数怎么用?&nbsp;首先,domain&nbsp;应该设置成&nbsp;&quot;AF_INET&quot;,就象上面的数据结构&nbsp;&nbsp;<BR>

⌨️ 快捷键说明

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