Java网络编程——使用NIO实现非阻塞Socket通信
https://blog.csdn.net/yanmei_yao/article/details/8586199
JavaSocket学习—NIO实现非阻塞的通信
https://blog.csdn.net/henushang/article/details/84653615
Java Socket(六) 使用多线程实现多客户端的通信
https://blog.csdn.net/u013007900/article/details/50411649
Socket 多线程客户端与服务端(借鉴了他人)
https://blog.csdn.net/m0_38089615/article/details/80444794
java socket通信I/O阻塞>多线程实现非阻塞通信
https://blog.csdn.net/heroboyluck/article/details/78416782
示例代码见附件:很遗憾,太懒,代码内容还是我分的包,如果你要运行的话,还需要自己下一点小的功夫,改变一下包路径。
Server端代码:
- 
package com.henushang.socket.chapter4nio;
 - 
import java.io.IOException;
 - 
import java.net.InetSocketAddress;
 - 
import java.nio.ByteBuffer;
 - 
import java.nio.CharBuffer;
 - 
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;
 - 
import java.util.Set;
 - 
public class EchoServerNoBlock {
 - 
private int port = 8000;
 - 
private ServerSocketChannel serverSocketChannel;
 - 
Selector selector;
 - 
public EchoServerNoBlock() throws Exception {
 - 
selector = Selector.open();
 - 
serverSocketChannel = ServerSocketChannel.open();
 - 
serverSocketChannel.socket().setReuseAddress(true);
 - 
serverSocketChannel.configureBlocking(false);// 设置通信为非阻塞模式,没有这一配置,则无法实现非阻塞
 - 
serverSocketChannel.socket().bind(new InetSocketAddress(port));
 - 
System.out.println(“等待连接…”);
 - 
}
 - 
public void service() throws Exception {
 - 
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
 - 
while (selector.select() > 0) {
 - 
Set<SelectionKey> readyKeys = selector.selectedKeys();
 - 
Iterator<SelectionKey> iterator = readyKeys.iterator();
 - 
SelectionKey key = null;
 - 
while (iterator.hasNext()) {
 - 
try {
 - 
key = iterator.next();
 - 
iterator.remove();
 - 
if (key.isAcceptable()) {
 - 
System.out.println(“accept”);
 - 
ServerSocketChannel ssc = (ServerSocketChannel) key
 - 
.channel();
 - 
SocketChannel sc = ssc.accept();
 - 
System.out.println(“接收到链接”
 - 
+ sc.socket().getInetAddress() + “:”
 - 
+ sc.socket().getPort());
 - 
sc.configureBlocking(false);
 - 
ByteBuffer buffer = ByteBuffer.allocate(1024);
 - 
sc.register(selector, SelectionKey.OP_READ
 - 
| SelectionKey.OP_WRITE, buffer);
 - 
}
 - 
if (key.isReadable()) {
 - 
System.out.println(“read”);
 - 
receive(key);
 - 
}
 - 
if (key.isWritable()) {
 - 
send(key);
 - 
}
 - 
} catch (Exception e) {
 - 
e.printStackTrace();
 - 
if (key != null) {
 - 
key.cancel();
 - 
key.channel().close();
 - 
}
 - 
}
 - 
}
 - 
}
 - 
}
 - 
/**
 - 
* 发送消息处理方法
 - 
* @param key
 - 
* @throws Exception
 - 
* @author henushang
 - 
*/
 - 
public void send(SelectionKey key) throws Exception {
 - 
ByteBuffer buffer = (ByteBuffer) key.attachment();
 - 
SocketChannel socketChannel = (SocketChannel) key.channel();
 - 
buffer.flip();
 - 
String data = decode(buffer);
 - 
if (data.indexOf(“\r\n”) == -1) {
 - 
return;
 - 
}
 - 
String outputData = data.substring(0, data.indexOf(“\n”) + 1);
 - 
System.out.println(outputData);
 - 
ByteBuffer outputBuffer = encode(“henushang:” + outputData);
 - 
while (outputBuffer.hasRemaining()) {
 - 
socketChannel.write(outputBuffer);
 - 
}
 - 
ByteBuffer temp = encode(outputData);
 - 
buffer.position(temp.limit());
 - 
buffer.compact();
 - 
if (outputData.equals(“byt\r\n”)) {
 - 
key.cancel();
 - 
socketChannel.close();
 - 
System.out.println(“关闭连接”);
 - 
}
 - 
}
 - 
/**
 - 
* 接受链接处理方法
 - 
* @param key
 - 
* @throws IOException
 - 
* @author henushang
 - 
*/
 - 
public void receive(SelectionKey key) throws IOException {
 - 
SocketChannel sc = (SocketChannel) key.channel();
 - 
ByteBuffer buffer = (ByteBuffer) key.attachment();
 - 
ByteBuffer readBuffer = ByteBuffer.allocate(32);
 - 
sc.read(readBuffer);
 - 
readBuffer.flip();
 - 
buffer.limit(readBuffer.capacity());
 - 
buffer.put(readBuffer);
 - 
}
 - 
static Charset charset = Charset.forName(“UTF-8″);
 - 
/**
 - 
* 解码
 - 
* @param byteBuffer
 - 
* @return
 - 
* @author henushang
 - 
*/
 - 
public static String decode(ByteBuffer byteBuffer) {
 - 
CharBuffer charBuffer = charset.decode(byteBuffer);
 - 
return charBuffer.toString();
 - 
}
 - 
/**
 - 
* 编码
 - 
* @param msg
 - 
* @return
 - 
* @author henushang
 - 
*/
 - 
public static ByteBuffer encode(String msg) {
 - 
return charset.encode(msg);
 - 
}
 - 
}
 
客户端代码:
- 
package com.henushang.socket.chapter4nio;
 - 
import java.io.BufferedReader;
 - 
import java.io.IOException;
 - 
import java.io.InputStreamReader;
 - 
import java.io.PrintWriter;
 - 
import java.net.InetAddress;
 - 
import java.net.InetSocketAddress;
 - 
import java.nio.channels.SocketChannel;
 - 
import com.henushang.socket.util.SocketUtils;
 - 
public class EchoClient {
 - 
private SocketChannel socketChannel;
 - 
private int port = 8000;
 - 
public EchoClient() throws Exception {
 - 
socketChannel = SocketChannel.open();
 - 
InetAddress inetAddress = InetAddress.getLocalHost();
 - 
InetSocketAddress inetSocketAddress = new InetSocketAddress(inetAddress, port);
 - 
socketChannel.connect(inetSocketAddress);
 - 
System.out.println(“准备连接服务器”);
 - 
}
 - 
public static void main(String[] args) throws Exception {
 - 
new EchoClient().talk();
 - 
}
 - 
public void talk() {
 - 
try {
 - 
BufferedReader reader = SocketUtils.getReader(socketChannel.socket());
 - 
PrintWriter pw = SocketUtils.getWriter(socketChannel.socket());
 - 
BufferedReader localreaderReader = new BufferedReader(new InputStreamReader(System.in));
 - 
String msg = null;
 - 
while ((msg = localreaderReader.readLine()) != null) {
 - 
System.out.println(msg);
 - 
pw.println(msg);
 - 
pw.flush();
 - 
System.out.println(reader.readLine());
 - 
if (“bye”.equals(msg)) {
 - 
break;
 - 
}
 - 
}
 - 
} catch (IOException e) {
 - 
e.printStackTrace();
 - 
}finally{
 - 
SocketUtils.close(socketChannel);
 - 
}
 - 
}
 - 
}
 
工具类代码:
- 
package com.henushang.socket.util;
 - 
import java.io.BufferedReader;
 - 
import java.io.IOException;
 - 
import java.io.InputStream;
 - 
import java.io.InputStreamReader;
 - 
import java.io.OutputStream;
 - 
import java.io.PrintWriter;
 - 
import java.net.Socket;
 - 
import java.nio.channels.SocketChannel;
 - 
public class SocketUtils {
 - 
public static PrintWriter getWriter(Socket socket) throws IOException {
 - 
OutputStream os = socket.getOutputStream();
 - 
return new PrintWriter(os);
 - 
}
 - 
public static PrintWriter getWriter(SocketChannel socketChannel) throws IOException {
 - 
return getWriter(socketChannel.socket());
 - 
}
 - 
public static BufferedReader getReader(Socket socket) throws IOException{
 - 
InputStream is = socket.getInputStream();
 - 
return new BufferedReader(new InputStreamReader(is, “UTF-8″));
 - 
}
 - 
public static BufferedReader getReader(SocketChannel socketChannel) throws IOException{
 - 
return getReader(socketChannel.socket());
 - 
}
 - 
public static void close(Socket socket) {
 - 
try {
 - 
if (socket != null) {
 - 
socket.close();
 - 
}
 - 
} catch (Exception e) {
 - 
e.printStackTrace();
 - 
}
 - 
}
 - 
public static void close(SocketChannel socketChannel) {
 - 
try {
 - 
if (socketChannel != null) {
 - 
socketChannel.close();
 - 
}
 - 
} catch (Exception e) {
 - 
e.printStackTrace();
 - 
}
 - 
}
 - 
public static String echo(String msg) {
 - 
return “echo:” + msg;
 - 
}
 - 
}
 
这种方式是一个线程在不停的循环检测监听到的事件,然后分别作出相应的处理。可是这种方式只适合那种处理过程时间短的情况,如果某一个操作处理的事件太长的话,则会让其他的事件一直处于等待状态,比如发送或者接收一个很大的文件,这样显然是很不合适的。
使用NIO的NoBlocking的操作方式固然减少了系统使用多线程建立连接的开销,但是也并不是完全适合任何情况的。
所以,在几种方式中没有最好的,只有最合适的。
而做程序也是一样的,没有那个语言是最好的,只有最合适的语言。