使用NIO完成网络通信的三个核心。
- 通道(Channel): 负责连接。
java.nio.channels.Channel
| -- SelectableChannel
| -- SocketChannel
| -- ServerSocketChannel
| -- DatagramChannel
| -- Pipe.SinkChannel
| -- Pipe.SourceChannel- 缓冲区(Buffer): 负责数据存取。
- 选择器(Selector): 负责监控SelectableChannel的IO状况。非阻塞式才使用到Selector。
阻塞式示例
示例:
@Test
public void client() throws IOException {
FileChannel inChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9898));
ByteBuffer bytes = ByteBuffer.allocate(1024);
while (inChannel.read(bytes) != -1) {
bytes.flip();
socketChannel.write(bytes);
bytes.clear();
}
socketChannel.close();
inChannel.close();
}
@Test
public void server() throws IOException {
ServerSocketChannel ssChannel = ServerSocketChannel.open();
FileChannel outChannel = FileChannel.open(Paths.get("2.jpg"),
StandardOpenOption.READ, StandardOpenOption.WRITE,
StandardOpenOption.CREATE
);
ssChannel.bind(new InetSocketAddress(9898));// 绑定端口
SocketChannel socketChannel = ssChannel.accept();// 获取客户端的通道
ByteBuffer bytes = ByteBuffer.allocate(1024);
while (socketChannel.read(bytes) != -1) {
bytes.flip();
outChannel.write(bytes);
bytes.clear();
}
socketChannel.close();
outChannel.close();
ssChannel.close();
}
一个较完整的示例,带有客户端与服务端的反馈:
@Test
public void client() throws IOException {
FileChannel inChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9898));
ByteBuffer bytes = ByteBuffer.allocate(1024);
while (inChannel.read(bytes) != -1) {
bytes.flip();
socketChannel.write(bytes);
bytes.clear();
}
// 关闭(阻塞式需要告诉服务端发完了。
socketChannel.shutdownOutput();
// 接受服务端发来的反馈。
// 反馈的内容到SocketChannel中,所以从SocketChannel读。
int len;
while ((len = socketChannel.read(bytes)) != -1) {
bytes.flip();
System.out.println(new String(bytes.array(), 0, len));
bytes.clear();
}
socketChannel.close();
inChannel.close();
}
@Test
public void server() throws IOException {
ServerSocketChannel ssChannel = ServerSocketChannel.open();
FileChannel outChannel = FileChannel.open(Paths.get("2.jpg"),
StandardOpenOption.READ, StandardOpenOption.WRITE,
StandardOpenOption.CREATE
);
ssChannel.bind(new InetSocketAddress(9898));// 绑定端口
SocketChannel socketChannel = ssChannel.accept();// 获取客户端的通道
ByteBuffer bytes = ByteBuffer.allocate(1024);
while (socketChannel.read(bytes) != -1) {
bytes.flip();
outChannel.write(bytes);
bytes.clear();
}
// 处理完发送反馈给客户端
bytes.put("服务端数据接收成功".getBytes());
bytes.flip();
socketChannel.write(bytes);
socketChannel.close();
outChannel.close();
ssChannel.close();
}
非阻塞式示例
TCP示例
客户端:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.Date;
import java.util.Scanner;
public class Client {
public static void main(String[] args) throws IOException {
// 打开通道
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9898));
socketChannel.configureBlocking(false); // 非阻塞模式
Scanner scan = new Scanner(System.in); // 输入数据
// 发送数据
ByteBuffer buffer = ByteBuffer.allocate(1024);
while (scan.hasNext()) {
String str = String.format("%s\n%s", new Date().toString(), scan.next());
buffer.put(str.getBytes());
buffer.flip();
socketChannel.write(buffer);
buffer.clear();
}
// 关闭通道
socketChannel.close();
}
}
服务端:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
public class Server {
public static void main(String[] args) throws IOException {
ServerSocketChannel sschannel = ServerSocketChannel.open();
sschannel.configureBlocking(false);// 非阻塞模式
sschannel.bind(new InetSocketAddress(9898));
// 获取选择器
Selector selector = Selector.open();
// 注册到选择器上,并指定选择键。
sschannel.register(selector, SelectionKey.OP_ACCEPT);
// 轮询获取选择器上已"准备就绪"事件
while (selector.select() > 0) {
// 获取选择器上已注册的选择键
Iterator it = selector.selectedKeys().iterator();
while (it.hasNext()) {
// 选择键获取事件
SelectionKey sk = it.next();
// 判断事件类型,处理
if (sk.isAcceptable()) {
SocketChannel socketChannel = sschannel.accept();
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ);
} else if (sk.isReadable()) {
SocketChannel socketChannel = (SocketChannel) sk.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int len = 0;
while ((len = socketChannel.read(buffer)) > 0) {
buffer.flip();
System.out.println(new String(buffer.array(), 0, len));
buffer.clear();
}
}
// 用完删掉
it.remove();
}
}
}
}
UDP示例
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.util.Date;
import java.util.Scanner;
public class UDPClient {
public static void main(String[] args) throws IOException {
DatagramChannel dc = DatagramChannel.open();
dc.configureBlocking(false);
Scanner scan = new Scanner(System.in);
ByteBuffer buffer = ByteBuffer.allocate(1024);
while (scan.hasNext()) {
String str = String.format("%s\n%s", new Date().toString(), scan.next());
buffer.put(str.getBytes());
buffer.flip();
dc.send(buffer, new InetSocketAddress("127.0.0.1",9898));
buffer.clear();
}
dc.close();
}
}
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Iterator;
public class UDPServer {
public static void main(String[] args) throws IOException {
DatagramChannel dc = DatagramChannel.open();
dc.configureBlocking(false);
dc.bind(new InetSocketAddress(9898));
Selector selector = Selector.open();
dc.register(selector, SelectionKey.OP_READ);
while (selector.select() > 0) {
Iterator it = selector.selectedKeys().iterator();
while (it.hasNext()) {
SelectionKey sk = it.next();
if (sk.isReadable()) {
ByteBuffer buffer = ByteBuffer.allocate(1024);
dc.receive(buffer);
buffer.flip();
System.out.println(new String(buffer.array(), 0, buffer.limit()));
buffer.clear();
}
}
it.remove();
}
}
}