NIO学习笔记四 :SocketChannel 和 ServerSocketChannel

Java NIO中的SocketChannel是一个连接到TCP网络套接字的通道。可以通过以下2种方式创建SocketChannel:

打开一个SocketChannel并连接到互联网上的某台服务器。
SocketChannel channel = SocketChannel.open();
channel.connect(new InetSocketAddress(90));
一个新连接到达ServerSocketChannel时,会创建一个SocketChannel。
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(90));
SocketChannel channel = serverSocketChannel.accept();
关闭 SocketChannel
当用完SocketChannel之后调用SocketChannel.close()关闭SocketChannel:
socketChannel.close();

往SocketChannel中写入数据
ByteBuffer buffer = ByteBuffer.allocate(1024);
buffer.clear();
buffer.put("测试数据".getBytes("UTF-8"));
buffer.flip();
while(buffer.hasRemaining()){
socketChannel.write(buffer);
}
读取SocketChannel 中的数据
ByteBuffer buffer = ByteBuffer.allocate(1024);
int read = channel.read(buffer);

示例代码
客户端
public class SocketChanneClient {
public static void main(String args[]) throws Exception {
SocketChannel channel = SocketChannel.open();
channel.connect(new InetSocketAddress(90));
while (true) {
Scanner scanner = new Scanner(System.in);
String message = scanner.next();
sendMessage(channel,message);
}

}

public static void sendMessage(SocketChannel socketChannel, String mes) throws IOException {
if (mes == null || mes.isEmpty()){
return;
}
byte[] bytes = mes.getBytes("UTF-8");
int size = bytes.length;
ByteBuffer buffer = ByteBuffer.allocate(size);
buffer.clear();
buffer.put(bytes);
buffer.flip();
while(buffer.hasRemaining()){
socketChannel.write(buffer);
}
socketChannel.close();


}
}

服务端
public class ServerSocketChannelServer {
public static void main(String[] args) throws IOException{
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(90));
ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 10, 1000, TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<Runnable>(100));
while (true){
SocketChannel channel = serverSocketChannel.accept();
if ((channel !=null)){
executor.execute( new SocketChannelThread(channel));
}
}
}

}
线程池处理类
public class SocketChannelThread implements Runnable {
private SocketChannel channel;
private String remoteName;

public SocketChannelThread(SocketChannel channel) throws IOException {
this.channel = channel;
this.remoteName = channel.getRemoteAddress().toString();
System.out.println("客户:" + remoteName + " 连接成功!");
}

@Override
public void run() {
ByteBuffer buffer = ByteBuffer.allocate(1024);

byte b[];
while (true) {
try {
b = new byte[1024];
buffer.clear();
int read = channel.read(buffer);
StringBuilder sb = new StringBuilder();
if (read != -1) {
buffer.flip();
int index = 0;
while (buffer.hasRemaining()) {
b[index++] = buffer.get();
if (index >= read) {
index = 0;
sb.append(new String(b, "UTF-8"));
System.out.println(remoteName + ":" + sb.toString());
}
}
buffer.clear();
}

} catch (Exception e) {
System.out.println(remoteName + " 断线了,连接关闭");
try {
channel.close();
} catch (IOException ex) {
}
break;
}
}
}
}

以上创建SocketChannel 是阻塞式的 ,同时也支持非阻塞式的。
阻塞是服务端读取SocketChannel 数据时,如果读取不到,进程一直阻塞直到客户端有数据请求到服务端。
非阻塞是服务端读取SocketChannel 数据时,如果读取不到,java.nio.channels.SocketChannel#read(java.nio.ByteBuffer) 方法返回0
设置非阻塞模式
channel.configureBlocking(false);

 

posted @ 2018-05-12 09:23  霸王猿  阅读(641)  评论(0编辑  收藏  举报