ServerSocketChannel
ServerSocketChannel作用?就是专职干什么的?
1、监听新进来的TCP链接通道,
2、创建新的SocketChannel
ServerSocketChannel 不具备 什么能力
ServerSocketChannel并不能进行数据传输的能力
如何创建ServerSocketChannel实例
ServerSocketChannel socketChannel =ServerSocketChannel.open();
该对象关联了一个未绑定ServerSocket的通道,
为ServerSocketChannel绑定监听端口号
JDK1.7前,需要调用ServerSocketChannel的socket方法,再调用bind()来进行关联
JDK1.7后,就可以直接调用ServerSocketChannel的bind()来进行端口绑定了。
ServerSocketChannel如何监听新进来的连接
通过 ServerSocketChannel.accept() 方法监听新进来的连接。
ServerSocketChannel 默认是 阻塞模式,可以查看JDK源码
如下,所示:
通过ServerSocketChannel.configureBlocking(true)来设定阻塞模式
1、在阻塞模式下,
如果有新的连接进来,那么accept()方法返回的是一个包含新进来的连接的SocketChannel,
如果没有新的连接,那么accept()方法,就会一直阻塞在这里,直到有的新连接进来
2、在非阻塞模式下ServerSocketChannel. configureBlocking(false)
如果有连接进来,那么accept()方法返回的是一个包含新进来的连接的SocketChannel
如果没有新的连接,那么accept()方法会立即返回null
3、阻塞模式与非阻塞模式的根本区别?
其实,就是在没有新的连接的情况下,如何处理的?不返回,一直等待的话,就是阻塞;
如果立即返回的话,就是非阻塞了。
SocketChannel
创建SocketChannel的方式?
方式一:在客户端创建
SocketChannel socketChannel = SocketChannel.open();
方式二:在服务器端创建
ServerSocketChannel接受一个连接请求后得到,如
SocketChannel socketChannel = serverSocketChannel.accept();
将管道中的数据读到缓存里,用的是socketChannel的read方法
int read = socketChannel.read(sizeBuffer);
将缓存里的数据写到管道中,用的是socketChannel的write方法
socketChannel.write(sizeBuffer);
例子如下:
服务端:
package xingej.channel; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; public class ServerSocketChannelTest { public void initChannel() throws IOException { //服务器端,通过open方法,来创建ServerSocketChannel //注意,此时,服务器端,还没有进行绑定端口呢 ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); //设置为非阻塞模式 // serverSocketChannel.configureBlocking(false); //绑定端口号 //JDK1.7版本之后的写法 serverSocketChannel.bind(new InetSocketAddress(8081)); //JDK1.7版本之前的写法 // serverSocketChannel.socket().bind(new InetSocketAddress(8081)); //创建字节缓存区 //缓存区的大小是1024字节,这个可以自己调试,如改成64,128.... ByteBuffer byteBuffer = ByteBuffer.allocate(1024); while (true) { System.out.println("-------服务器端-----开始接收-----客户端的连接---------"); //在服务器端,接收客户端的链接,如果存在客户端的话,就返回一个 //SocketChannel对象 //如果是阻塞模式的话,没有新的链接进来,就会阻塞在这里,否则,往下执行 //如果是非阻塞模式的话,没有新的链接进来,就会立马返回一个null,程序不会阻塞在这里, //会立马往下进行的 SocketChannel socketChannel = serverSocketChannel.accept(); if (null != socketChannel) { while (true) { //清楚缓存区的数据,可以接收新的数据 byteBuffer.clear(); //将管道socketChannel的数据读取到 缓存byteBuffer里 //readSize 表示 读取的字节数 int readSize = socketChannel.read(byteBuffer); if (readSize == -1) { break; } //再从 字节缓存里,进行其他 业务逻辑操作,\ // 注意,这里的缓存区使用的字节类型 // 因此,如果需要其他类型的话,需要进行转换 System.out.println(new String(byteBuffer.array())); } } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) throws IOException { new ServerSocketChannelTest().initChannel(); } }
客户端如下:
package xingej.channel; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; public class SocketChannelTest { public void connectServer() throws IOException{ // 创建一个 SocketChannel对象, // 请注意,并没有进行 链接服务器端哦 SocketChannel socketChannel = SocketChannel.open(); //开始链接服务器端 socketChannel.connect(new InetSocketAddress("localhost", 8081)); //在客户端创建 字节缓存区 ByteBuffer byteBuffer = ByteBuffer.allocate(1024); String msg = "\nhello, nio, hello ,spark, hello ,hadoop, flume, mesos, marathon, netty, mina, stream, inputstream, outputstream \n" + "hello, nio, hello ,spark, hello ,hadoop, flume, mesos, marathon, netty, mina, stream, inputstream, outputstream \n" + "hello, nio, hello ,spark, hello ,hadoop, flume, mesos, marathon, netty, mina, stream, inputstream, outputstream 北京\n"; //往字节缓存区,添加数据 byteBuffer.put(msg.getBytes()); // 针对是更新limit值,将此值更新为position了,用于接下来的读操作 byteBuffer.flip(); while(byteBuffer.hasRemaining()) { //将字节缓存里的数据,写到管道中去 socketChannel.write(byteBuffer); } socketChannel.close(); } public static void main(String[] args) throws IOException{ new SocketChannelTest().connectServer(); } }
启动方式:
先启动服务器端,然后再启动客户端