1.IO第一阶段,BIO,阻塞式IO
服务器端代码:
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public abstract class Server {
public static int DEFAULT_HOSTS=7778;
public static ServerSocket serverSocket;
public static void start() throws IOException{
start(DEFAULT_HOSTS);
}
private static void start(int defaultHosts) throws IOException{
if (serverSocket!=null) return;
try {
serverSocket = new ServerSocket(defaultHosts);
System.out.println(("客户端已经启动" + defaultHosts));
Socket socket=serverSocket.accept();
new Thread(new ServerHandler(socket)).start();
}finally {
serverSocket.close();
}
}
public static void main(String[] args) {
Server server=new Server() {
@Override
public int hashCode() {
return super.hashCode();
}
};
try {
server.start(7778);
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户端代码:
import java.io.*;
import java.net.Socket;
public class Client {
private String ip="127.0.0.1";
private static final int port=7778;
private Socket socket=null;
PrintWriter printWriter=null;
BufferedReader bufferedReader=null;
public void sed(String s){
try {
socket=new Socket(ip,port);
bufferedReader=new BufferedReader(new InputStreamReader(socket.getInputStream()));
printWriter = new PrintWriter(socket.getOutputStream(), true);
printWriter.println(s);
String s1 ;
while (true){
if((s1 = bufferedReader.readLine())!=null)
System.out.println(s1);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Client client=new Client();
client.sed("start--");
}
核心源码:
/**
* Accepts connections.
* @param s the connection
*/
protected void accept(SocketImpl s) throws IOException {
acquireFD();
try {
socketAccept(s);
} finally {
releaseFD();
}
}
NIO阶段,同步非阻塞IO:
客户端输入消息:
public class NioClient {
public static void main(String[] args) {
InetSocketAddress address=new InetSocketAddress("127.0.0.1",7778);
SocketChannel socketChannel=null;
ByteBuffer byteBuffer=ByteBuffer.allocate(1024);
try {
socketChannel= SocketChannel.open();
socketChannel.connect(address);
while (true){
byte[] bytes=new byte[1024];
System.in.read(bytes);
byteBuffer.put(bytes);
byteBuffer.flip();
socketChannel.write(byteBuffer);
byteBuffer.clear();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
服务器端代码:
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; import java.util.Random; import java.util.Set; public class SeverHadler implements Runnable{ Selector selector=null; InetSocketAddress inetSocketAddress; //2 建立缓冲区 private ByteBuffer readBuf = ByteBuffer.allocate(1024); //3 private ByteBuffer writeBuf = ByteBuffer.allocate(1024); public SeverHadler(int port){ this.inetSocketAddress=new InetSocketAddress(port); } @Override public void run() { Charset charset=Charset.forName("UTF-8"); Random rnd=new Random(); try { selector=Selector.open(); ServerSocketChannel serverSocketChannel=ServerSocketChannel.open(); serverSocketChannel.configureBlocking(false); serverSocketChannel.bind(inetSocketAddress); serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); } catch (IOException e) { e.printStackTrace(); } while (!Thread.currentThread().isInterrupted()){ try { int select = selector.select(); if (select==0){ continue; } Set<SelectionKey> keySet=selector.selectedKeys(); Iterator<SelectionKey> iterator = keySet.iterator(); SelectionKey selectionKey=null; while (iterator.hasNext()){ SelectionKey next = iterator.next(); iterator.remove(); if (next.isValid()){ if(next.isAcceptable()){ this.accept(next); } //8 如果为可读状态 if(next.isReadable()){ this.read(next); } //9 写数据 if(next.isWritable()){ //this.write(key); //ssc } } } } catch (IOException e) { e.printStackTrace(); } } } private void write(SelectionKey key){ //ServerSocketChannel ssc = (ServerSocketChannel) key.channel(); //ssc.register(this.seletor, SelectionKey.OP_WRITE); } private void read(SelectionKey key) { try { //1 清空缓冲区旧的数据 this.readBuf.clear(); //2 获取之前注册的socket通道对象 SocketChannel sc = (SocketChannel) key.channel(); //3 读取数据 int count = sc.read(this.readBuf); //4 如果没有数据 if(count == -1){ key.channel().close(); key.cancel(); return; } //5 有数据则进行读取 读取之前需要进行复位方法(把position 和limit进行复位) this.readBuf.flip(); //6 根据缓冲区的数据长度创建相应大小的byte数组,接收缓冲区的数据 byte[] bytes = new byte[this.readBuf.remaining()]; //7 接收缓冲区数据 this.readBuf.get(bytes); //8 打印结果 String body = new String(bytes).trim(); System.out.println("Server : " + body); // 9..可以写回给客户端数据 } catch (IOException e) { e.printStackTrace(); } } private void accept(SelectionKey key) { try { //1 获取服务通道 ServerSocketChannel ssc = (ServerSocketChannel) key.channel(); //2 执行阻塞方法 SocketChannel sc = ssc.accept(); //3 设置阻塞模式 sc.configureBlocking(false); //4 注册到多路复用器上,并设置读取标识 sc.register(this.selector, SelectionKey.OP_READ); } catch (IOException e) { e.printStackTrace(); } }
核心源码:
open时候实际上是返回了一个文件描述
static FileDescriptor socket(boolean var0) throws IOException {
return socket(UNSPEC, var0);
}
static FileDescriptor socket(ProtocolFamily var0, boolean var1) throws IOException {
boolean var2 = isIPv6Available() && var0 != StandardProtocolFamily.INET;
return IOUtil.newFD(socket0(var2, var1, false, fastLoopback));
}
connect时先声明一个读锁一个写锁,解答一个疑惑为什么需要两个锁分别为读和写。可以理解为操作系统里面两辆车过桥的问题,两个车,一个桥,如何让桥两边的车通过。
this.begin();
var9 = this.stateLock;
synchronized(this.stateLock) {
if (!this.isOpen()) {
boolean var10 = false;
return var10; }
if (this.localAddress == null) {
NetHooks.beforeTcpConnect(this.fd, var5.getAddress(), var5.getPort());
}
this.readerThread = NativeThread.current();
}
do {
InetAddress var31 = var5.getAddress();
if (var31.isAnyLocalAddress()) {
var31 = InetAddress.getLocalHost();
}
//用了Net进行连接
var8 = Net.connect(this.fd, var31, var5.getPort());
} while(var8 == -3 && this.isOpen());//循环的
} finally {
this.readerCleanup();
this.end(var8 > 0 || var8 == -2);
assert IOStatus.check(var8);
}
synchronized(this.stateLock) {
if (!this.isOpen()) {
var5 = 0;
var20 = false;
break label310;
}
this.writerThread = NativeThread.current();
}
do {
//IO写入
var3 = IOUtil.write(this.fd, var1, -1L, nd);
} while(var3 == -3 && this.isOpen());
最终调用:
private static int writeFromNativeBuffer(FileDescriptor var0, ByteBuffer var1, long var2, NativeDispatcher var4) throws IOException {
int var5 = var1.position();
int var6 = var1.limit();
assert var5 <= var6;
int var7 = var5 <= var6 ? var6 - var5 : 0;
boolean var8 = false;
if (var7 == 0) {
return 0;
} else {
int var9;
if (var2 != -1L) {
//最终写入
var9 = var4.pwrite(var0, ((DirectBuffer)var1).address() + (long)var5, var7, var2);
} else {
var9 = var4.write(var0, ((DirectBuffer)var1).address() + (long)var5, var7);
}
if (var9 > 0) {
var1.position(var5 + var9);
}
return var9;
}
}