服务端代码
package com.example.nettytest.nio.day3;
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;
/**
* @description: NIO(Selector处理write事件 写入内容过多问题)代码示例
* @author: xz
* @create: 2022-09-18
*/
public class Test6Server {
public static void main(String[] args) throws IOException {
writeServer1();
}
/**
* Selector写入内容过多问题 代码示例
* */
public static void writeServer1() throws IOException{
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.configureBlocking(false);
Selector selector = Selector.open();
ssc.register(selector, SelectionKey.OP_ACCEPT);
ssc.bind(new InetSocketAddress(8080));
while (true) {
selector.select();
Iterator<SelectionKey> iter = selector.selectedKeys().iterator();
while (iter.hasNext()) {
SelectionKey key = iter.next();
iter.remove();
if (key.isAcceptable()) {
SocketChannel sc = ssc.accept();
sc.configureBlocking(false);
SelectionKey sckey = sc.register(selector, 0, null);
sckey.interestOps(SelectionKey.OP_READ);
// 1. 向客户端发送大量数据
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 9000000; i++) {
sb.append("a");
}
ByteBuffer buffer = Charset.defaultCharset().encode(sb.toString());
if (buffer.hasRemaining()) {
// 2. 返回值代表实际写入的字节数
int write = sc.write(buffer);
System.out.println("实际写入的字节数===="+write);
}
}
}
}
}
}
客户端代码示例
package com.example.nettytest.nio.day3;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
/**
* @description:
* @author: xz
* @create: 2022-09-18
*/
public class Test6Client {
public static void main(String[] args) throws IOException {
SocketChannel sc = SocketChannel.open();
sc.connect(new InetSocketAddress("localhost", 8080));
// 3. 接收数据
int count = 0;
while (true) {
ByteBuffer buffer = ByteBuffer.allocate(1024 * 1024);
count += sc.read(buffer);
System.out.println("实际读取到的字节数==="+count);
buffer.clear();
}
}
}
启动服务端,控制台输出如下:

启动客户端,控制台输出如下:

再处理write事件代码中,代码修如下:
// 2. 返回值代表实际写入的字节数
int write = sc.write(buffer);
System.out.println("实际写入的字节数===="+write);
// 3. 判断是否有剩余内容
if (buffer.hasRemaining()) {
/**
* 4、关注事件
*sckey.interestOps 表示关注原先注册的事件
* SelectionKey.OP_WRITE 表示关注可写事件
*/
sckey.interestOps(sckey.interestOps() + SelectionKey.OP_WRITE);
// 5. 把未写完的数据挂到 sckey 上
sckey.attach(buffer);
}else if (key.isWritable()) {
ByteBuffer buffer1 = (ByteBuffer) key.attachment();
SocketChannel sc1 = (SocketChannel) key.channel();
int write1 = sc1.write(buffer1);
System.out.println("实际写入的字节数:"+write1);
// 6. 清理操作
if (!buffer.hasRemaining()) {
// 需要清除buffer
key.attach(null);
//不需关注可写事件
key.interestOps(key.interestOps() - SelectionKey.OP_WRITE);
}
}
修改后的完整代码示例
package com.example.nettytest.nio.day3;
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;
/**
* @description: NIO(Selector处理write事件 写入内容过多问题)代码示例
* @author: xz
* @create: 2022-09-18
*/
public class Test6Server {
public static void main(String[] args) throws IOException {
writeServer2();
}
/**
* 解决 Selector写入内容过多问题的方式 代码示例
* */
public static void writeServer2() throws IOException{
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.configureBlocking(false);
Selector selector = Selector.open();
ssc.register(selector, SelectionKey.OP_ACCEPT);
ssc.bind(new InetSocketAddress(8080));
while (true) {
selector.select();
Iterator<SelectionKey> iter = selector.selectedKeys().iterator();
while (iter.hasNext()) {
SelectionKey key = iter.next();
iter.remove();
if (key.isAcceptable()) {
SocketChannel sc = ssc.accept();
sc.configureBlocking(false);
SelectionKey sckey = sc.register(selector, 0, null);
sckey.interestOps(SelectionKey.OP_READ);
// 1. 向客户端发送大量数据
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 9000000; i++) {
sb.append("a");
}
ByteBuffer buffer = Charset.defaultCharset().encode(sb.toString());
// 2. 返回值代表实际写入的字节数
int write = sc.write(buffer);
System.out.println("实际写入的字节数===="+write);
// 3. 判断是否有剩余内容
if (buffer.hasRemaining()) {
/**
* 4、关注事件
*sckey.interestOps 表示关注原先注册的事件
* SelectionKey.OP_WRITE 表示关注可写事件
*/
sckey.interestOps(sckey.interestOps() + SelectionKey.OP_WRITE);
// 5. 把未写完的数据挂到 sckey 上
sckey.attach(buffer);
}else if (key.isWritable()) {
ByteBuffer buffer1 = (ByteBuffer) key.attachment();
SocketChannel sc1 = (SocketChannel) key.channel();
int write1 = sc1.write(buffer1);
System.out.println("实际写入的字节数:"+write1);
// 6. 清理操作
if (!buffer.hasRemaining()) {
// 需要清除buffer
key.attach(null);
//不需关注可写事件
key.interestOps(key.interestOps() - SelectionKey.OP_WRITE);
}
}
}
}
}
}
}
启动服务端,控制台输出如下:

启动客户端,控制台输出如下:
