1. 程式人生 > >Java中Socket如何獲得輸入流

Java中Socket如何獲得輸入流

Socket類是java語言建立網路連線的核心類,通過對指定地址和埠的訪問,獲得資源的輸入流。本文通過對原始碼分析,簡單介紹Socket類的實現。

Java version jdk1.8.0_121
package java.net
        Class Socket
public InputStream getInputStream() throws IOException {
        if (isClosed())
            throw new SocketException("Socket is closed");
        if (!isConnected
()) throw new SocketException("Socket is not connected"); if (isInputShutdown()) throw new SocketException("Socket input is shutdown"); final Socket s = this; InputStream is = null; try { is = AccessController.doPrivileged( new
PrivilegedExceptionAction<InputStream>() { public InputStream run() throws IOException { return impl.getInputStream(); } }); } catch (java.security.PrivilegedActionException e) { throw (IOException)
e.getException(); } return is; }
	核心程式碼如下:
		public InputStream run() throws IOException {
                    return impl.getInputStream();
                }
    那麼impl是什麼,又是如何實現的?
 SocketImpl impl;

 void setImpl() {
        if (factory != null) {
            impl = factory.createSocketImpl();
            checkOldImpl();
        } else {
            // No need to do a checkOldImpl() here, we know it's an up to date
            // SocketImpl!
            impl = new SocksSocketImpl();
        }
        if (impl != null)
            impl.setSocket(this);
    }
SocksSocketImpl類例項化一個PlainSocketImpl類,並獲得其中的輸入流
Class SocksSocketImpl如下:
try {
      AccessController.doPrivileged(
         new PrivilegedExceptionAction<Void>() {
             public Void run() throws Exception {
                    cmdsock = new Socket(new PlainSocketImpl());
                    cmdsock.connect(new InetSocketAddress(server, serverPort));
                    cmdIn = cmdsock.getInputStream();
                    cmdOut = cmdsock.getOutputStream();
                    return null;
                            }
                        });
                } 
Class PlainSocketImpl
class PlainSocketImpl extends AbstractPlainSocketImpl
{
    private AbstractPlainSocketImpl impl;

    PlainSocketImpl() {
        if (useDualStackImpl) {
            impl = new DualStackPlainSocketImpl(exclusiveBind);
        } else {
            impl = new TwoStacksPlainSocketImpl(exclusiveBind);
        }
    }

    protected synchronized InputStream getInputStream() throws IOException {
        return impl.getInputStream();
    }
}
PlainSocketImpl類、DualStackPlainSocketImpl類和TwoStacksPlainSocketImpl類都是AbstractPlainSocketImpl的子類,其中DualStackPlainSocketImpl類和TwoStacksPlainSocketImpl類中都沒有getInputStream方法,因此這三個類的getInputStream方法全部繼承於AbstractPlainSocketImpl類。

Class AbstractPlainSocketImpl
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;
    }
getInputStream方法例項化一個SocketInputStream並返回該輸入流引用。

Class SocketInputStream
SocketInputStream(AbstractPlainSocketImpl impl) throws IOException {
        super(impl.getFileDescriptor());
        this.impl = impl;
        socket = impl.getSocket();
    }
AbstractPlainSocketImpl類中沒有getSocket方法,只有子類PlainSocketImpl中有該方法。
    Socket getSocket() {
        return impl.getSocket();
    }