ServerSocketChannel和SocketChannel
Posted 疯狂的妞妞
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ServerSocketChannel和SocketChannel相关的知识,希望对你有一定的参考价值。
暂未考虑花大时间去学这些底层代码,直接进入框架的学习,代码来自网络
Server
package spring.server; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.nio.charset.Charset; import java.util.Iterator; public class Server { /* * 处理器类 */ static class Handler { private int bufferSize = 1024; // 缓冲器容量 private String localCharset = "UTF-8"; // 编码格式 public Handler() { } public Handler(int bufferSize) { this(bufferSize, null); } public Handler(String localCharset) { this(-1, localCharset); } public Handler(int bufferSize, String localCharset) { if (bufferSize > 0) { this.bufferSize = bufferSize; } if (localCharset != null) { this.localCharset = localCharset; } } /* * 连接请求处理方法 */ public void handleAccept(SelectionKey selectionKey) throws IOException { // 通过选择器键获取服务器套接字通道,通过accept()方法获取套接字通道连接 SocketChannel socketChannel = ((ServerSocketChannel) selectionKey.channel()).accept(); // 设置套接字通道为非阻塞模式 socketChannel.configureBlocking(false); // 为套接字通道注册选择器,该选择器为服务器套接字通道的选择器,即选择到该SocketChannel的选择器 // 设置选择器关心请求为读操作,设置数据读取的缓冲器容量为处理器初始化时候的缓冲器容量 socketChannel.register(selectionKey.selector(), SelectionKey.OP_READ, ByteBuffer.allocate(bufferSize)); } public void handleRead(SelectionKey selectionKey) throws IOException { // 获取套接字通道 SocketChannel socketChannel = (SocketChannel) selectionKey.channel(); // 获取缓冲器并进行重置,selectionKey.attachment()为获取选择器键的附加对象 ByteBuffer byteBuffer = (ByteBuffer) selectionKey.attachment(); byteBuffer.clear(); // 没有内容则关闭通道 if (socketChannel.read(byteBuffer) == -1) { socketChannel.close(); } else { // 将缓冲器转换为读状态 byteBuffer.flip(); // 将缓冲器中接收到的值按localCharset格式编码保存 String receivedRequestData = Charset.forName(localCharset).newDecoder().decode(byteBuffer).toString(); System.out.println("接收到客户端的请求数据:" + receivedRequestData); // 返回响应数据给客户端 String responseData = "已接收到你的请求数据,响应数据为:(响应数据)"; byteBuffer = ByteBuffer.wrap(responseData.getBytes(localCharset)); socketChannel.write(byteBuffer); // 关闭通道 socketChannel.close(); } } } public static void main(String[] args) { try { // 创建ServerSocketChannel通道,绑定监听端口为8080 ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.socket().bind(new InetSocketAddress(8080)); // 设置为非阻塞模式 serverSocketChannel.configureBlocking(false); // 注册选择器,设置选择器选择的操作类型 Selector selector = Selector.open(); serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); // 创建处理器 Handler handler = new Handler(1204); while (true) { // 等待请求,每次等待阻塞3s,超过时间则向下执行,若传入0或不传值,则在接收到请求前一直阻塞 if (selector.select(3000) == 0) { System.out.println("等待请求超时......"); continue; } System.out.println("-----处理请求-----"); // 获取待处理的选择键集合 Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator(); while (keyIterator.hasNext()) { SelectionKey selectionKey = keyIterator.next(); try { // 如果是连接请求,调用处理器的连接处理方法 if (selectionKey.isAcceptable()) { handler.handleAccept(selectionKey); } // 如果是读请求,调用对应的读方法 if (selectionKey.isReadable()) { handler.handleRead(selectionKey); } } catch (IOException e) { keyIterator.remove(); continue; } } // 处理完毕从待处理集合移除该选择键 keyIterator.remove(); } } catch (IOException e) { e.printStackTrace(); } } }
Client
package spring.server; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; public class Client { public static void main(String[] args) throws IOException { SocketChannel socketChannel = SocketChannel.open(); socketChannel.connect(new InetSocketAddress("127.0.0.1", 8080)); String newData = "New String to write to file..." + System.currentTimeMillis(); ByteBuffer buf = ByteBuffer.allocate(48); buf.clear(); buf.put(newData.getBytes()); buf.flip(); while (buf.hasRemaining()) { socketChannel.write(buf); } // socketChannel.configureBlocking(false); // socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80)); // // while(! socketChannel.finishConnect() ){ // //wait, or do something else... // } socketChannel.close(); } }
以上是关于ServerSocketChannel和SocketChannel的主要内容,如果未能解决你的问题,请参考以下文章
ServerSocketChannel和SocketChannel
网络编程模型之NIO-ServerSocketChannel