Java Socket, DatagramSocket, ServerSocketChannel io代码跟踪
Java Socket, DatagramSocket, ServerSocketChannel这三个分别对应了,TCP, udp, NIO通信API封装。JDK封装了,想跟下代码,看下具体最后是怎么实现的。
都是通过native方法实现的。
下面是具体代码的跟进
1. Socket
Socket clientSocket = serverSocket.accept();
InputStream is = clientSocket.getInputStream();
byte buff[] = new byte[1024];
length = is.read(buff);
上面的代码片段是从Socket读取数据的代码。跟进clientSocket.getInputStream()
/** * Gets an InputStream for this socket. */ protected synchronized InputStream getInputStream() throws IOException { synchronized (fdLock) { if (isClosedOrPending()) throw new IOException("Socket Closed"); if (shut_rd) throw new IOException("Socket input is shutdown"); if (socketInputStream == null) socketInputStream = new SocketInputStream(this); } return socketInputStream; }
这里拿到的是SocketInputStream对象,跟进SocketInputStream.read(byte[] buf)
/** * Reads into a byte array data from the socket. * @param b the buffer into which the data is read * @return the actual number of bytes read, -1 is * returned when the end of the stream is reached. * @exception IOException If an I/O error has occurred. */ public int read(byte b[]) throws IOException { return read(b, 0, b.length); }
继续跟进
/** * Reads into a byte array <i>b</i> at offset <i>off</i>, * <i>length</i> bytes of data. * @param b the buffer into which the data is read * @param off the start offset of the data * @param length the maximum number of bytes read * @return the actual number of bytes read, -1 is * returned when the end of the stream is reached. * @exception IOException If an I/O error has occurred. */ public int read(byte b[], int off, int length) throws IOException { return read(b, off, length, impl.getTimeout()); }
继续跟进
int read(byte b[], int off, int length, int timeout) throws IOException { int n; // EOF already encountered if (eof) { return -1; } // connection reset if (impl.isConnectionReset()) { throw new SocketException("Connection reset"); } // bounds check if (length <= 0 || off < 0 || length > b.length - off) { if (length == 0) { return 0; } throw new ArrayIndexOutOfBoundsException("length == " + length + " off == " + off + " buffer length == " + b.length); } boolean gotReset = false; // acquire file descriptor and do the read FileDescriptor fd = impl.acquireFD(); try { n = socketRead(fd, b, off, length, timeout); if (n > 0) { return n; } } catch (ConnectionResetException rstExc) { gotReset = true; } finally { impl.releaseFD(); } /* * We receive a "connection reset" but there may be bytes still * buffered on the socket */ if (gotReset) { impl.setConnectionResetPending(); impl.acquireFD(); try { n = socketRead(fd, b, off, length, timeout); if (n > 0) { return n; } } catch (ConnectionResetException rstExc) { } finally { impl.releaseFD(); } } /* * If we get here we are at EOF, the socket has been closed, * or the connection has been reset. */ if (impl.isClosedOrPending()) { throw new SocketException("Socket closed"); } if (impl.isConnectionResetPending()) { impl.setConnectionReset(); } if (impl.isConnectionReset()) { throw new SocketException("Connection reset"); } eof = true; return -1; }
socketRead(fd, b, off, length, timeout);跟进
private int socketRead(FileDescriptor fd, byte b[], int off, int len, int timeout) throws IOException { return socketRead0(fd, b, off, len, timeout); }
继续跟进
private native int socketRead0(FileDescriptor fd, byte b[], int off, int len, int timeout)
2. DatagramSocket
clientSocket = new DatagramSocket(); packetToSend = new DatagramPacket(buff, buff.length, InetAddress.getByName("127.0.0.1"), 10002); clientSocket.send(packetToSend); //发送数据包
跟进send()
public void send(DatagramPacket p) throws IOException { InetAddress packetAddress = null; synchronized (p) { if (isClosed()) throw new SocketException("Socket is closed"); checkAddress (p.getAddress(), "send"); if (connectState == ST_NOT_CONNECTED) { // check the address is ok wiht the security manager on every send. SecurityManager security = System.getSecurityManager(); // The reason you want to synchronize on datagram packet // is because you don't want an applet to change the address // while you are trying to send the packet for example // after the security check but before the send. if (security != null) { if (p.getAddress().isMulticastAddress()) { security.checkMulticast(p.getAddress()); } else { security.checkConnect(p.getAddress().getHostAddress(), p.getPort()); } } } else { // we're connected packetAddress = p.getAddress(); if (packetAddress == null) { p.setAddress(connectedAddress); p.setPort(connectedPort); } else if ((!packetAddress.equals(connectedAddress)) || p.getPort() != connectedPort) { throw new IllegalArgumentException("connected address " + "and packet address" + " differ"); } } // Check whether the socket is bound if (!isBound()) bind(new InetSocketAddress(0)); // call the method to send getImpl().send(p); }
继续
protected native void send(DatagramPacket p) throws IOException;
这里最后调用native方法
3.ServerSocketChannel
SocketChannel client = server.accept(); ByteBuffer buffer = ByteBuffer.allocate(1024); client.read(buffer);
继续
public abstract int read(ByteBuffer dst) throws IOException;
继续
public int read(ByteBuffer var1) throws IOException { if (var1 == null) { throw new NullPointerException(); } else { Object var2 = this.readLock; synchronized(this.readLock) { if (!this.ensureReadOpen()) { return -1; } else { int var3 = 0; boolean var20 = false; byte var10000; byte var5; label356: { int var27; try { var20 = true; this.begin(); Object var4 = this.stateLock; synchronized(this.stateLock) { if (!this.isOpen()) { var5 = 0; var20 = false; break label356; } this.readerThread = NativeThread.current(); } while(true) { var3 = IOUtil.read(this.fd, var1, -1L, nd); if (var3 != -3 || !this.isOpen()) { var27 = IOStatus.normalize(var3); var20 = false; break; } } } finally { if (var20) { label271: { this.readerCleanup(); this.end(var3 > 0 || var3 == -2); Object var11 = this.stateLock; synchronized(this.stateLock) { if (var3 > 0 || this.isInputOpen) { break label271; } var10000 = -1; } return var10000; } assert IOStatus.check(var3); } } label303: { this.readerCleanup(); this.end(var3 > 0 || var3 == -2); Object var28 = this.stateLock; synchronized(this.stateLock) { if (var3 > 0 || this.isInputOpen) { break label303; } var10000 = -1; } return var10000; } assert IOStatus.check(var3); return var27; } this.readerCleanup(); this.end(var3 > 0 || var3 == -2); Object var6 = this.stateLock; synchronized(this.stateLock) { if (var3 <= 0 && !this.isInputOpen) { var10000 = -1; return var10000; } } assert IOStatus.check(var3); return var5; } } } }
继续
static int read(FileDescriptor var0, ByteBuffer var1, long var2, NativeDispatcher var4) throws IOException { if (var1.isReadOnly()) { throw new IllegalArgumentException("Read-only buffer"); } else if (var1 instanceof DirectBuffer) { return readIntoNativeBuffer(var0, var1, var2, var4); } else { ByteBuffer var5 = Util.getTemporaryDirectBuffer(var1.remaining()); int var7; try { int var6 = readIntoNativeBuffer(var0, var5, var2, var4); var5.flip(); if (var6 > 0) { var1.put(var5); } var7 = var6; } finally { Util.offerFirstTemporaryDirectBuffer(var5); } return var7; } }
继续
private static int readIntoNativeBuffer(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; if (var7 == 0) { return 0; } else { boolean var8 = false; int var9; if (var2 != -1L) { var9 = var4.pread(var0, ((DirectBuffer)var1).address() + (long)var5, var7, var2); } else { var9 = var4.read(var0, ((DirectBuffer)var1).address() + (long)var5, var7); } if (var9 > 0) { var1.position(var5 + var9); } return var9; } }
继续
int read(FileDescriptor var1, long var2, int var4) throws IOException { return FileDispatcherImpl.read0(var1, var2, var4); }
继续
static native int read0(FileDescriptor var0, long var1, int var3) throws IOException;
最后都是native方法
JVM是c++. c实现的,最后调用的应该是c/c++的方法
Please call me JiangYouDang!