Java NIO(六)--ServerSocketChannel与SocketChannel

来源:互联网 发布:js flag用法 编辑:程序博客网 时间:2024/04/29 12:47

一、SocketChanel

1、创建SocketChannel

有两种方法可以获取一个SocketChannel实例 
1. 通过静态方法open打开一个
SocketChannel socketChannel = SocketChannel.open();

ServerSocketChannel接受一个连接请求后等到
SocketChannel socketChannel = serverSocketChannel.accept();

获取到实例后可通过connect方法与服务端建立连接:

socketChannel.connect(new InetSocketAddress(1234));

2、读写数据

SocketChannel的读写数据与其他通道没有区别,读数据使用多个read方法,将数据读取如一个buffer中,返回一个int值,表示成功读取的字节数,返回-1表示读取到了数据流的末尾了;
sizeBuffer.clear();int read = socketChannel.read(sizeBuffer);
使用write方法将buffer中的数据写入到通道中,同样需要循环写入;

buffer.flip();while (buffer.hasRemaining()) {    socketChannel.write(dest);}

3、非阻塞模式


非阻塞就是普通套接字的区别了,SocketChannel在非阻塞模式下,许多方法都是可能直接返回不等待的: 
1. connect方法,可能没有完成连接建立就已经返回,需要使用finishConnect,判断是否完成了连接; 
2. read方法,可能没有读取任何就返回了(不是到数据末尾),需要通过返回值判断; 
3. write方法,与阻塞模式一样,需要在循环中写入;


二、ServerSocketChannel

1、创建ServerSocketChannel

通过静态方法open获取一个实例,并使用bind方法绑定地址:
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();serverSocketChannel.bind(new InetSocketAddress(1234));

完成绑定后,可以通过accept方法,接受客户端连接请求,与客户端建立连接后,获取到一个SocketChannel实例,通过这个实例与建立连接的客户端进行通信;

2、非阻塞模式

ServerSocketChannel同样有非阻塞模式,此时,accept方法在没有连接请求是,可能返回Null,需要做判断处理;

三 实例

服务端代码:
import java.io.IOException;import java.net.InetSocketAddress;import java.net.ServerSocket;import java.net.Socket;import java.net.SocketAddress;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.util.Iterator;import java.util.Set;public class NIOServer {public static   int flag = 1;public static void main(String[] args) throws IOException {// 1. 定义ServerSocketChannel 并监听本机指定的端口ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();// 2. 设置非阻塞模式serverSocketChannel.configureBlocking(false);// 3. 检索与此通道关联的服务器套接字ServerSocket serverSocket = serverSocketChannel.socket();// 4. 进行服务的绑定serverSocket.bind(new InetSocketAddress(8889));// 5. 定义SelectorSelector selector = Selector.open();// 6. 注册selectorserverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);// 7.保持Server运行while (true) {// 7.1 返回读事件已经就绪的那些通道。 并进行判断if (selector.select(1000 * 4) == 0) {log("服务端在等待....");continue;}// 7.2 一旦调用了select()方法,并且返回值表明有一个或更多个通道就绪了// 然后可以通过调用selector的selectedKeys()方法,访问“已选择键集(selected key// set)”中的就绪通道。// --- 返回此选择器的已选择键集。Set<SelectionKey> selectionKeySet = selector.selectedKeys();Iterator<SelectionKey> iterator = selectionKeySet.iterator();SocketChannel client =  null;// 7.3 遍历获取while (iterator.hasNext()) {SelectionKey myKey = iterator.next();// 7.4 此键的通道是否已准备好接受新的套接字连接。if (myKey.isAcceptable()) {// 7.4.1接受到此通道套接字的连接。// 此方法返回的套接字通道(如果有)将处于阻塞模式。 client = serverSocketChannel.accept();// 7.4.2配置为非阻塞client.configureBlocking(false);Socket socket = client.socket();SocketAddress remoteAddr = socket.getRemoteSocketAddress();log("Connected to: " + remoteAddr + "  \t Connection Accepted:   \n");// 7.4.3注册到selector,等待连接client.register(selector, SelectionKey.OP_READ);} if (myKey.isReadable()) {// 7.5.1  返回为之创建此键的通道。client = (SocketChannel) myKey.channel();ByteBuffer byteBuffer = ByteBuffer.allocate(1024 * 3); // 7.5.2 将缓冲区清空以备下次读取byteBuffer.clear();// 读取服务器发送来的数据到缓冲区中int readCount = -1;readCount = client.read(byteBuffer);// 如果没有数据 则关闭if (readCount == -1) {Socket socket = client.socket(); SocketAddress remoteAddr = socket.getRemoteSocketAddress();log("Connection closed by client: " + remoteAddr);client.close();myKey.cancel();return;}   // 有数据 则打印输出String receiveText = new String( byteBuffer.array(),0,readCount);log("服务器端接受客户端数据--:"+receiveText);}// 移除iterator.remove();}}}private static void log(String str) {System.out.println(str);}}



客户端代码:

import java.io.IOException;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.SocketChannel;import java.util.ArrayList;  public class NIOClient { public static void main(String[] args) throws IOException, InterruptedException { // 1.在客户端定义ScoketChannel 连接指定的服务端InetSocketAddress crunchifyAddr = new InetSocketAddress("localhost", 8889);SocketChannel crunchifyClient = SocketChannel.open(crunchifyAddr); log("Connecting to Server on port 8889..."); // 2.定义发送的数据ArrayList<String> companyDetails = new ArrayList<String>();companyDetails.add("Lenovo");companyDetails.add("Samsung");companyDetails.add("Huawei");companyDetails.add("Facebook");companyDetails.add("Twitter");companyDetails.add("IBM");companyDetails.add("Google"); // 3.循环发送for (String companyName : companyDetails) { // 3.1 将字符转转换为字节byte[] message = new String(companyName).getBytes("UTF-8");// 3.2 定义Buffer 并将字节数组数据封装在Buffer中ByteBuffer buffer = ByteBuffer.wrap(message);// 3.3 Channel读取Buffer中的数据crunchifyClient.write(buffer); log("sending: " + companyName);// 清空Bufferbuffer.clear(); // 等待2000毫秒Thread.sleep(2000);}// 关闭ChannelcrunchifyClient.close();} private static void log(String str) {System.out.println(str);}}



0 0
原创粉丝点击