一.前言
前篇文章中了解了SocketChannel:提供了连接到套接字通道,从某种层面而言,NIO中提供了类似于java.net包中对于网络操作的api的功能。既然已经有连接到Socket套接字的通道,可以主动发起连接、传输数据,还缺少接收连接(client端)。不言而喻,还缺少接收连接,接收数据的通道(server端)。这篇文章就主要介绍监听套接字的通道ServerSocketChannel。
二.ServerSocketChannel
A selectable channel for stream-oriented listening sockets.
上述摘自java docs中定义:ServerSocketChannel是面向流的监听socket套接字的可选择性通道。从定义中可以看出以下几点:
- 具有阻塞和非阻塞两种模式
- 可以注册到多路复用器上
- 基于TCP连接
- 需要绑定到特定端口上
ServerSocketChannel可以被无参的open()
方法创建。但是改方法只是创建了一个ServerSocketChannel对象,并没有进行绑定操作,仍需要调用bind()
方法进行绑定,使之监听某个套接字。未进行绑定的ServerSocketChannel调用accept()
,将会抛出NotYetBoundException
异常。
ServerSocketChannel支持的可选参数:
参数名 | 作用描述 |
---|---|
SO_RCVBUF | 套接字接收缓冲区大小 |
SO_REUSEADDR | 重新使用地址 |
ServerSocketChannel支持两种模式:阻塞模式和非阻塞模式。且是线程安全的
三.ServerSocketChannel使用
1.创建ServerSocketChannel
ServerSocketChannel channel = ServerSocketChannel.open(); //创建ServerSocketChannel
2.绑定到本机网络接口
channel.bind(new InetSocketAddress(8091)); //绑定至8091端口
3.接收连接
SocketChannel socketChannel = channel.accept();
ServerSocketChannel的accept方法返回SocketChannel套接字通道,用于读取请求数据和写入响应数据。
ServerSocketChannel的阻塞和非阻塞体现在这里:- 阻塞模式:在调用accept方法后,将阻塞知道有新的socket连接时返回SocketChannel对象,代表新建立的套接字通道。
- 非阻塞模式:在调用accept方法后,如果无连接建立,则返回
null
;如果有连接,则返回SocketChannel。
四.简单的client-server
创建简单的server:
public void createServerSocketChannel() throws IOException { ServerSocketChannel channel = ServerSocketChannel.open(); channel.bind(new InetSocketAddress(8091)); while (true) { SocketChannel socketChannel = channel.accept(); ByteBuffer byteBuffer = ByteBuffer.allocate(16); int count = socketChannel.read(byteBuffer); while(count != -1) { byteBuffer.flip(); while (byteBuffer.hasRemaining()) { System.out.print((char) byteBuffer.get()); } byteBuffer.clear(); count = socketChannel.read(byteBuffer); } System.out.println(); }}
创建简单client:
public void client() throws IOException { SocketChannel socketChannel = SocketChannel.open( new InetSocketAddress("10.17.83.11", 8091)); String msg = "ok"; socketChannel.write(ByteBuffer.wrap(msg.getBytes())); SocketChannel socketChannel3 = SocketChannel.open( new InetSocketAddress(8091)); socketChannel3.write(ByteBuffer.wrap(msg.getBytes())); System.out.println("s3"); SocketChannel socketChannel4 = SocketChannel.open( new InetSocketAddress(8091)); socketChannel4.write(ByteBuffer.wrap(msg.getBytes())); System.out.println("s4"); socketChannel4.close(); socketChannel3.close(); socketChannel.close();}
ServerSocketChannel基本上不会单独使用绝大多数情况下都是配合多路复用Selector选择器共同使用。这里只关注ServerSocketChannel本身,关于其与多路复用混合使用,后面再介绍Selector时再做详细介绍!