第17章 络编程
本章将主要介绍Java 络通信的支持,通过这些 络支持类,Java程序可以非常方便地访问互联 上的HTTP服务、FTP服务等,并可以直接取得互联 上的远程资源,还可以向远程资源发送GET、POST请求。
17.1 络编程的基础知识
17.1.1 络基础知识
- 计算机 络,就是把分布在不同地理区域的计算机与专门的外部设备用通信线路互连成一个规模大、功能强的 络系统,从而使众多的计算机可以方便地互相传递信息,共享硬件、软件、数据信息等资源。
- IP(Internet Protocol)协议又称互联 协议,是支持 间互联的数据 协议。它提供 间连接的完善功能,包括IP数据 规定互联 络范围内的地址格式。
- TCP(Transmission Control Protocol)协议,即传输控制协议,它规定一种可靠的数据信息传递服务。虽然IP和TCP这两个协议功能不尽相同,也可以分开单独使用,但它们是在同一个时期作为一个协议来设计的,并且在功能上也是互补的。
17.3.8 使用Java 7 的AIO实现非阻塞通信
- Java7的NIO.2提供了异步Channel支持,这种异步Channel可以提供更高效的IO,这种基于异步Channel的IO机制也被称为异步IO(AsynchronousIO)。
- NIO.2提供了一系列以Asynchronous 开头的Channel接口和类,NIO.2为AIO提供了两个接口和三个实现类,其中AsynchronousSocketChannel、AsynchronousServerSocketChannel是支持TCP通信的异步Channel。
17.4 基于UDP协议的 络编程
UDP协议是一种不可靠的 络协议,它在通信实例的两端各建立一个Socket,但这两个Socket之间并没有虚拟链路,这两个Socket只是发送、接收数据 的对象。Java提供了DatagramSocket对象作为基于UDP协议的Socket,使用DatagramPacket代表DatagramSocket发送、接收的数据 。
17.4.1 UDP协议基础
- UDP协议是英文User Datagram Protocol的缩写,即用户数据 协议,主要用来支持那些需要在计算机之间传输数据的 络连接。
- UDP协议是一种面向非连接的协议,面向非连接指的是在正式通信前不必与对方先建立连接,不管对方状态就直接发送。至于对方是否可以接收到这些数据内容,UDP协议无法控制,因此说UDP协议是一种不可靠的协议。UDP协议适用于一次只传送少量数据、对可靠性要求不高的应用环境。
- UDP协议和TCP协议简单对比如下:
TCP协议(打电话):可靠,传输大小无限制,但是需要连接建立时间,差错控制开销大。
UDP协议(发短信):不可靠,差错控制开销较小,传输大小限制在64KB以下,不需要建立连接。
17.4.2 使用DatagramSocket发送、接收数据
- Java使用DatagramSocket代表UDP协议的Socket,DatagramSocket本身只是码头,不维护状态,不能产生IO流,它的唯一作用就是接收和发送数据 ,Java使用DatagramPacket来代表数据 ,DatagramSocket接收和发送的数据都是通过DatagramPacket对象完成的。
- DatagramSocket的构造器:
DatagramSocket():创建一个DatagramSocket实例,并将该对象绑定到本机默认IP地址、本机所有可用端口中随机选择的某个端口。
DatagramSocket(int prot):创建一个DatagramSocket实例,并将该对象绑定到本机默认IP地址、指定端口。
DatagramSocket(int port, InetAddress laddr):创建一个DatagramSocket实例,并将该对象绑定到指定IP地址、指定端口。
- 得到了DatagramSocket实例之后,就可以通过如下两个方法来接收和发送数据。
receive(DatagramPacket p):从该DatagramSocket中接收数据 。
send(DatagramPacket p):以该DatagramSocket对象向外发送数据 。
- 从上面两个方法可以看出,使用DatagramSocket发送数据 时,DatagramSocket并不知道将该数据 发送到哪里,而是由DatagramPacket自身决定数据 的目的地。
- DatagramPacket的构造器:
DatagramPacket(byte[] buf, int length):以一个空数组来创建DatagramPacket对象,该对象的作用是接收DatagramSocket中的数据。
DatagramPacket(byte[] buf, int length, InetAddress addr, int port):以一个包含数据的数组来创建DatagramPacket对象,创建该DatagramPacket对象时还指定了IP地址和端口—这就决定了该数据 的目的地。
DatagramPacket(byte[] buf, int offset, int length):以一个空数组来创建DatagramPacket对象,并指定接收到的数据放入buf数组中时从offset开始,最多放length个字节。
DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port):创建一个用于发送的DatagramPacket对象,指定发送buf数组中从offset开始,总共length个字节。
- 在接收数据之前,应该采用上面的第一个或第三个构造器生成一个DatagramPacket对象,给出接收数据的字节数组及其长度。然后调用DatagramSocket的receive()方法等待数据 的到来,receive()将一直等待(该方法会阻塞调用该方法的线程),直到收到一个数据 为止。如下代码所示。
- 在发送数据之前,调用第二个或第四个构造器创建DatagramPacket对象,此时的字节数组里存放了想发送的数据。除此之外,还要给出完整的目的地址,包括IP地址和端口 。发送数据是通过DatagramSocket的send()方法实现的,send()方法根据数据 的目的地址来寻径以传送数据 。如下代码所示。
17.4.3 使用MulticastSocket实现多点广播
-
DatagramSocket 只允许数据 发送给指定的目标地址,而MulticastSocket可以将数据 以广播方式发送到多个客户端。
-
从图17.8中可以看出,MulticastSocket类是实现多点广播的关键,当MulticastSocket 把一个DatagramPacket发送到多点广播IP地址时,该数据 将被自动广播到加入该地址的所有Multicast Socket。MulticastSocket既可以将数据 发送到多点广播地址,也可以接收其他主机的广播信息。
-
MulticastSocket是DatagramSocket的一个子类,也就是说,MulticastSocket是特殊的DatagramSocket。当要发送一个数据 时,可以使用随机端口创建MulticastSocket,也可以在指定端口创建MulticastSocket。
-
MulticastSocket提供了如下三个构造器。
public MulticastSocket():使用本机默认地址、随机端口来创建MulticastSocket对象。
public MulticastSocket(int portNumber):使用本机默认地址、指定端口来创建MulticastSocket对象。
public MulticastSocket(SocketAddress bindaddr):使用本机指定IP地址、指定端口来创建MulticastSocket对象。
- 创建MulticastSocket对象后,还需要将该MulticastSocket加入到指定的多点广播地址,MulticastSocket使用joinGroup()方法加入指定组;使用leaveGroup()方法脱离一个组。
joinGroup(InetAddress multicastAddr):将该MulticastSocket加入指定的多点广播地址。
leaveGroup(InetAddress multicastAddr):让该MulticastSocket离开指定的多点广播地址。
17.5 使用代理服务器
- 从Java5开始,Java在java.net包下提供了Proxy和ProxySelector两个类,其中Proxy代表一个代理服务器,可以在打开URLConnection连接时指定Proxy,创建Socket连接时也可以指定Proxy;而ProxySelector代表一个代理选择器,它提供了对代理服务器更加灵活的控制,它可以对HTTP、HTTPS、FTP、SOCKS等进行分别设置,而且还可以设置不需要通过代理服务器的主机和地址。通过使用ProxySelector,可以实现像在Internet Explorer、Firefox等软件中设置代理服务器类似的效果。
- 代理服务器的功能就是代理用户去取得 络信息。当使用浏览器直接连接其他Internet站点取得 络信息时,通常需要先发送请求,然后等响应到来。代理服务器是介于浏览器和服务器之间的一台服务器,设置了代理服务器之后,浏览器不是直接向Web服务器发送请求,而是向代理服务器发送请求,浏览器请求被先送到代理服务器,由代理服务器向真正的Web服务器发送请求,并取回浏览器所需要的信息,再送回给浏览器。由于大部分代理服务器都具有缓冲功能,它会不断地将新取得的数据存储到代理服务器的本地存储器上,如果浏览器所请求的数据在它本机的存储器上已经存在而且是最新的,那么它就无须从Web服务器取数据,而直接将本地存储器上的数据送回浏览器,这样能显著提高浏览速度。
- 归纳起来,代理服务器主要提供如下两个功能。
(1)突破自身IP限制,对外隐藏自身IP地址。突破IP限制包括访问国外受限站点,访问国内特定单位、团体的内部资源。
(2)提高访问速度,代理服务器提供的缓冲功能可以避免每个用户都直接访问远程主机,从而提高客户端访问速度。
17.5.1直接使用Proxy创建连接
- Proxy有一个构造器:Proxy(Proxy.Type type,SocketAddress sa),用于创建表示代理服务器的Proxy对象。其中sa参数指定代理服务器的地址,type表示该代理服务器的类型,该服务器类型有如下三种。
Proxy.Type.DIRECT:表示直接连接,不使用代理。
Proxy.Type.HTTP:表示支持高级协议代理,如HTTP或FTP。
Proxy.Type.SOCKS:表示SOCKS(V4或V5)代理。
- 一旦创建了Proxy对象之后,程序就可以在使用URLConnection 打开连接时,或者创建 Socket连接时传入一个Proxy对象,作为本次连接所使用的代理服务器。
- 其中URL包含了一个URLConnection openConnection(Proxy proxy)方法,该方法使用指定的代理服务器来打开连接;而Socket则提供了一个Socket(Proxy proxy)构造器,该构造器使用指定的代理服务器创建一个没有连接的Socket对象。
17.5.2使用ProxySelector自动选择代理服务器
- 前面介绍的直接使用Proxy对象可以在打开URLConnection或Socket时指定代理服务器,但使用这种方式每次打开连接时都需要显式地设置代理服务器,比较麻烦。如果希望每次打开连接时总是具有默认的代理服务器,则可以借助于ProxySelector来实现。
- ProxySelector代表一个代理选择器,它本身是一个抽象类,程序无法创建它的实例,开发者可以考虑继承ProxySelector来实现自己的代理选择器。实现ProxySelector的步骤非常简单,程序只要定义一个继承ProxySelector的类,并让该类实现如下两个抽象方法。
List
select(URI uri):根据业务需要返回代理服务器列表,如果该方法返回的集合中只包含一个Proxy,该Proxy将会作为默认的代理服务器。
connectFailed(URI uri,SocketAddress sa,IOException ioe):连接代理服务器失败时回调该方法。
- 实现了自己的ProxySelector类之后,调用ProxySelector的setDefault(ProxySelector ps)静态方法来注册该代理选择器即可。
- 除此之外,Java为ProxySelector提供了一个实现类:sun.net.spi.DefaultProxySelector(这是一个未公开API,应尽量避免直接使用该API),系统已经将DefaultProxySelector注册成默认的代理选择器,因此程序可调用ProxySelector.getDefault)方法来获取DefaultProxySelector实例。
- DefaultProxySelector 继承了ProxySelector,当然也实现了两个抽象方法,它的实现策略如下。
connectFailed():如果连接失败,DefaultProxySelector将会尝试不使用代理服务器,直接连接远程资源。
select():DefaultProxySelector 会根据系统属性来决定使用哪个代理服务器。ProxySelector会检测系统属性与URL之间的匹配,然后决定使用相应的属性值作为代理服务器。关于代理服务器常用的属性名有如下三个。
(1)http.proxyHost:设置HTTP访问所使用的代理服务器的主机地址。该属性名的前缀可以改为https、ftp等,分别用于设置HTTPS访问和FTP访问所用的代理服务器的主机地址。(2)http.proxyPort:设置HTTP访问所使用的代理服务器的端口。该属性名的前缀可以改为https、ftp等,分别用于设置HTTPS访问和FTP访问所用的代理服务器的端口。
(3)http.nonProxyHosts:设置HTTP访问中不需要使用代理服务器的主机,支持使用*通配符;支持指定多个地址,多个地址之间用竖线( | )分隔。
文章知识点与官方知识档案匹配,可进一步学习相关知识 络技能树跨区域 络的通信学习 络层的作用22557 人正在系统学习中
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!