Java中Socket如何獲得輸入流
阿新 • • 發佈:2018-12-17
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();
}