Java使用NIO实现Socket通信
一、介绍
在上次的博客中,已经了解到NIO
当中最为重要的两个对象。分别是缓冲Buffer
和通道Channel
,也进行了基本的使用,不过使用的是FileChannel
,主要用来与文件打交道。
那么,这一次使用NIO
实现Socket
网络通信,主要是使用到ServerSocketChannel
和SocketChannel
。
同样,在本次作为NIO
的网络通信,建议先了解传统BIO
的网络通信,传送门在此。
二、实现
1)服务端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
| package com.banmoon.test;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.*; import java.nio.charset.StandardCharsets; import java.util.Iterator; import java.util.Set;
@Slf4j public class TestSocketServer {
public static void main(String[] args) throws IOException { ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); Selector selector = Selector.open(); serverSocketChannel.socket().bind(new InetSocketAddress(2333)); serverSocketChannel.configureBlocking(false);
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) { if (selector.select(2000) == 0) { log.info("服务器已等待2秒,继续静默等待"); continue; }
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator(); while (iterator.hasNext()) { SelectionKey selectionKey = iterator.next(); if (selectionKey.isAcceptable()) { SocketChannel socketChannel = serverSocketChannel.accept(); socketChannel.configureBlocking(false); socketChannel.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(1024)); }
if (selectionKey.isReadable()) { SocketChannel socketChannel = (SocketChannel) selectionKey.channel(); ByteBuffer byteBuffer = (ByteBuffer) selectionKey.attachment(); socketChannel.read(byteBuffer); byteBuffer.flip(); log.info("服务端接受到数据:{}", new String(byteBuffer.array(), 0, byteBuffer.limit(), StandardCharsets.UTF_8)); }
iterator.remove(); } }
}
}
|
2)客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| package com.banmoon.test;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; import java.nio.charset.StandardCharsets; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit;
@Slf4j public class TestSocketClient {
public static void main(String[] args) throws IOException, InterruptedException { SocketChannel socketChannel = SocketChannel.open(); socketChannel.configureBlocking(false); InetSocketAddress netAddress = new InetSocketAddress("127.0.0.1", 2333); if (!socketChannel.connect(netAddress)) { while (!socketChannel.finishConnect()) { log.info("与服务器连接中,请稍后"); TimeUnit.SECONDS.sleep(1); } } log.info("连接服务器成功"); String str = "hello,半月无霜"; ByteBuffer byteBuffer = ByteBuffer.wrap(str.getBytes(StandardCharsets.UTF_8)); socketChannel.write(byteBuffer); CountDownLatch countDownLatch = new CountDownLatch(1); countDownLatch.await(); }
}
|
3)测试
先启用服务端,再启用客户端,客户端可以启用多个
或者也可以先启用客户端,再启用服务端
服务端 |
客户端 |
|
|
三、最后
实际上,这只是简单的一个应用,后续复杂的都是基于此简单的服务、客户端进行展开。继续加油!
我是半月,祝你幸福!!!