网络(network) 是几乎可以实时相互发送和接收数据的计算机和其他设备的集合。网络通常用线缆连接,数据位转换为电磁波,通过线缆移动。不过,无线网络会通过无线电波传输数据,许多长距离的传输现在会用通过玻璃纤维发送可见光的光纤电缆来完成。传输数据的任何物理介质并没有什么神秘可言。从理论上讲,数据甚至可以通过用碳驱动的计算机发送烟信号来相互传输。这种网络的响应时间(和对环境的影响)可能很差。
网络中的每台机器称为一个节点(node)。大多数节点是计算机,但是打印机、路由器、网桥、网关、哑终端和可口可乐机也都是节点。你可以使用Java与可乐机进行交互,但多数情况下都是与其他计算机对话。具有完备功能的计算机节点也称为主机(host)。这里将用节点一词指代网络的所有设备,用主机一词表示通用的计算机节点。
每个网络节点都有地址(address),这是用于唯一标识节点的一个字节序列。你可以将这组字节看作是数字,但一般不能保证地址中的字节数或字节序(big endian或little endian)与Java中 的简单数值类型一致。每个地址中的字节越多,可用的地址就越多,就可以有更多的设备同时连入网络。
所有现代计算机网络都是包交换(分组交换)网络:流经网络的数据分割成小块,称为包(packet,也称分组),每个包都单独加以处理。每个包都包含了由谁发送和将发往何处的信息。将数据分成单独的带有地址的包,其最重要的优点是,多个即将交换的包可以在一条线缆上传输,这使得建立网络的成本更低:多个计算机可以互不干扰地共用同一条线缆(与之相反,如果使用传统的电话线,当你在一个交换区中打本地电话时,实际上你将独占从你的电话到通话人电话之间的一条线缆。当所有线缆都占用时,有时有紧急事件或者节假日里就会发生这种情况,那么并不是每个拿起电话的人都能听到拨号音。如果你一直不挂断,最后当线不忙时你才会听到拨号音。在一些电话服务不如美国的国家中,等待半个小时或更长时间才听到拨号音是很常见的事情)。分包还有另一个好处,这就是可以进行校验,用来检测包在传输中是否遭到破坏。
我们仍然遗漏了重要的一点:计算机来回传递数据时还需要提供些什么。协议(protocol)是定义计算机如何通信的一组明确的规则:包括地址格式、数据如何分包等。针对网络通信的不同方面,定义有很多不同的协议。例如,超文本传输协议(Hypertext Transfer Protocol, HTTP) 定义了Web浏览器如何与服务器通信;在另一个方面,IEEE 802.3标准定义了另外一个协议,规定了数据位如何编码为某种特定类型线缆上的电信号。开放、公开的协议标准允许不同厂家的软件和设备相互通信:Web服务器不关心客户端是UNIX工作站、Android手 机还是一个iPad,因为所有客户端都使用相同的HTTP,与平台无关。
通过网络发送数据是一项复杂的操作,必须仔细地协调网络的物理特性以及所发送数据的逻辑特征。通过网络发送数据的软件必须了解如何避免包的冲突,将数字数据转换为模拟信号,检测和修正错误,将包从一台主机路由到另外的主机等。需要支持多个操作系统以及添加了异构网络电缆时,这个过程将变得更加复杂。
为了对应用程序开发人员和最终用户隐藏这种复杂性,网络通信的不同方面被分解为多个层。每一层表示为物理硬件(即线缆和电流)与所传输信息之间的不同抽象层次。在理论上,每一层只与紧挨其上和其下的层对话。将网络分层,这样就可以修改甚至替换某一层的软件,只要层与层之间的接口保持不变,就不会影响到其他层。
图1-1显示了你的网络中可能存在的协议栈。尽管如今在Internet上中间层协议相当稳定,但是上层和下层的协议变化很大。有些主机使用Ethernet;有些使用WiFi;有些使用PPP;还有一些主机使用其他的协议。类似地,这个栈顶层使用的协议完全取决于主机运行的程序。关键是,从栈的顶层来看,底层协议是什么并不重要,反之亦然,从底层来看,也不关心顶层协议是什么。这个分层模型实现了应用协议与网络硬件物理特性以及网络连接拓扑结构的解耦合。
有几种不同的分层模型,分别适合特定类型网络的需要。本教程采用适用于Internet的标准TCP/IP四层模型,如图1-2所示。在这个模型中,应用程序如Firefox和Warcraft运行在应用层,只与传输层对话。传输层只与应用层和网际层对话。网际层则只与主机网络层和传输层对话,绝不直接与应用层对话。主机网络层通过线缆、光纤或其他介质将数据移动到远程系统的主机网络层,然后再通过上述各层将数据逐级上移传输到远程系统的应用层。
例如,当Web浏览器向Web服务器发送获取网页的请求时,浏览器实际上只与本地客户机的传输层对话。传输层将请求分解为TCP片,向数据添加序列号和校验和,然后将请求传递给本地网际层。网际层根据本地网络所需的大小将各TCP片分成IP数据报,并传递到主机网络层以便通过线缆传输数据。主机网络层将数字数据编码为适合特定物理介质的模拟信号,将请求发送到线缆,目标地址的远程系统的主机网络层可以由此读取请求。
远程系统的主机网络层将模拟信号解码为数字数据,将生成的IP数据报传递给服务器的网际层。网际层简单地检查IP数据报是否被破坏,如果已经分片则重组数据,然后传递给服务器的传输层。服务器的传输层检查是否所有的数据都已到达,对于丢失或破坏的部分则要求重传(这个请求实际上将向下通过服务器的网际层,再通过服务器的主机网络层,回到客户端系统,然后再在客户端系统向上返回客户端的传输层,传输层再通过本地网际层和主机网络层重传前面丢失的数据。所有这些对于应用层是完全透明的)。一旦服务器的传输层接收到足够多的连续顺序数据报,就将其重组写人一个流,由服务器应用层上运行的Web服务器读取。服务器响应这个请求,再通过服务器系统的各个分层发回响应,通过Internet进行传输并分发给Web客户端。
可以猜到,实际的过程更为错综复杂。主机网络层是最复杂的,特意地隐藏了很多细节。例如,通过Internet发送的数据在到达最终目的地之前,完全有可能经过几个路由器以及相应的分层。可能需要从大气中的无线电波转换为铜线缆中的电子信号,再转换到光纤电缆中的光脉冲,然后再反过来,从光脉冲转换到电子信号再到无线电波。不过,90%的情况下Java代码都将在应用层工作,只需要与传输层对话。其他10%的时间会在传输层处理,与应用层或网际层对话。主机网络层的复杂性对你是隐藏的,这是分层模型的关键。
提示:如果阅读网络相关文献,你可能会看到另一个七层模型,称为开放系统互联参考模型(Open Systems Interconnection Reference Model, OSI)。对于Java网络程序,OSI模型过于复杂了。OSI模型与本教程使用的TCP/IP模型之间最大的区别是,OSI模型将主机网络层分为数据链路层和物理层,另外在应用层和传输层之间插入了表示层和会话层。OSI模型更加一般化,更适合于非TCP/IP网络,不过大多数情况下仍然过于复杂。在任何情况下,Java的网络类只工作于TCP/IP网络中,而且始终运行在应用层或传输层上,所以对于本教程的目的而言,使用更加复杂的OSI模型并不会带来任何好处。
对于应用层,它看起来像是在直接与其他系统的应用层对话,网络在两个应用层之间创建了一个逻辑路径。如果你考虑一下IRC聊天会话,就能很容易地理解这个逻辑路径。IRC聊天的大多数参与者会说他们在与另一个人交谈。如果实在要追问,他们可能会说是在与自己的计算机交谈(实际就是应用层),这个计算机再与另一个人的计算机交谈,那台计算机则与那个人交谈。深于一层的所有细节实际上都是不可见的,也确实应该如此。下面我们来详细地考虑各个分层。
作为Java程序员,你处在网络食物链中相当高的位置。在你的雷达探测之下发生着很多事情。在基于IP的Internet (Java唯一-真正理解的网络)的标准参考模型中,网络中隐藏的部分属于主机网络层(host-to-work layer,也称为链路层、数据链路层或网络接口层)。主机网络层定义了一个特定的网络接口( 如以太网卡或WiFi天线)如何通过物理连接向本地网络或世界其他地方发送IP数据报。
主机网络层中,由连接不同计算机的硬件(线缆、光纤电缆、无线电波或烟信号)组成的部分有时称为网络的物理层。作为Java程序员,不需要担心这一层,除非出现了问题,比如插头从计算机后面掉了下来,或者有人挖断了你与外部世界之间的T-1线。换句话说,Java从 来都看不到物理层。
需要考虑主机网络层和物理层的主要原因是性能(如果你认为有必要考虑)。例如,如果你的客户端使用速度很快、很可靠的光纤连接,与在北大西洋的一个油井钻台上使用大延迟的卫星连接相比,协议和应用程序的设计就要有所不同。另外,如果你的客户端参与一个3G数据计划,带宽相对低时要按字节收费,你就要做出不同的选择。如果你要写一个一般的消费者应用,以上任何客户端都有可能使用这个应用,你就要尽量找到一个最佳的折中点,或者可能甚至要检测并动态适应不同的客户端功能。不过,不论你遇到哪一种物理链路,在这些网络上用来完成通信的API都是一样的。之所以能够做到这一点,就是因为有网际层。
网络的下一层,这也是需要你考虑的第一层,就是网际层(internet layer)。在OSI模型中,网际层使用了一个更一般的名字,称为网络层(network layer)。网络层协议定义了数据位和字节如何组织为更大的分组,称为包,还定义了寻址机制,不同计算机要按这个寻址机制查找对方。网际协议(IP) 是世界上使用最广泛的网络层协议,也是Java唯一理解的网络层协议。
实际上,这是两个协议: IPv4和IPv6, IPv4 使用32位地址,IPv6使用128位地址,另外还增加了一些技术特性来帮助完成路由。这是两个完全不同的网络协议,如果没有特殊的网关和/或隧道协议,即使在相同的网络上它们也无法做到互操作,不过Java几乎对你隐藏了所有这些区别。
在IPv4和IPv6中,数据按包在网际层上传输,这些包称为数据报(datagram) 。每个IPv4数据报包含一个长度为20至60字节的首部,以及一个包含多达65515字节数据的有效载荷(payload) 。实际上,大多数IPv4数据报都小得多,从几十字节到稍大于8K字节不等。IPv6数据报包含-一个更大的首部,数据可以多达4G字节。
图1-3展示各个部分在IPv4数据报中是如何排列的。所有位和字节都采用big-endian方式,由左至右为最高位到最低位。
除了路由和寻址,网际层的第二个作用是支持不同类型的主机网络层相互对话。Internet路由器会完成WiFi和Ethernet、Ethernet和DSL、 DSL和光纤往返等协议之间的转换。如果没有网际层或类似的分层,则每个计算机只能与同一类网络上的其他计算机对话。网际层负责使用同构协议将异构网络相互连接。
原始数据报有--些缺点。最显著的缺点是不能保证可靠传送,即使能传送也可能在传输中遭到破坏。首部校验和只能检测首部中的破坏情况,而不能检测数据报中的数据部分。最后,即使数据报能到达目的地而未被破坏,也不一定会以发送时的顺序到达。各个数据报可能会经过不同路由从源到达目的地。如果数据报A在数据报B之前发送,这并不意味着数据报A会在数据报B之前到达。
传输层(transportlayer)负责确保各包以发送的顺序接收,并保证没有数据丢失或破坏。如果丢包,传输层会请求发送方重传这个包。为实现这个目标,IP网络会给每个数据报添加一一个附加首部,其中包含有更多信息。这一层上主要有两个协议。第一个是传输控制协议(Transmission Control Protocol, TCP),这是一个开销很高的协议,支持对丢失或破坏的数据进行重传,并按照发送时的顺序进行传送。第二个协议是用户数据报协议(User Datagram Protocol, UDP),它允许接收方检测被破坏的包,但不保证这些包以正确的顺序传送(或者包有可能根本未传送)。但是,UDP通常比TCP快。TCP称为可靠的(reliable) 协议; UDP是不可靠的(unreliable) 协议。后面我们将看到,不可靠的协议要比听起来有用得多。
向用户传送数据的层称为应用层(application layer)。它下面的三层共同定义了数据如何从一台计算机传输到另一台计算机。应用层确定了数据传输后的操作。例如,应用层协议如HTTP (用于国际互联网)可以确保Web浏览器将图像显示为图片,而不是一长串数字。你的程序中有关网络的部分大多都是在应用层花费时间。应用层协议就像一盆字母汤(alphabet soup) ;除了用于Web的HTTP,还有用于电子邮件的SMTP、POP和IMAP;用于文件传输的FTP、FSP和TFTP;用于文件访问的NFS;用于文件共享的Gnutella和BitTorrent;用于语音通信的会话启动协议(Session Initiation Protocol ,SIP)和Skype等。此外,你的程序可以在必要时定义自己的应用层协议。
IP (网际协议)是冷战时期由军方资助开发的,所以最后包含了大量军方关心的特性。
首先,它必须健壮。如果前苏联以核武器攻击了克利夫兰的路由器,则整个网络不能停止运转,所有消息仍然必须到达预期的目的地(当然除了那些要到达克利夫兰的消息)。因此IP设计为允许任意两点之间有多个路由,可以绕过被破坏的路由器实现数据包的路由。
其次,军方有多种不同类型的计算机,所有这些计算机必须都能相互通话。因此IP必须是开放的,与平台无关;如果有一个协议用于IBM主机,另一个协议用于PDP-11,这样并不好。IBM主机有可能需要与PDP-11以及周围任何其他奇怪的计算机进行通话。由于两点间存在多个路由,并且两点间的最短路径可能由于网络业务流量或其他因素(如克利夫兰的存在)而随时间改变,所以构成某个特定数据流的包可能不会采用相同的路由。另外,即使它们全部到达,也可能不会以发送的顺序到达。为了改进这种基本机制,将TCP置于IP之上,使连接的两端能够确认接收到IP包,以及请求重传丢失或被破坏的包。此外,TCP允许接收端的包按发送时的顺序重新组合在一起。
不过,TCP会有很大开销。因此,如果数据的顺序不是特别重要,而且单个包的丢失不会完全破坏数据流,那么有时也可以使用UDP发送数据包,而不需要TCP提供的保证。UDP是不可靠的协议,它不能保证包一一定到达目的地,也不保证包会以发送时相同的顺序到达。虽然这对于文件传输等用途来说存在问题,但是在有些应用程序中,即使丢失部分数据最终用户也不会注意到,对于这种应用程序而言,UDP则完全可以接受。例如,丢失视频或音频中的一些数据位不会造成太大的质量下降。如果要等待类似TCP等协议请求重传丢失的数据,那才会是更严重的问题。此外,可以在应用层的UDP数据流中建立纠错码,来解决数据丢失问题。
可以在IP之上运行很多其他协议。最常使用的是ICMP,即网际控制消息协议(InternetControl Message Protocol),它使用原始IP数据报在主机之间传递错误消息。使用这个协议最著名的应用是ping程序。Java不支持ICMP,也不允许发送原始IP数据报(而只允许发送TCP片或UDP数据报)。Java支持的协议只有TCP和UDP,以及建立在TCP和UDP之上的应用层协议。所有其他传输层、网际层和更底层的协议,如ICMP、IGMP、ARP、RARP、RSVP和其他协议在Java程序中都只能通过链接到原生代码来实现。
作为Java程序员,你不需要担心IP的内部工作原理,但你必须了解寻址。IPv4网络中的每台计算机都由一个4字节的数字标识。一般写为点分四段(dotted quad)格式,如199.1 .32.90,这4个数中,每个数都是-一个无符号字节,范围从0到255。IPv4网络中的每台计算机都有唯一的4字节地址。当数据通过网络传输时,包的首部会包括要发往的机器地址(目的地址)和发送这个包的机器地址(源地址)。沿路的路由器通过检查目的地址来选择发送数据包的最佳路由。包括源地址是为了让接收方知道要向谁回复。
可能的IP地址有40亿多一点,无法做到地球上每人一个地址,更无法做到每台计算机一个地址。更糟的是,地址的分配并不是很高效。2011年4月, 亚洲和澳大利亚的地址已经用光。无法再向这些地区分配更多的IPv4地址。在此之后,这些地区只能通过对现有的地址进行回收和再分配来维持。2012年9月,欧洲也用完了所有地址。北美洲、拉丁美洲和非洲只剩下为数不多的IP地址可以分配,不过也坚持不了多久。
虽然计算机可以轻松地处理数字,但人类对于记忆数字却不在行。因此,开发了域名系统(Domain Name System,DNS),用来将人类易于记忆的主机名( 如www .oreilly.com)转换为数字Internet地址( 如208.201.239.101)。当Java程序访问网络时,它们需要同时处理数字地址和相应的主机名。这些方法由java.net.InetAddress类提供。
有些计算机(尤其是服务器)有固定的地址。其他计算机(特别是局域网和无线连接上的客户端)可能每次启动时会收到不同的地址,这通常由DHCP服务器提供。你只需要记住IP地址可能会随着时间而改变,写代码时不要假定系统有相同的IP地址。例如,当保存应用程序状态时不要存储本地IP地址。相反,要在程序每次启动时进行新的查询。还有一种可能(尽管可能性不大),IP地址有可能在程序运行时改变( 例如,DHCP租期到期),所以应当每次需要时检查当前的IP地址,而不是将其缓存。除此之外,动态分配和手工分配的地址之间的区别对Java程序没有影响。
有一些地址区块和模式很特殊。以10.、172.16.、172.31 .和192.168.开头的所有IPv4地址都未分配。这些地址可以在内部网使用,但是使用这些地址的主机不允许加入全球Internet。这些不可路由的地址对于建立Internet上看不到的专用网会很有用。以127开头的IPv4地址(最常见的是127.0.0.1)总表示本地回送地址(local loopback address) 。也就是说,这些地址总指向本地计算机,而不论你在哪个计算机上运行。这个地址的主机名通常是localhost。在IPv6中,回送地址为0:0:0:0:0:0:0:1 (也就是::1)。 地址0.0.0.0总指示起始主机,但是只能用作为源地址,而不能作为目的地址。类似的,所有以0. (8个二进制0)开头的IPv4地址都指示同一个本地网络上的-一个主机。
4字节都使用相同数字的IPv4地址(如255.255.255.255) 是一个广播地址。发送到这个地址的包将由本地网络上的所有节点接收,但不能超越这个本地网络。这通常用来完成发送。例如,一个临时使用的客户端( 如笔记本电脑)启动时,它会向255.255.255.255发送一个特定的消息,查找本地DHCP服务器。这个网络上的所有节点都接收到这个包,不过只有DHCP服务器做出响应。具体地,它会向这个笔记本电脑发送本地网络配置的有关信息,包括这个笔记本电脑在余下的会话中要使用的IP地址以及用来解析主机名的DNS服务器的地址。
如果每台计算机一次只做一件事情,那么地址可能就足够了。但是,现代计算机同时要做很多不同的事情。电子邮件需要与FTP请求分开,而FTP又要与Web业务流分开。这是通过端口(port) 实现的。每台有IP地址的计算机都有几千个逻辑端口( 确切地讲,每个传输层协议有65535个端口)。这些只是计算机内存中的抽象,不表示任何物理实物,与USB端口不同。每个端口由1到65535之间的一个数字标识。每个端口可以分配给一个特定的服务。
例如,Web的底层协议HTTP一般使用端口80。我们说Web服务器在端口80监听(listen)入站连接(incoming connection)。当数据发送到特定IP地址的某个机器上的Web服务器时,它还会发送到该机器的特定端口(通常是端口80)。接收方检查接口收到的各个包,将数据发送给监听这个端口的程序。各种通信业务流就是这样区分的。
1到1023的端口号保留给已知的服务,如finger、 FTP、HTTP和IMAP。在UNIX系统上,包括Linux和Max OS X,只有以root用户运行的程序才可以接收这些端口的数据,但是所有程序都可以向这些端口发送数据。在Windows上, 所有程序都可以使用这些端口,不需要专门的特权。表1-1给出了本教程所讨论协议的已知端口。这种分配不是绝对的,特别是Web服务器通常就会在80以外的端口运行,可能是由于需要在同一台机器上运行多个服务器,或者因为安装服务器的人没有在端口80运行的root特权。在UNIX系统上,文件/etc/services存储了-一个相当完整的端口分配列表。
Internet是世界上最大的基于IP的网络。它是所有七个大洲(包括南极洲)多个不同国家的计算机使用IP相互对话的一个无组织的集合。Internet 上每台计算机都至少有一个标识此计算机的IP地址。大多数还有至少-一个主机名映射到这个IP地址。Internet不属 于任何人(不过它的各个部分有相应的所有者)。它不受任何人控制,这不表示某些政府没有做过这种尝试。它只是约定以一种标准方式相互对话的一个非常大的计算机集合。
Internet不是唯一的基于IP的网络,但却是最大的一个。其他IP网络称为internet (首字母i小写) :例如没有连接Internet的高安全性内部网。Intranet大致描述了公司将大量数据置于内部Web服务器的实践做法,这些数据对本地网络以外的用户不可见。
除非在与更宽网络物理隔离的高安全性环境中工作,否则你使用的internet很可能就是Internet。为确保Internet 上不同网络中的主机可以相互通信,就需要遵守一些对纯粹内部internet不适用的规则。最重要的规则是要处理不同组织、公司和个人地址的分配。如果每个人都随心所欲地随机挑选Internet地址,那么有相同地址的不同计算机出现在Internet上立即就会引起冲突。
为避免这个问题,区域Internet注册机构会为Internet服务提供商(ISP) 分配IPv4地址块。当公司或组织要建立一个基于IP的网络连接到Internet时,它们的ISP会给他们分配一个地址块。每个地址块有固定的前缀。例如,如果前缀是216.254.85,那么本地网络可以使用从216.254.85.0到216.254.85.255的地址。由于这个块固定了前24位,所以称为/24。/23指定 了前23位,而留出9位表示总共2或512个本地IP地址。/30子网(最小的子网)指定了子网中IP地址的前30位,留出2位表示总共2或4个本地IP地址。不过,所有块中最低地址用于标识网络本身,最高地址是这个网络的一个广播地址,所以比你原先预想的要少两个地址。
出于IP地址越来越稀缺,而对原始IP地址的需求越来越大,如今大多数网络都使用了网络地址转换(Network Address Translation, NAT)。基于NAT的网络中,大多数节点只有不可路由的本地地址,这些地址可能从10.x.x.x、172.16.x.x到172.31 .x.x,或192.168. x.x选择。将本地网络连接到ISP的路由器会把这些本地地址转换为更小的一组可路由的地址。
例如,我的公寓里有大约十来个IP节点,它们都共用一个外部可见的IP地址。我现在用的这个计算机的IP地址是192.168.1.5,不过,在你的网络上这个地址可能指示一个完全不同的主机(如果存在这样一个主机)。另外,你也无法向192.168.1.5发送数据到达我的计算机。实际上,必须把数据发送到216.254.85.72 (即使如此,只有当我把NAT路由器配置为将入站连接传递到192.168.1.5时,数据才会真正送达我的计算机)。
路由器会监视出站和入站连接,调整IP包中的地址。对于出站的包,它将源地址改为路由器的外部地址(在我的网络上这是216.254.85.72)。对于入站的包,它将目的地址改为一个本地地址,如192.168.1.12。 它如何记录哪些连接来自或发往哪台内部计算机,这对于Java程序员并不是特别重要。只要正确地配置了你的机器,这个过程基本上就是透明的。你只需要记住外部地址和内部地址有可能不同就行了。
最后要说明的是,IPv6会使这里的大部分内容变得过时。NAT会毫无意义,不过防火墙还是有用的。仍然有可以路由的子网,不过那些子网会大得多。
Internet上有些顽皮的人。为了把他们关在门外,在本地网络建立一一个访问点,检查所有进出该访问点的业务流通常很有用。位于Internet和本地网络之间的-一些硬件和软件会检查所有进出的数据,以保证其合法性,这就称为防火墙(firewall) 。防火墙通常是将本地网络连接到更大的Internet的路由器的一部分,还可以完成其他任务,如网络地址转换。此外,防火墙也可以是单独的机器。现代操作系统如Mac OS X和红帽Linux通常有内置的个人防火墙,只监视发送到这个机器的业务流。无论采用何种方法,防火墙都要负责检查传入或传出其网络接口的各个包,根据- -组规则接收或拒绝这些包。
过滤通常是基于网络地址和端口的。例如,所有来自C类网络193.28.25.x的通信会被拒绝,因为你过去遭遇过这个网络中黑客的攻击。出站SSH连接可能是允许的,但入站SSH连接不允许。端口80 (Web) 的人站连接是允许的,但只限于公司的Web服务器。更智能的防火墙会查看包的内容,确定是否接收或拒绝。防火墙具体的配置(哪些数据包允许通过而哪些不允许)取决于各个网站的安全需求。Java与防火墙没有太大关系,除非防火墙总是碍你的事。
代理服务器(proxy server)与防火墙有关。如果说防火墙会阻止一个网络上的主机与外界直接建立连接,那么代理服务器就起到了中间人的作用。这样一来,如果防火墙阻止一个机器连接外部网络,这个机器可以请求本地代理服务器的Web页面,而不是直接请求远程Web服务器的Web页面。然后代理服务器会请求Web服务器的页面,将响应转发给最初发出请求的机器。代理还可以用于FTP服务和其他连接。使用代理服务器的安全优势之一是外部主机只能看到代理服务器,而不会知道内部机器的主机名和IP地址,这就使得攻击内部网络更加困难。
防火墙一般工作于传输层或网际层,而代理服务器通常工作于应用层。代理服务器对一些应用层协议非常了解,如HTTP和FTP (一个值得注意的例外是SOCKS代理服务器,它工作于传输层,可以代理所有TCP和UDP连接,而不考虑应用层协议)。可以检查通过代理服务器的包,确保其中包含适当类型的数据。例如,看起来包含Telnet数据的FTP包可能会被拒绝。图1-4展示了代理服务器在分层模型中的位置。
只要所有对Internet的访问都通过代理服务器转发,那么访问就可以受到严格的控制。例如,公司可能选择阻止访问www.playboy.com,但允许访问www.microsoft.com。一些公司允许入站FTP,但不允许出站FTP,这样机密数据就不会容易地被非法带出公司。其他公司已经开始使用代理服务器来跟踪员工的Web使用情况,这样可以看到谁在利用Internet获取技术支持,而谁在利用它找私人朋友。
代理服务器还可以用来实现本地缓存(local caching)。当请求Web服务器的文件时,代理服务器首先查看此文件是否已在缓存中。如果文件在缓存中,那么代理服务器将提供缓存中的文件,而不是Internet 上的文件。如果这个文件不在缓存中,那么代理服务器将获取此文件,转发给请求方,并将它存储在缓存中,供下次请求使用。这种机制可以显著地降低Internet连接的负载,大大提高响应时间。美国在线(America Online)运转着世界上最大的代理服务器“场”之一,可以加快向用户传输数据的速度。如果你查看Web服务器的日志文件,可能会发现aol.com域客户的一些点击记录,但不像你想象的那么多,要知道AOL用户已超过300万。这是因为AOL代理服务器从其缓存中提供了许多页面,而不是为每位用户都重新请求页面。很多其他大的ISP也是这样做的。
代理服务器最大的问题在于它无法应对所有协议。通常已有的协议如HTTP、FTP和SMTP允许通过,而更新的协议如BitTorrent则不允许通过(有些网络管理员会认为这应算是一项功能)。在快速改变的Internet世界,这是一个很大的缺点,对于Java程序员而言更是一个缺点,因为它限制了定制协议的有效性。使用Java可以很容易地创建为你的应用而优化的新协议,这通常也很有用。但是,没有代理服务器能理解这些独一无二的协议。因此,有些开发人员开始通过HTTP来接入他们的协议,最著名的是SOAP。不过,这对安全性有显著的负面影响。防火墙的存在肯定事出有因,而不只是找Java程序员的麻烦。
大多数现代网络编程都基于客户/服务器模型。客户/服务器应用程序-般将 大量数据存储在昂贵的高性能服务器或服务器云上,而大多数程序逻辑和用户界面由客户端软件处理,这些客户端软件运行在相对便宜的个人计算机上。在多数情况下,服务器主要发送数据,而客户端主要接收数据,但很少有一个程序只发送或只接收数据。更有可能的是客户端发起对话,而服务器等待客户端与它开始对话。图1-5展示了这两种可能性。在有些情况下,同一个程序会同时作为客户端和服务器。
你已经熟悉了许多客户/服务器系统的例子。在2013年,Internet 上最流行的客户/服务器系统是Web。Web服务器(如Apache)响应Web客户端( 如Firefox)的请求。数据存储在Web服务器上,会发送给请求数据的客户端。除了最初的页面请求,几乎所有数据都从服务器向客户端传输,而不是从客户端传输至服务器。FTP是符合客户/服务器模型的更古老的服务。FTP使用不同的应用协议和不同的软件,但依然分为发送文件的FTP服务器和接收文件的FTP客户端。人们通常使用FTP从客户端向服务器上传文件,所以很难讲数据传输主要是一一个方向传输,但是要说FTP客户发起连接而FTP服务器进行响应,这仍然是正确的。
不是所有应用程序都简单地符合客户/服务器模型。例如,在网络游戏中,看起来两个玩家都能大致相同地来回发送数据(至少在公平游戏中是如此)。这种连接称为“对等”(peer-to-peer)连接。电话系统就是典型的对等网络例子。每部电话都可以呼叫另外的电话,或者被另外的电话呼叫。你不需要购买一部电话发 送呼叫,另一部电话接收呼叫。
Java在其核心网络API中没有显式的对等通信。不过,应用程序可以很容易地通过几种方式提供对等通信,最常见的是同时作为服务器和客户端。另外,对等端可以通过中间服务器程序相互通信,这个程序将数据从一端转发到其他对等端。这样就很好地解决了两个对等端如何发现对方的问题。
虽然世界上有很多标准组织,但关于应用层网络编程和协议的大多数标准都由下面两个组织制定,它们分别是IETF (Internet Engineering Task Force, Internet 工程任务组)和W3C (World Wide Web Consortium,国际互联网协会)。IETF是不太正式的民间团体,向所有感兴趣参与的团队开放。它的标准是根据“多数人的意见和正在运行的代码”做出决定,倾向于跟踪而不是引导实现。IETF标准包括TCP/IP、MIME和SMTP。与IETF不同,W3C是厂商组织,由缴纳会费的成员公司控制,明确拒绝个人参与。在极大程度上,W3C会尽力在实现之前定义标准。W3C标准包括HTTP、HTML和XML。