概念
阻塞&非阻塞
参照数据有没有准备好而言。
- 阻塞:数据没有准备好,用户线程不会继续往下执行。
- 非阻塞:不管数据有没有准备好,用户线程都继续执行。
==关键标志:用户线程是否可继续执行。==
同步&异步
参照同一时间点(时间段)内,能不能同时完成多个任务而言。
- 同步:同一时间段内,用户线程只能做一件事。
- 异步:同一时间段内,用户线程可完成多件事。
==关键标志:用户线程是否可执行其它操作。==
输入&输出
相对内存而言的。
- 输出:从内存中取出。
- 输入:存放入内存。
BIO->NIO->AIO
- BIO:同步阻塞
- NIO:同步非阻塞
- AIO:异步非阻塞
IO处理网络连接
BIO
- BIOServer
public class BIOServer {
ServerSocket server;
public BIOServer(int port){
try {
server = new ServerSocket(port);
System.out.println("BIOServer is started,the port is:" + port);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 监听客户端请求
*/
public void listener(){
while (true) {
try {
//该方法阻塞,没有接受到数据便不会往下执行
Socket client = server.accept();
//socket->RAM
InputStream is =client.getInputStream();
byte [] buff = new byte[1024];
//RAM-> Buff
int len = is.read(buff);
if(len > 0){
//Buff-> Console
String msg = new String(buff,0,len);
System.out.println("Client's msg: " + msg);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
new BIOServer(8080).listener();
}
}
- BIOClient
public class BIOClient {
private Socket client;
public BIOClient(int port){
try {
client = new Socket("localhost", port);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 发送消息
* @param msg
*/
public void sendMsg(String msg){
OutputStream os = null;
try {
//RAM->socket
os = client.getOutputStream();
os.write(msg.getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 关闭客户端
*/
public void closeClient(){
try {
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
BIOClient client = new BIOClient(8080);
client.sendMsg("Hello,I'm client!");
client.closeClient();
}
}
- Console
BIOServer is started,the port is:8080
Client's msg: Hello,I'm client!
NIO
- NIOServer
public class NIOServer {
private int port = 8080;
private ServerSocketChannel server;
//选择器
private Selector selector;
ByteBuffer receiveBuffer = ByteBuffer.allocate(1024);
ByteBuffer sendBuffer = ByteBuffer.allocate(1024);
Map<SelectionKey,String> sessionMsg = new HashMap<SelectionKey,String>();
public NIOServer(int port) throws IOException {
this.port = port;
server = ServerSocketChannel.open();
server.socket().bind(
new InetSocketAddress(this.port)
);
//默认为阻塞,手动设置为非阻塞
server.configureBlocking(false);
selector = Selector.open();
//管道注册为可接受状态
server.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("NIOServer is ready,the port is :"+this.port);
}
public void listener() throws IOException {
while (true) {
int i = selector.select();
if (i == 0 ) {
continue;
}
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> iterator = keys.iterator();
while (iterator.hasNext()) {
//处理具体事情
process(iterator.next());
//移除
iterator.remove();
}
}
}
private void process(SelectionKey key) throws IOException {
//判断是否建立好连接
if(key.isAcceptable()){
SocketChannel client = server.accept();
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_READ);
}
//读数据
else if (key.isReadable()) {
receiveBuffer.clear();
//这条管道是交给我们NIO API内部去处理的
SocketChannel client = (SocketChannel)key.channel();
int len = client.read(receiveBuffer);
if(len > 0){
String msg = new String(receiveBuffer.array(), 0, len);
sessionMsg.put(key, msg);
System.out.println("Client's msg:" + msg);
}
client.register(selector, SelectionKey.OP_WRITE);
}
//写数据
else if (key.isWritable()) {
//不是本管道,则不处理
if(!sessionMsg.containsKey(key)){ return;}
//通过key取得相应管道
SocketChannel client = (SocketChannel)key.channel();
sendBuffer.clear();
sendBuffer.put(new String(sessionMsg.get(key) + ",Your request has been processed!").getBytes());
sendBuffer.flip();//
client.write(sendBuffer);
key.cancel();
client.close();
}
}
public void closeServer(){
try {
server.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
NIOServer nioServer = null;
try {
nioServer = new NIOServer(8080);
nioServer.listener();
} catch (IOException e) {
e.printStackTrace();
} finally {
nioServer.closeServer();
}
}
}
- NIOCLient
public class NIOClient {
private SocketChannel client;
private int port = 8080;
private InetSocketAddress serverAdrress;
private Selector selector;
private ByteBuffer receiveBuffer = ByteBuffer.allocate(1024);
private ByteBuffer sendBuffer = ByteBuffer.allocate(1024);
public NIOClient(int port){
try {
this.port = port;
serverAdrress = new InetSocketAddress("localhost", this.port);
client = SocketChannel.open();
client.configureBlocking(false);
client.connect(serverAdrress);
selector = Selector.open();
client.register(selector, SelectionKey.OP_CONNECT);
} catch (IOException e) {
e.printStackTrace();
}
}
public void sendMsg(String msg) {
try {
boolean isFinished = false;
while (!isFinished) {
//
if (selector.select() > 0) {
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> iterator = keys.iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove();
if(key.isConnectable()){
client.register(selector, SelectionKey.OP_WRITE);
client.finishConnect();
}
if (key.isWritable()) {
sendBuffer.clear();
sendBuffer.put(msg.getBytes());
sendBuffer.flip();
client.write(sendBuffer);
client.register(selector, SelectionKey.OP_READ);
} else if (key.isReadable()) {
receiveBuffer.clear();
int len = client.read(receiveBuffer);
if (len > 0) {
receiveBuffer.flip();
System.out.println("Server's msg :" + new String(receiveBuffer.array(), 0, len));
}
isFinished = true;
key.cancel();
client.close();
selector.close();
}
}
}
}
} catch (ClosedChannelException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws IOException, InterruptedException {
ExecutorService executorService= Executors.newCachedThreadPool();
final Semaphore semaphore = new Semaphore(10);
for(int i=0;i<10;i++){
final int finalI = i;
Runnable runnable=new Runnable(){
@Override
public void run() {
try {
semaphore.acquire();
NIOClient client = new NIOClient(8080);
client.sendMsg("Hello,I'm client" + finalI + "!");
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
executorService.execute(runnable);
}
executorService.shutdown();
}
}
- 打印结果
NIOServer is ready,the port is :8080
Client's msg:Hello,I'm client5!
Client's msg:Hello,I'm client8!
Client's msg:Hello,I'm client0!
Client's msg:Hello,I'm client9!
Client's msg:Hello,I'm client4!
Client's msg:Hello,I'm client2!
Client's msg:Hello,I'm client1!
Client's msg:Hello,I'm client6!
Client's msg:Hello,I'm client3!
Client's msg:Hello,I'm client7!