Socket 类表示通信双方中的客户端,用于呼叫远端机器上的一个端口,主动向服务器端发送数据(当连接建立后也能接收数据)。下面我将从源码的角度来介绍Socket类的内部原理及其方法。
二、Socket类源码介绍首先,Socket类实现了java.io.Closeable的接口
public class Socket implements java.io.Closeable { }
下面定义了一些Socket的一些状态
private boolean created = false; private boolean bound = false; private boolean connected = false; private boolean closed = false; private Object closeLock = new Object(); private boolean shutIn = false; private boolean shutOut = false;
Socket 的实现
SocketImpl impl;
确定是否使用旧的 Socket
private boolean oldImpl = false;
创建一个未连接的Socket
public Socket() { setImpl(); }
Socket 的实现类,通过Proxy代理实现
public Socket(Proxy proxy) { // Create a copy of Proxy as a security measure if (proxy == null) { throw new IllegalArgumentException("Invalid Proxy"); } Proxy p = proxy == Proxy.NO_PROXY ? Proxy.NO_PROXY : sun.net.ApplicationProxy.create(proxy); Proxy.Type type = p.type(); if (type == Proxy.Type.SOCKS || type == Proxy.Type.HTTP) { SecurityManager security = System.getSecurityManager(); InetSocketAddress epoint = (InetSocketAddress) p.address(); if (epoint.getAddress() != null) { checkAddress (epoint.getAddress(), "Socket"); } if (security != null) { if (epoint.isUnresolved()) epoint = new InetSocketAddress(epoint.getHostName(), epoint.getPort()); if (epoint.isUnresolved()) security.checkConnect(epoint.getHostName(), epoint.getPort()); else security.checkConnect(epoint.getAddress().getHostAddress(), epoint.getPort()); } impl = type == Proxy.Type.SOCKS ? new SocksSocketImpl(p) : new HttpConnectSocketImpl(p); impl.setSocket(this); } else { if (p == Proxy.NO_PROXY) { if (factory == null) { impl = new PlainSocketImpl(); impl.setSocket(this); } else setImpl(); } else throw new IllegalArgumentException("Invalid Proxy"); } }
使用用户指定的 SocketImpl 创建一个未连接的 Socket。
protected Socket(SocketImpl impl) throws SocketException { this.impl = impl; if (impl != null) { checkOldImpl(); this.impl.setSocket(this); } }
Socket使用代理器和端口号篇port
public Socket(String host, int port) throws UnknownHostException, IOException { this(host != null ? new InetSocketAddress(host, port) : new InetSocketAddress(InetAddress.getByName(null), port), (SocketAddress) null, true); }
利用网络地址和端口号创建Socket
public Socket(InetAddress address, int port) throws IOException { this(address != null ? new InetSocketAddress(address, port) : null, (SocketAddress) null, true); }
创建本地和联网的Socket
public Socket(String host, int port, InetAddress localAddr, int localPort) throws IOException { this(host != null ? new InetSocketAddress(host, port) : new InetSocketAddress(InetAddress.getByName(null), port), new InetSocketAddress(localAddr, localPort), true); } public Socket(InetAddress address, int port, InetAddress localAddr, int localPort) throws IOException { this(address != null ? new InetSocketAddress(address, port) : null, new InetSocketAddress(localAddr, localPort), true); }
定义实现本地连接和本地数据流
private Socket(SocketAddress address, SocketAddress localAddr, boolean stream) throws IOException { setImpl(); // backward compatibility if (address == null) throw new NullPointerException(); try { createImpl(stream); if (localAddr != null) bind(localAddr); connect(address); } catch (IOException | IllegalArgumentException | SecurityException e) { try { close(); } catch (IOException ce) { e.addSuppressed(ce); } throw e; } }
创建套接字实现。
void createImpl(boolean stream) throws SocketException { if (impl == null) setImpl(); try { impl.create(stream); created = true; } catch (IOException e) { throw new SocketException(e.getMessage()); } }
检查旧的嵌套字
private void checkOldImpl() { if (impl == null) return; // SocketImpl.connect() is a protected method, therefore we need to use // getDeclaredMethod, therefore we need permission to access the member oldImpl = AccessController.doPrivileged (new PrivilegedAction() { public Boolean run() { Class> clazz = impl.getClass(); while (true) { try { clazz.getDeclaredMethod("connect", SocketAddress.class, int.class); return Boolean.FALSE; } catch (NoSuchMethodException e) { clazz = clazz.getSuperclass(); // java.net.SocketImpl class will always have this abstract method. // If we have not found it by now in the hierarchy then it does not // exist, we are an old style impl. if (clazz.equals(java.net.SocketImpl.class)) { return Boolean.TRUE; } } } } }); }
设置网络嵌套字
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); }
获取网络嵌套字
SocketImpl getImpl() throws SocketException { if (!created) createImpl(true); return impl; }
定义连接服务端
public void connect(SocketAddress endpoint) throws IOException { connect(endpoint, 0); }
定义连接并设置有超时时间
public void connect(SocketAddress endpoint, int timeout) throws IOException { if (endpoint == null) throw new IllegalArgumentException("connect: The address can't be null"); if (timeout < 0) throw new IllegalArgumentException("connect: timeout can't be negative"); if (isClosed()) throw new SocketException("Socket is closed"); if (!oldImpl && isConnected()) throw new SocketException("already connected"); if (!(endpoint instanceof InetSocketAddress)) throw new IllegalArgumentException("Unsupported address type"); InetSocketAddress epoint = (InetSocketAddress) endpoint; InetAddress addr = epoint.getAddress (); int port = epoint.getPort(); checkAddress(addr, "connect"); SecurityManager security = System.getSecurityManager(); if (security != null) { if (epoint.isUnresolved()) security.checkConnect(epoint.getHostName(), port); else security.checkConnect(addr.getHostAddress(), port); } if (!created) createImpl(true); if (!oldImpl) impl.connect(epoint, timeout); else if (timeout == 0) { if (epoint.isUnresolved()) impl.connect(addr.getHostName(), port); else impl.connect(addr, port); } else throw new UnsupportedOperationException("SocketImpl.connect(addr, timeout)"); connected = true; bound = true; }
将嵌套字绑定本地
public void bind(SocketAddress bindpoint) throws IOException { if (isClosed()) throw new SocketException("Socket is closed"); if (!oldImpl && isBound()) throw new SocketException("Already bound"); if (bindpoint != null && (!(bindpoint instanceof InetSocketAddress))) throw new IllegalArgumentException("Unsupported address type"); InetSocketAddress epoint = (InetSocketAddress) bindpoint; if (epoint != null && epoint.isUnresolved()) throw new SocketException("Unresolved address"); if (epoint == null) { epoint = new InetSocketAddress(0); } InetAddress addr = epoint.getAddress(); int port = epoint.getPort(); checkAddress (addr, "bind"); SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkListen(port); } getImpl().bind (addr, port); bound = true; }
检查地址
private void checkAddress (InetAddress addr, String op) { if (addr == null) { return; } if (!(addr instanceof Inet4Address || addr instanceof Inet6Address)) { throw new IllegalArgumentException(op + ": invalid address type"); } }
定义接受请求
final void postAccept() { connected = true; created = true; bound = true; }
下面定义实现状态设置
void setCreated() { created = true; } void setBound() { bound = true; } void setConnected() { connected = true; }
获取网络地址
public InetAddress getInetAddress() { if (!isConnected()) return null; try { return getImpl().getInetAddress(); } catch (SocketException e) { } return null; }
获取本地地址
public InetAddress getLocalAddress() { // This is for backward compatibility if (!isBound()) return InetAddress.anyLocalAddress(); InetAddress in = null; try { in = (InetAddress) getImpl().getOption(SocketOptions.SO_BINDADDR); SecurityManager sm = System.getSecurityManager(); if (sm != null) sm.checkConnect(in.getHostAddress(), -1); if (in.isAnyLocalAddress()) { in = InetAddress.anyLocalAddress(); } } catch (SecurityException e) { in = InetAddress.getLoopbackAddress(); } catch (Exception e) { in = InetAddress.anyLocalAddress(); // "0.0.0.0" } return in; }
返回此套接字连接到的远程端口号。
public int getPort() { if (!isConnected()) return 0; try { return getImpl().getPort(); } catch (SocketException e) { // Shouldn't happen as we're connected } return -1; }
获取本地端口号
public int getLocalPort() { if (!isBound()) return -1; try { return getImpl().getLocalPort(); } catch(SocketException e) { // shouldn't happen as we're bound } return -1; }
获取远程嵌套字地址
public SocketAddress getRemoteSocketAddress() { if (!isConnected()) return null; return new InetSocketAddress(getInetAddress(), getPort()); }
获取本地嵌套字地址
public SocketAddress getLocalSocketAddress() { if (!isBound()) return null; return new InetSocketAddress(getLocalAddress(), getLocalPort()); }
获取嵌套字的传输管道
public SocketChannel getChannel() { return null; }
获取输入流函数
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() { public InputStream run() throws IOException { return impl.getInputStream(); } }); } catch (java.security.PrivilegedActionException e) { throw (IOException) e.getException(); } return is; }
获取输出流函数
public OutputStream getOutputStream() throws IOException { if (isClosed()) throw new SocketException("Socket is closed"); if (!isConnected()) throw new SocketException("Socket is not connected"); if (isOutputShutdown()) throw new SocketException("Socket output is shutdown"); final Socket s = this; OutputStream os = null; try { os = AccessController.doPrivileged( new PrivilegedExceptionAction() { public OutputStream run() throws IOException { return impl.getOutputStream(); } }); } catch (java.security.PrivilegedActionException e) { throw (IOException) e.getException(); } return os; }
设置无延时TCP传输
public void setTcpNoDelay(boolean on) throws SocketException { if (isClosed()) throw new SocketException("Socket is closed"); getImpl().setOption(SocketOptions.TCP_NODELAY, Boolean.valueOf(on)); }
获取TCP无延时服务
public boolean getTcpNoDelay() throws SocketException { if (isClosed()) throw new SocketException("Socket is closed"); return ((Boolean) getImpl().getOption(SocketOptions.TCP_NODELAY)).booleanValue(); }
设置延时等待
public void setSoLinger(boolean on, int linger) throws SocketException { if (isClosed()) throw new SocketException("Socket is closed"); if (!on) { getImpl().setOption(SocketOptions.SO_LINGER, new Boolean(on)); } else { if (linger < 0) { throw new IllegalArgumentException("invalid value for SO_LINGER"); } if (linger > 65535) linger = 65535; getImpl().setOption(SocketOptions.SO_LINGER, new Integer(linger)); } }
获取延时等待
public int getSoLinger() throws SocketException { if (isClosed()) throw new SocketException("Socket is closed"); Object o = getImpl().getOption(SocketOptions.SO_LINGER); if (o instanceof Integer) { return ((Integer) o).intValue(); } else { return -1; } }
发送紧急信息
public void sendUrgentData (int data) throws IOException { if (!getImpl().supportsUrgentData ()) { throw new SocketException ("Urgent data not supported"); } getImpl().sendUrgentData (data); }
设置OOB内联
public void setOOBInline(boolean on) throws SocketException { if (isClosed()) throw new SocketException("Socket is closed"); getImpl().setOption(SocketOptions.SO_OOBINLINE, Boolean.valueOf(on)); }
获取OOB(面向对象)内联
public boolean getOOBInline() throws SocketException { if (isClosed()) throw new SocketException("Socket is closed"); return ((Boolean) getImpl().getOption(SocketOptions.SO_OOBINLINE)).booleanValue(); }
设置超时时间
public synchronized void setSoTimeout(int timeout) throws SocketException { if (isClosed()) throw new SocketException("Socket is closed"); if (timeout < 0) throw new IllegalArgumentException("timeout can't be negative"); getImpl().setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout)); }
获取超时时间
public synchronized int getSoTimeout() throws SocketException { if (isClosed()) throw new SocketException("Socket is closed"); Object o = getImpl().getOption(SocketOptions.SO_TIMEOUT); if (o instanceof Integer) { return ((Integer) o).intValue(); } else { return 0; } }
设置发送缓冲区大小
public synchronized void setSendBufferSize(int size) throws SocketException{ if (!(size > 0)) { throw new IllegalArgumentException("negative send size"); } if (isClosed()) throw new SocketException("Socket is closed"); getImpl().setOption(SocketOptions.SO_SNDBUF, new Integer(size)); }
获取发送缓冲区大小
public synchronized int getSendBufferSize() throws SocketException { if (isClosed()) throw new SocketException("Socket is closed"); int result = 0; Object o = getImpl().getOption(SocketOptions.SO_SNDBUF); if (o instanceof Integer) { result = ((Integer)o).intValue(); } return result; }
设置获取缓冲区的大小
public synchronized void setReceiveBufferSize(int size) throws SocketException{ if (size <= 0) { throw new IllegalArgumentException("invalid receive size"); } if (isClosed()) throw new SocketException("Socket is closed"); getImpl().setOption(SocketOptions.SO_RCVBUF, new Integer(size)); }
获取获取缓冲区大小
public synchronized int getReceiveBufferSize() throws SocketException{ if (isClosed()) throw new SocketException("Socket is closed"); int result = 0; Object o = getImpl().getOption(SocketOptions.SO_RCVBUF); if (o instanceof Integer) { result = ((Integer)o).intValue(); } return result; }
设置保持存活函数
public void setKeepAlive(boolean on) throws SocketException { if (isClosed()) throw new SocketException("Socket is closed"); getImpl().setOption(SocketOptions.SO_KEEPALIVE, Boolean.valueOf(on)); }
获取保持存活函数
public boolean getKeepAlive() throws SocketException { if (isClosed()) throw new SocketException("Socket is closed"); return ((Boolean) getImpl().getOption(SocketOptions.SO_KEEPALIVE)).booleanValue(); }
设置Socket传输通道大小
public void setTrafficClass(int tc) throws SocketException { if (tc < 0 || tc > 255) throw new IllegalArgumentException("tc is not in range 0 -- 255"); if (isClosed()) throw new SocketException("Socket is closed"); try { getImpl().setOption(SocketOptions.IP_TOS, tc); } catch (SocketException se) { // not supported if socket already connected // Solaris returns error in such cases if(!isConnected()) throw se; } }
获取Socket传输通道大小
public int getTrafficClass() throws SocketException { return ((Integer) (getImpl().getOption(SocketOptions.IP_TOS))).intValue(); }
定义设置重用地址方法
public void setReuseAddress(boolean on) throws SocketException { if (isClosed()) throw new SocketException("Socket is closed"); getImpl().setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(on)); }
定义获取重用方法
public boolean getReuseAddress() throws SocketException { if (isClosed()) throw new SocketException("Socket is closed"); return ((Boolean) (getImpl().getOption(SocketOptions.SO_REUSEADDR))).booleanValue(); }
定义Socket类的关闭
public synchronized void close() throws IOException { synchronized(closeLock) { if (isClosed()) return; if (created) impl.close(); closed = true; } }
这个方法应放置于文件末尾,用于关闭嵌套字的输入
public void shutdownInput() 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 already shutdown"); getImpl().shutdownInput(); shutIn = true; }
这个方法应放置于文件末尾,用于关闭嵌套字的输出
public void shutdownOutput() throws IOException { if (isClosed()) throw new SocketException("Socket is closed"); if (!isConnected()) throw new SocketException("Socket is not connected"); if (isOutputShutdown()) throw new SocketException("Socket output is already shutdown"); getImpl().shutdownOutput(); shutOut = true; }
将Socket信息转化为字符串
public String toString() { try { if (isConnected()) return "Socket[addr=" + getImpl().getInetAddress() + ",port=" + getImpl().getPort() + ",localport=" + getImpl().getLocalPort() + "]"; } catch (SocketException e) { } return "Socket[unconnected]"; }
判断是否处于连接状态
public boolean isConnected() { // Before 1.3 Sockets were always connected during creation return connected || oldImpl; }
判断是否处于绑定状态
public boolean isBound() { // Before 1.3 Sockets were always bound during creation return bound || oldImpl; }
判断是否关闭状态
public boolean isClosed() { synchronized(closeLock) { return closed; } }
判断是否是输入关闭状态
public boolean isInputShutdown() { return shutIn; }
判断是否是输出关闭状态
public boolean isOutputShutdown() { return shutOut; }
定义所有客户端套接字的工厂
private static SocketImplFactory factory = null;
定义设置所有客户端套接字的工厂
public static synchronized void setSocketImplFactory(SocketImplFactory fac) throws IOException { if (factory != null) { throw new SocketException("factory already defined"); } SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkSetFactory(); } factory = fac; }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)