该类继承自SocketImpl类
该类引入了如下包:
import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.FileDescriptor; import sun.net.ConnectionResetException; import sun.net.NetHooks; import sun.net.ResourceManager;
该类的类头注释如下:
/** * Default Socket Implementation. This implementation does * not implement any security checks. * Note this class should <b>NOT</b> be public. * * @author Steven B. Byrne */
大意如下:
默认的套接字实现方式
该实现方式不执行一些安全检查
该类非public类
该类含有如下的成员变量:
超时时间
int timeout;
IP服务类型
private int trafficClass;
中止读取信号
private boolean shut_rd = false;
中止写入信号
private boolean shut_wr = false;
套接字输入流
private SocketInputStream socketInputStream = null;
套接字输出流
private SocketOutputStream socketOutputStream = null;
使用文件描述符的线程数
protected int fdUseCount = 0;
文件描述符控制锁
protected final Object fdLock = new Object();
文件描述符的关闭状态
protected boolean closePending = false;
连接状态指示
private int CONNECTION_NOT_RESET = 0; private int CONNECTION_RESET_PENDING = 1; private int CONNECTION_RESET = 2;
针对上述种类的状态记录
private int resetState;
重置锁
private final Object resetLock = new Object();
判定是TCP还是UDP(true是TCP,false是UDP;不过不是很清楚为啥要叫字段stream……)
protected boolean stream;
常量声明
public final static int SHUT_RD = 0; public final static int SHUT_WR = 1;
该类含有如下的成员方法:
构造函数(同步的构造函数,需要运输层传送方法)
protected synchronized void create(boolean stream) throws IOException { this.stream = stream; if (!stream) {//为UDP ResourceManager.beforeUdpCreate(); // only create the fd after we know we will be able to create the socket fd = new FileDescriptor(); try { socketCreate(false);//创建UDP的Socket } catch (IOException ioe) { ResourceManager.afterUdpClose(); fd = null; throw ioe; } } else {//创建TCP fd = new FileDescriptor(); socketCreate(true); } if (socket != null) socket.setCreated();//父类包含的Socket变量 if (serverSocket != null) serverSocket.setCreated();//父类包含的ServerSocket }
创建连接(目标主机名和目的端口
protected void connect(String host, int port) throws UnknownHostException, IOException { boolean connected = false; try { InetAddress address = InetAddress.getByName(host);//DNS获得主机地址 this.port = port; this.address = address; connectToAddress(address, port, timeout);//创建连接 connected = true; } finally { if (!connected) {//连接失败 try { close();//关闭Socket } catch (IOException ioe) { /* Do nothing. If connect threw an exception then it will be passed up the call stack */ } } } }
创建连接(主机地址和端口
protected void connect(InetAddress address, int port) throws IOException { this.port = port; this.address = address; try { connectToAddress(address, port, timeout); return; } catch (IOException e) { // everything failed close(); throw e; } }
创建连接(一个完成SockAddress接口的(主机地址),和连接时限)
protected void connect(SocketAddress address, int timeout) throws IOException { boolean connected = false; try { if (address == null || !(address instanceof InetSocketAddress))//不是实际地址就炸 throw new IllegalArgumentException("unsupported address type"); InetSocketAddress addr = (InetSocketAddress) address; if (addr.isUnresolved()) throw new UnknownHostException(addr.getHostName()); this.port = addr.getPort(); this.address = addr.getAddress(); connectToAddress(this.address, port, timeout); connected = true; } finally { if (!connected) { try { close(); } catch (IOException ioe) { /* Do nothing. If connect threw an exception then it will be passed up the call stack */ } } } }
创建连接(上面一个的进化版,多了时限
private void connectToAddress(InetAddress address, int port, int timeout) throws IOException { if (address.isAnyLocalAddress()) {//判定是不是本地地址 doConnect(InetAddress.getLocalHost(), port, timeout); } else { doConnect(address, port, timeout); } }
网络连接权限(根据具体的操作号,后面对应的实体种类不同),该方法只是整合参数,具体设置在SocketSetOption里
public void setOption(int opt, Object val) throws SocketException { if (isClosedOrPending()) {//判定当前套接字状态 throw new SocketException("Socket Closed"); } boolean on = true; switch (opt) {//根据操作权限码选择 /* check type safety b4 going native. These should never * fail, since only java.Socket* has access to * PlainSocketImpl.setOption(). */ case SO_LINGER: if (val == null || (!(val instanceof Integer) && !(val instanceof Boolean))) throw new SocketException("Bad parameter for option"); if (val instanceof Boolean) { /* true only if disabling - enabling should be Integer */ on = false; } break; case SO_TIMEOUT://设置超时时限 if (val == null || (!(val instanceof Integer))) throw new SocketException("Bad parameter for SO_TIMEOUT"); int tmp = ((Integer) val).intValue(); if (tmp < 0) throw new IllegalArgumentException("timeout < 0"); timeout = tmp; break; case IP_TOS://设置IP头控制字段(type of service if (val == null || !(val instanceof Integer)) { throw new SocketException("bad argument for IP_TOS"); } trafficClass = ((Integer)val).intValue();//设置控制字段 break; case SO_BINDADDR://绑定地址 throw new SocketException("Cannot re-bind socket"); case TCP_NODELAY://TCP 无延迟发包 if (val == null || !(val instanceof Boolean)) throw new SocketException("bad parameter for TCP_NODELAY"); on = ((Boolean)val).booleanValue(); break; case SO_SNDBUF: case SO_RCVBUF://设置发送和接收缓冲大小 if (val == null || !(val instanceof Integer) || !(((Integer)val).intValue() > 0)) { throw new SocketException("bad parameter for SO_SNDBUF " + "or SO_RCVBUF"); } break; case SO_KEEPALIVE://链接保持 if (val == null || !(val instanceof Boolean)) throw new SocketException("bad parameter for SO_KEEPALIVE"); on = ((Boolean)val).booleanValue(); break; case SO_OOBINLINE: if (val == null || !(val instanceof Boolean)) throw new SocketException("bad parameter for SO_OOBINLINE"); on = ((Boolean)val).booleanValue(); break; case SO_REUSEADDR://重定位地址 if (val == null || !(val instanceof Boolean)) throw new SocketException("bad parameter for SO_REUSEADDR"); on = ((Boolean)val).booleanValue(); break; default: throw new SocketException("unrecognized TCP option: " + opt); } socketSetOption(opt, on, val); }
获得具体操作设置字段的值(逻辑基本和上一个方法一样
public Object getOption(int opt) throws SocketException { if (isClosedOrPending()) { throw new SocketException("Socket Closed"); } if (opt == SO_TIMEOUT) { return new Integer(timeout); } int ret = 0; /* * The native socketGetOption() knows about 3 options. * The 32 bit value it returns will be interpreted according * to what we're asking. A return of -1 means it understands * the option but its turned off. It will raise a SocketException * if "opt" isn't one it understands. */ switch (opt) { case TCP_NODELAY: ret = socketGetOption(opt, null); return Boolean.valueOf(ret != -1); case SO_OOBINLINE: ret = socketGetOption(opt, null); return Boolean.valueOf(ret != -1); case SO_LINGER: ret = socketGetOption(opt, null); return (ret == -1) ? Boolean.FALSE: (Object)(new Integer(ret)); case SO_REUSEADDR: ret = socketGetOption(opt, null); return Boolean.valueOf(ret != -1); case SO_BINDADDR: InetAddressContainer in = new InetAddressContainer(); ret = socketGetOption(opt, in); return in.addr; case SO_SNDBUF: case SO_RCVBUF: ret = socketGetOption(opt, null); return new Integer(ret); case IP_TOS: try { ret = socketGetOption(opt, null); if (ret == -1) { // ipv6 tos return trafficClass; } else { return ret; } } catch (SocketException se) { // TODO - should make better effort to read TOS or TCLASS return trafficClass; // ipv6 tos } case SO_KEEPALIVE: ret = socketGetOption(opt, null); return Boolean.valueOf(ret != -1); // should never get here default: return null; } }
同步进行TCP链接
synchronized void doConnect(InetAddress address, int port, int timeout) throws IOException { synchronized (fdLock) { if (!closePending && (socket == null || !socket.isBound())) { NetHooks.beforeTcpConnect(fd, address, port);//建立TCP } } try { acquireFD();//获得当前套接字的描述符 try { socketConnect(address, port, timeout); /* socket may have been closed during poll/select */ synchronized (fdLock) { if (closePending) { throw new SocketException ("Socket closed"); } } // If we have a ref. to the Socket, then sets the flags // created, bound & connected to true. // This is normally done in Socket.connect() but some // subclasses of Socket may call impl.connect() directly! if (socket != null) { socket.setBound(); socket.setConnected(); } } finally { releaseFD();//归还文件描述符的使用权 } } catch (IOException e) { close(); throw e; } }
对某个端口监听(参数是时间)
protected synchronized void listen(int count) throws IOException { socketListen(count); }
接收某个连接请求(来自Scoket实例
protected void accept(SocketImpl s) throws IOException { acquireFD(); try { socketAccept(s); } finally { releaseFD(); } }
获得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; }
设置数据输入流为特定输入流
void setInputStream(SocketInputStream in) { socketInputStream = in; }
获得套接字输出流(就是发送给链接方的数据
protected synchronized OutputStream getOutputStream() throws IOException { synchronized (fdLock) { if (isClosedOrPending()) throw new IOException("Socket Closed"); if (shut_wr) throw new IOException("Socket output is shutdown"); if (socketOutputStream == null) socketOutputStream = new SocketOutputStream(this); } return socketOutputStream; }
设置当前的所操作的Socket(实质Socket和文件描述符绑定
void setFileDescriptor(FileDescriptor fd) { this.fd = fd; }
设置目的主机地址
void setAddress(InetAddress address) { this.address = address; }
设置目的端口
void setPort(int port) { this.port = port; }
设置本地监听端口
void setLocalPort(int localport) { this.localport = localport; }
返回当前Socket链接的有效性
protected synchronized int available() throws IOException { if (isClosedOrPending()) { throw new IOException("Stream closed."); } /* * If connection has been reset or shut down for input, then return 0 * to indicate there are no buffered bytes. */ if (isConnectionReset() || shut_rd) { return 0; } /* * If no bytes available and we were previously notified * of a connection reset then we move to the reset state. * * If are notified of a connection reset then check * again if there are bytes buffered on the socket. */ int n = 0; try { n = socketAvailable();//当前无效 if (n == 0 && isConnectionResetPending()) {//重新设置链接 setConnectionReset(); } } catch (ConnectionResetException exc1) { setConnectionResetPending();//设置成预备重设状态 try { n = socketAvailable();//再次尝试获得有效性 if (n == 0) {//如果仍然无效就再次重设 setConnectionReset(); } } catch (ConnectionResetException exc2) { } } return n; }
关闭链接
protected void close() throws IOException { synchronized(fdLock) { if (fd != null) { if (!stream) { ResourceManager.afterUdpClose(); } if (fdUseCount == 0) { if (closePending) { return; } closePending = true; /* * We close the FileDescriptor in two-steps - first the * "pre-close" which closes the socket but doesn't * release the underlying file descriptor. This operation * may be lengthy due to untransmitted data and a long * linger interval. Once the pre-close is done we do the * actual socket to release the fd. */ try { socketPreClose(); } finally { socketClose(); } fd = null; return; } else { /* * If a thread has acquired the fd and a close * isn't pending then use a deferred close. * Also decrement fdUseCount to signal the last * thread that releases the fd to close it. */ if (!closePending) { closePending = true; fdUseCount--; socketPreClose(); } } } } }
重新设置链接
void reset() throws IOException { if (fd != null) { socketClose(); } fd = null; super.reset(); }
中止从套接字中输入数据
protected void shutdownInput() throws IOException { if (fd != null) { socketShutdown(SHUT_RD); if (socketInputStream != null) { socketInputStream.setEOF(true); } shut_rd = true; } }
中止向套接字中输出数据
protected void shutdownOutput() throws IOException { if (fd != null) { socketShutdown(SHUT_WR); shut_wr = true; } }
支持立即提交功能
protected boolean supportsUrgentData () { return true; }
发送紧急数据
protected void sendUrgentData (int data) throws IOException { if (fd == null) { throw new IOException("Socket Closed"); } socketSendUrgentData (data); }
最终操作(一般是用户用完忘了关
protected void finalize() throws IOException { close();
}
请求文件描述符(对该套接字使用请求
FileDescriptor acquireFD() { synchronized (fdLock) { fdUseCount++; return fd; } }
释放文件描述符(对该套接字释放
void releaseFD() { synchronized (fdLock) { fdUseCount--; if (fdUseCount == -1) { if (fd != null) { try { socketClose(); } catch (IOException e) { } finally { fd = null; } } } } }
返回状态位(是否重置链接
public boolean isConnectionReset() { synchronized (resetLock) { return (resetState == CONNECTION_RESET); } }
返回状态位(是否期待重设链接
public boolean isConnectionResetPending() { synchronized (resetLock) { return (resetState == CONNECTION_RESET_PENDING); } }
设置状态位(链接重置
public void setConnectionReset() { synchronized (resetLock) { resetState = CONNECTION_RESET; } }
设置状态位(链接需要重置
public void setConnectionResetPending() { synchronized (resetLock) { if (resetState == CONNECTION_NOT_RESET) { resetState = CONNECTION_RESET_PENDING; } } }
是否已经关闭或者期待关闭
public boolean isClosedOrPending() { /* * Lock on fdLock to ensure that we wait if a * close is in progress. */ synchronized (fdLock) { if (closePending || (fd == null)) { return true; } else { return false; } } }
返回超时时长
public int getTimeout() { return timeout; }
预关闭套接字(不释放文件描述符和资源
private void socketPreClose() throws IOException { socketClose0(true); }
关闭套接字(释放资源和描述符
protected void socketClose() throws IOException { socketClose0(false); }
接下来是一些需要完成的方法,方法用途可以通过名称判断:
abstract void socketCreate(boolean isServer) throws IOException; abstract void socketConnect(InetAddress address, int port, int timeout) throws IOException; abstract void socketBind(InetAddress address, int port) throws IOException; abstract void socketListen(int count) throws IOException; abstract void socketAccept(SocketImpl s) throws IOException; abstract int socketAvailable() throws IOException; abstract void socketClose0(boolean useDeferredClose) throws IOException; abstract void socketShutdown(int howto) throws IOException; abstract void socketSetOption(int cmd, boolean on, Object value) throws SocketException; abstract int socketGetOption(int opt, Object iaContainerObj) throws SocketException; abstract void socketSendUrgentData(int data) throws IOException;
该类含有如下的静态代码块(初始化网络库的运行环境
static { java.security.AccessController.doPrivileged(//无视安全检查 new java.security.PrivilegedAction<Void>() { public Void run() { System.loadLibrary("net"); return null; } }); }
该类属于Socket的基本模版,主要为套接字定下了一个大的框架,计算机网络知识中的一些操作在这里也得到体现,如紧急提交标志位等,该类的阅读需要一定的计算机网络基础,否则可能难以准确理解实际意义。