Java学习(十一)
文章目录
网络编程
-
基本网络支持
-
InetAddress
类其有两个子类分别表示ipv4和ipv6,即
Inet4Address
、Inet6Address
该类没有构造器,通过两个静态方法:
getByName(String host)
和getByAddress(byte[] addr)
来获取实例通过实例方法获取主机名、IP地址:
getHostAddress()
、getHostName()
、getLocalHost()
测试是否可达:
isReachable(int timeout)
-
URLDecoder
和URLEncoder
这两个类用于完成普通字符串和
application/x-www-form-urlencoded MIME
字符串之间的转换,后者是特殊编码的字符串,当URL中包含非西欧字符时(例如浏览器中的中文),就会使用上述编码进行转换。URLDecoder
用于把后者转换成前者,URLEncoder
则相反。形参都是
(String s, String enc)
,enc
是字符集 -
URL
、URLConnection
、URLPermission
URL类包含如下实例方法:
getFile()
:获取资源名getHost()
:获取主机名getPath()
:获取URL的路径部分getPort()
:int端口号getProtocol
getQuery()
:获取查询字符串URLConnection
代表与URL引用的远程对象的通信连接(TCP连接),由URL类实例的openConnection()
返回得到,HttpURLConnection
表示与URL之间的HTTP连接。URLConnection
可以走邮件、文件传输协议,而HttpURLConnection
就单指浏览器的HTTP协议InputStream openStream()
,得到一个读取该URL资源的InputStream
URLPermission
用于管理HttpURLConnection
的权限问题从创建URL连接、发送请求,到读取URL资源一般需要的步骤如下:
openConnection()
获取URLConnection
对象- 设置
URLConnection
的参数和普通请求属性 - 发送GET请求:直接用
connect()
建立实际连接即可;发送POST请求:获取URLConnection
实例对应的输出流来发送请求参数(必须设置setDoOutput(true);setDoInput(true);
) - 等待远程资源变成可用,通过访问头字段或通过输入流读取远程资源的数据
-
-
TCP网络编程
-
建立服务端
使用
ServerSocket
类,用于监听客户端请求Socket accpet()
:返回与客户端对应的Socket
对象;若没有客户端连接则一直处于阻塞状态close();
:关闭该ServerSocket
构造器:
ServerSocket(int port)
:指定端口建立ServerSocket(int port, int backlog)
:启用用于改变连接队列长度的backlog
参数ServerSocket(int port, int backlog, InetAddress localAddr)
:服务端有多个IP,将该实例绑定到指定的IP -
通信
使用
Socket
类进行通信,其构造器需要指定远程主机和其端口InputStream getIntputStream()
:得到Socket
的输入流OutputStream getOutputStream()
:得到Socket
的输出流setSoTimeout(int timeout)
:超过此时间认为超时通信失败,如果超时后仍然操作Socket
,那么会抛出SocketTimeoutException
异常判断建立连接超时:先创建无连接的Socket,再调用
connect(InetAddress host, int timeout)
实例方法设置超时时长。 -
多线程的必要性
如果使用传统的
BufferReader
的readLine()
方法,那么在该方法返回成功之前,线程将被阻塞,所以服务端应该为每个不同的客户端连接建立一个线程;同样地,客户端也应该专门为从服务端读取数据建立一个线程。特别地:如果考虑聊天室的话,其实是一个全连接的模型:群聊(一对多)、私聊(一对一),需要建立一个根据
value
映射key
的特殊map
,因为此map
一个key
(客户端)的value
(输出流)不能与别的重复。 -
半关闭
shutdownInput()
、isInputShutdown()
shutdownOutput()
、isOutputShutdown()
一旦关闭其中一个流,就无法再次打开
如果通过获取Socket的输入/输出流,并单独调用IO流的
close()
方法,则会导致整个Socket
被关闭 -
NIO
实现非阻塞式Socket
通信Selector
类,通过其静态的open方法来获取实例,可同时监控多个SelectableChannel
的IO状况,是非阻塞式IO的核心。有三种
SelectionKey
集合:SelectionKey keys()
:所有注册在Selector
上的Channel
集合SelectionKey selectedKeys()
:可被select()
方法获取的需要IO处理的Channel
集合SelectionKey
被取消注册关系的Channel集合
select
系列方法:主要是轮询可读的Channel,是阻塞方法SelectableChannel
:支持非阻塞IO的Channel对象,可通过实例方法register()
注册到Selector
上,由SelectionKey
表示。同时该类支持阻塞和非阻塞两种模式,可通过SelectableChannel configureBlocking(boolean block)
设置,通过boolean isBlocking()
来获取模式。但是不同的SelectableChannel
支持的操作不尽相同,比如ServerSocketChannel
就只代表ServerSocket
,只支持OP_ACCEPT
操作,可以通过int validOps()
获取他支持的所有操作。使用
ServerSocketChannel
来建立服务端:ServerSocketChannel server = ServerSocketChannel.open(); /*SelectableChannel只能通过open方法获得*/ InetSocketAddress isa = new InetSocketAddress("127.0.0.1", 30000); server.bind(isa); /*java7以后支持bind方法,否则需要先获取ServerSocket对象,用这个对象去关联地址和端口*/ server.configureBlocking(false); server.register(selector, SelectionKey.OP_ACCEPT);
-
AIO
实现非阻塞通信与同步IO的区别:
AIO
通过OS完成IO,再将结果返回给程序,而同步IO则是由程序自主实现IO,此时会阻塞线程。这种方式比较复杂。为了达到完全的异步操作,可以使用
CompletionHandler
监听器来监测IO是否完成。
-
-
UDP网络编程
Java使用
DatagramSocket
类来处理UDP通信。构造器:
DatagramSocket()
:绑定到本机默认IP和某个端口DatagramSocket(int port)
DatagramSocket(int port, InetAddress laddr)
发送与接收:
receive(DatagramPacket p)
send(DatagramPacket p)
数据包自主决定目的地:
DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)
:以buf创建数据包对象,从offset开始长度为length的数据包,发送到指定的目的地。(最复杂的构造器)setData(byte[] buf)
实例方法,可以反复设置其中的数据内容有三种实例方法知道
DatagramSocket
的来源:InetAddress getAddress()
int getPort()
SocketAddress getSocketAddress()
,SocketAddress
类封装了一个InetAddress
对象和一个int
值(端口)
多点广播:
MulticastSocket
joinGroup(InetAddress multicastAddr)
:加入指定的多点广播地址leaveGroup(InetAddress multicastAddr)
:离开指定的多点广播地址 -
代理服务器
直接使用
Proxy
类创建URLConnection