package socket; /** * 协议常量 * @author donald * 2017年2月11日 * 下午12:05:29 */ public class ProtocolConstants { /** * 加法协议编码 */ public static final String SUM_PROTOCOL_300000 = "300000"; /** * 乘法协议编码 */ public static final String MULTI_PROTOCOL_300100 = "300100"; /** * 计算结果 */ public static final String ACK_PROTOCOL_300200 = "300200"; /** * 协议编码长度 */ public static final Integer PROTOCOL_CODE_LENGTH = 6; /** * 协议操作数长度 */ public static final Integer OPERATE_NUM_LENGTH = 10; /** * 协议计算结果长度 */ public static final Integer PROTOCOL_ACK_LENGTH = 2; /** * 协议结束符 */ public static final String PROTOCOL_END = "\r\n"; /** * 协议结束符长度 */ public static final Integer PROTOCOL_END_LENGTH = 2; /** * 字符集 */ public static final String CHARSET_UTF8 = "UTF-8"; }
package socket; /** * 协议辅助工具 * @author donald * 2017年2月11日 * 下午12:05:13 */ public class ProtocolUtils { private static volatile ProtocolUtils instance = null; public static synchronized ProtocolUtils getInstance(){ if(instance == null){ instance = new ProtocolUtils(); } return instance; } /** * 如果orgStr的长度不够length,左侧填充0 * @param orgStr * @param length * @return */ public String fillString(String orgStr, int length){ if(orgStr.length() < length){ int orgStrLength = orgStr.length(); int zeroNum = length - orgStrLength; for(int i=0; i< zeroNum; i++){ orgStr = "0" + orgStr; } } return orgStr; } public static void main(String[] args) { int firstNum = 15; String firstNumStr = String.valueOf(firstNum); if(firstNumStr.length() <= 10){ firstNumStr = ProtocolUtils.getInstance().fillString(firstNumStr,10); } System.out.println("=======firstNumStr:"+firstNumStr); System.out.println("=======firstNumStr Integer Value:"+Integer.valueOf(firstNumStr)); } }
package socket; import java.io.IOException; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.UnknownHostException; /** * Socket Server * @author donald * 2017年2月12日 * 下午2:43:58 */ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class TcpServerSocket { private static int port = 4003;//端口号 private static int backlog = 20;//Server最大连接数 private static InetAddress serverHost = null;//server地址 static{ try { serverHost = InetAddress.getLocalHost(); System.out.println("主机名:"+serverHost.getHostName()); System.out.println("主机地址:"+serverHost.getHostAddress()); } catch (UnknownHostException e) { System.out.println("获取主机地址信息异常:"+e.getMessage()); e.printStackTrace(); } } //搭建服务器端 public static void main(String[] args){ TcpServerSocket tcpServerSocket = new TcpServerSocket(); //创建一个服务器端Socket,即SocketService tcpServerSocket.startServer(); } public void startServer(){ ServerSocket tcpServer=null; ExecutorService exec = Executors.newCachedThreadPool(); try { tcpServer=new ServerSocket(port,backlog,serverHost); System.out.println("服务器启动成功........."); while(true){ try { Socket socket = tcpServer.accept(); System.out.println("服务器接受客户端连接........."); SocketHandleRunnable sHandleRunnable = new SocketHandleRunnable(socket); exec.execute(sHandleRunnable); //有返回值 //exec.submit(sHandleRunnable); } catch (IOException e) { e.printStackTrace(); } } } catch (IOException e) { System.out.println("服务器启动失败:"+e.getMessage()); e.printStackTrace(); } finally{ try { tcpServer.close(); } catch (IOException e) { e.printStackTrace(); } exec.shutdown(); } } }
package socket; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; /** * Socket处理线程 * @author donald * 2017年2月12日 * 下午2:54:47 */ public class SocketHandleRunnable implements Runnable { private static ProtocolUtils protocolUtils = null; private Socket socket; static { protocolUtils = ProtocolUtils.getInstance(); } public SocketHandleRunnable(Socket socket) { super(); this.socket = socket; } @Override public void run() { System.out.println("开始处理Socket........"); InputStream serverInputStream = null; OutputStream serverOutputStream = null; BufferedInputStream serverBufferInputStream = null; BufferedOutputStream serverBufferOutputStream = null; try { serverInputStream = socket.getInputStream(); serverOutputStream = socket.getOutputStream(); serverBufferInputStream = new BufferedInputStream(serverInputStream); serverBufferOutputStream = new BufferedOutputStream(serverOutputStream); int protocolLenght = ProtocolConstants.PROTOCOL_CODE_LENGTH + ProtocolConstants.OPERATE_NUM_LENGTH*2 + ProtocolConstants.PROTOCOL_END_LENGTH; boolean flag = true; while(flag){ if(serverBufferInputStream.available() >= protocolLenght){ byte[] protcBuf = new byte[protocolLenght]; int readLength = serverBufferInputStream.read(protcBuf, 0, protocolLenght); System.out.println("从接受缓冲区读取的实际协议长度为:"+readLength); if(readLength == protocolLenght){ String protcStr = new String(protcBuf,ProtocolConstants.CHARSET_UTF8); String endStr = protcStr.substring(protcStr.length()-2, protcStr.length()); if(endStr.equals(ProtocolConstants.PROTOCOL_END)){ System.out.println("开始解析计算协议......"); String protocolCode = protcStr.substring(0, 6); String firstNumStr = protcStr.substring(6, 16); int firstNum = Integer.valueOf(firstNumStr); String secNumStr = protcStr.substring(16, 26); int secNum = Integer.valueOf(secNumStr); System.out.println("计算协议解析完毕......"); int result = 0; if(protocolCode.equals(ProtocolConstants.SUM_PROTOCOL_300000)){ result = firstNum + secNum; } if(protocolCode.equals(ProtocolConstants.MULTI_PROTOCOL_300100)){ result = firstNum*secNum; } System.out.println("开始发送计算结果协议......"); //将计算结果值发送给Client //发送计算结果协议编码 byte[] AckProtocolBytes = ProtocolConstants.ACK_PROTOCOL_300200.getBytes(ProtocolConstants.CHARSET_UTF8); serverBufferOutputStream.write(AckProtocolBytes); //结果值 String resultStr = String.valueOf(result); System.out.println("服务器计算结果为:"+resultStr); byte[] resultBytes = resultStr.getBytes(ProtocolConstants.CHARSET_UTF8); //结果长度 int resultLength = resultStr.length(); String reultLenthStr = String.valueOf(resultLength); reultLenthStr = protocolUtils.fillString(reultLenthStr, ProtocolConstants.PROTOCOL_ACK_LENGTH); byte[] resultLengthBytes = reultLenthStr.getBytes(ProtocolConstants.CHARSET_UTF8); serverBufferOutputStream.write(resultLengthBytes); //发送结果值 serverBufferOutputStream.write(resultBytes); //发送结束符 serverBufferOutputStream.write(ProtocolConstants.PROTOCOL_END.getBytes(ProtocolConstants.CHARSET_UTF8)); System.out.println("发送计算结果协议结束......"); //将缓冲区发送到Client,我们这里是强制清空缓冲区,实际不要这样做,以免影响数据传输效率 serverBufferOutputStream.flush(); } } if(readLength < 0){ System.out.println("与客户端失去连接....."); } if(readLength < protocolLenght){ //从缓冲区继续读取数据,直至读取的数据长度为协议长度+结束符; //当数据解析异常时,可以用InputStream.skip(long n),丢弃一些数据,以保证一次协议包的完成性 } } } } catch (IOException e) { e.printStackTrace(); } finally{ try { serverBufferInputStream.close(); serverBufferOutputStream.close(); socket.close(); } catch (IOException e) { e.printStackTrace(); } } System.out.println("Socket处理结束........"); } }
package socket; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import java.net.UnknownHostException; /** * Socket Client * @author donald * 2017年2月12日 * 下午2:43:46 */ public class TcpClient { private static ProtocolUtils protocolUtils = null; private static final String ip ="192.168.132.126"; private static final int port = 4003; private static final int bufferSize = 1024; static { protocolUtils = ProtocolUtils.getInstance(); } // 搭建客户端 public static void main(String[] args){ Socket socket = null; OutputStream clientOutputStream = null; InputStream clientInputStream = null; BufferedInputStream clientBufferInputStream = null; BufferedOutputStream clientBufferOutputStream = null; try { socket = new Socket(ip, port); socket.setSendBufferSize(bufferSize); socket.setReceiveBufferSize(bufferSize); socket.setKeepAlive(true); if(socket.isConnected()){ System.out.println("连接服务器成功..........."); try { clientOutputStream = socket.getOutputStream(); clientInputStream = socket.getInputStream(); clientBufferInputStream = new BufferedInputStream(clientInputStream); clientBufferOutputStream = new BufferedOutputStream(clientOutputStream); //只做长度为10以内的加法与乘法 //加法 System.out.println("发送加法计算协议开始..........."); //发送协议编码 byte[] sumProtocolBytes = ProtocolConstants.SUM_PROTOCOL_300000.getBytes(ProtocolConstants.CHARSET_UTF8); clientBufferOutputStream.write(sumProtocolBytes); //发送第一个操作数 int firstNum = 15; String firstNumStr = String.valueOf(firstNum); //如果操作符不够长度,则左侧补零 firstNumStr = protocolUtils.fillString(firstNumStr, ProtocolConstants.OPERATE_NUM_LENGTH); byte[] firstNumBytes = firstNumStr.getBytes(ProtocolConstants.CHARSET_UTF8); clientBufferOutputStream.write(firstNumBytes); //发送第二个操作数 int secondNum = 6; String secondNumStr = String.valueOf(secondNum); secondNumStr = protocolUtils.fillString(secondNumStr, ProtocolConstants.OPERATE_NUM_LENGTH); byte[] secondNumBytes = secondNumStr.getBytes(ProtocolConstants.CHARSET_UTF8); clientBufferOutputStream.write(secondNumBytes); //发送协议结束符 byte[] endBytes = ProtocolConstants.PROTOCOL_END.getBytes(ProtocolConstants.CHARSET_UTF8); clientBufferOutputStream.write(endBytes); System.out.println("发送加法计算协议结束..........."); System.out.println("发送乘法计算协议开始..........."); // 乘法 byte[] sumProtocolBytesx = ProtocolConstants.MULTI_PROTOCOL_300100.getBytes(ProtocolConstants.CHARSET_UTF8); clientBufferOutputStream.write(sumProtocolBytesx); //发送第一个操作数 int firstNumx = 17; String firstNumStrx = String.valueOf(firstNumx); //如果操作符不够长度,则左侧补零 firstNumStrx = protocolUtils.fillString(firstNumStrx, ProtocolConstants.OPERATE_NUM_LENGTH); byte[] firstNumBytesx = firstNumStrx.getBytes(ProtocolConstants.CHARSET_UTF8); clientBufferOutputStream.write(firstNumBytesx); //发送第二个操作数 int secondNumx = 8; String secondNumStrx = String.valueOf(secondNumx); secondNumStrx = protocolUtils.fillString(secondNumStrx, ProtocolConstants.OPERATE_NUM_LENGTH); byte[] secondNumBytesx = secondNumStrx.getBytes(ProtocolConstants.CHARSET_UTF8); clientBufferOutputStream.write(secondNumBytesx); //发送协议结束符 clientBufferOutputStream.write(endBytes); //将缓冲区发送到Server,我们这里是强制清空缓冲区,实际不要这样做,以免影响数据传输效率 clientBufferOutputStream.flush(); System.out.println("发送乘法计算协议结束..........."); try { Thread.sleep(3000); System.out.println("等待服务器计算结果..........."); } catch (InterruptedException e) { e.printStackTrace(); } boolean flag = true; //返回的协议长度,协议编码6+结果长度2 int ackLength = ProtocolConstants.PROTOCOL_CODE_LENGTH + ProtocolConstants.PROTOCOL_ACK_LENGTH; while(flag){ // System.out.println("等待解析服务器计算结果..........."); //结果值长度 int valueLenth = 0; //接受缓冲区的可利用长度大于等于8 if(clientBufferInputStream.available()>=ackLength){ byte[] codeBuf = new byte[6]; int codeLength = clientBufferInputStream.read(codeBuf, 0, 6); System.out.println("从接受缓冲区读取协议编码的实际长度为:"+codeLength); if(codeLength == 6){ String ackProtcolCode = new String(codeBuf,ProtocolConstants.CHARSET_UTF8); if(ackProtcolCode.equals(ProtocolConstants.ACK_PROTOCOL_300200)){ System.out.println("协议编码:"+ackProtcolCode); byte[] resultBuf = new byte[2]; int resultLength = clientBufferInputStream.read(resultBuf, 0, 2); if(resultLength == 2){ String resultLengthStr = new String(resultBuf,ProtocolConstants.CHARSET_UTF8); valueLenth = Integer.valueOf(resultLengthStr); System.out.println("结果值长度为:"+valueLenth); } if(resultLength < 0){ //与服务器失去连接 flag = false; System.out.println("与服务器失去连接....."); } } } if(codeLength < 0){ //与服务器失去连接 flag = false; System.out.println("与服务器失去连接....."); } } if(valueLenth > 0){ //结果值+协议结束符(2) int valueEndLenth = valueLenth + ProtocolConstants.PROTOCOL_END_LENGTH; if(clientBufferInputStream.available()>=valueEndLenth){ byte[] valueEndBuf = new byte[valueEndLenth]; int readLength = clientBufferInputStream.read(valueEndBuf, 0, valueEndLenth); System.out.println("从接受缓冲区读取计算结果值和结束符实际长度为:"+readLength); if(readLength == valueEndLenth){ String valueEndStr = new String(valueEndBuf,ProtocolConstants.CHARSET_UTF8); String endStr = valueEndStr.substring(valueEndStr.length()-2, valueEndStr.length()); if(endStr.equals(ProtocolConstants.PROTOCOL_END)){ System.out.println("计算结果协议结束:"+readLength); String valueStr = valueEndStr.substring(0,valueEndStr.length()-2); System.out.println("计算结果为:"+valueStr); } } if(readLength < 0){ //与服务器失去连接 flag = false; System.out.println("与服务器失去连接....."); } } } } } catch (IOException e) { System.out.println("服务器IO异常:"+e.getMessage()); e.printStackTrace(); } finally{ try { clientBufferInputStream.close(); clientInputStream.close(); } catch (IOException e) { System.out.println("关闭资源异常:"+e.getMessage()); e.printStackTrace(); } } } } catch (UnknownHostException e) { System.out.println("连接服务器异常:"+e.getMessage()); e.printStackTrace(); } catch (IOException e) { System.out.println("连接服务器IO异常:"+e.getMessage()); e.printStackTrace(); } finally{ try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } }
package socket; import java.io.UnsupportedEncodingException; import java.net.InetAddress; import java.net.UnknownHostException; /** * 辅助测试 * @author donald * 2017年2月12日 * 下午5:12:28 */ public class testByte { public static void main(String[] args) { try { String end = "\r\n"; byte[] endBytes = end.getBytes("UTF-8"); System.out.println("====endBytes Length:"+endBytes.length); String endStr = new String(endBytes,"UTF-8"); System.out.println("是否结束:"+endStr.equals("\r\n")); System.out.println("====结束符:"+endStr); String sumProtocol = "300000"; byte[] sumProtocolBytes = sumProtocol.getBytes("UTF-8"); System.out.println("====sumProtocol Length:"+sumProtocolBytes.length); String sumProtocolStr = new String(sumProtocolBytes,"UTF-8"); System.out.println("====加法协议:"+sumProtocolStr); String multiProtocol = "3000100"; byte[] multiProtocolBytes = multiProtocol.getBytes("UTF-8"); System.out.println("====multiProtocol Length:"+multiProtocolBytes.length); String multiProtocolStr = new String(multiProtocolBytes,"UTF-8"); System.out.println("====乘法协议:"+multiProtocolStr); int firstNum = 15; String firstNumStr = String.valueOf(firstNum); //如果第一个操作符不够长度,则补零 if(firstNumStr.length()<10){ int NumLength = firstNumStr.length(); int zeroNum = 10 - NumLength; String zeroNumStr=""; for(int i=0; i< zeroNum; i++){ zeroNumStr += "0"; } firstNumStr = zeroNumStr + firstNumStr; } System.out.println("补零后的字符串:"+firstNumStr); try { InetAddress host = InetAddress.getLocalHost(); System.out.println("主机名:"+host.getHostName()); System.out.println("主机地质:"+host.getHostAddress()); } catch (UnknownHostException e) { e.printStackTrace(); } } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } }
//ServerSocket //服务端 package java.net; import java.io.FileDescriptor; import java.io.IOException; import java.nio.channels.ServerSocketChannel; import java.security.AccessController; import java.security.PrivilegedExceptionAction; /** * This class implements server sockets. A server socket waits for * requests to come in over the network. It performs some operation * based on that request, and then possibly returns a result to the requester. * <p> * The actual work of the server socket is performed by an instance * of the <code>SocketImpl</code> class. An application can * change the socket factory that creates the socket * implementation to configure itself to create sockets * appropriate to the local firewall. * * @author unascribed * @see java.net.SocketImpl * @see java.net.ServerSocket#setSocketFactory(java.net.SocketImplFactory) * @see java.nio.channels.ServerSocketChannel * @since JDK1.0 */ public class ServerSocket implements java.io.Closeable {
//Socket //客户端 /** * This class implements client sockets (also called just * "sockets"). A socket is an endpoint for communication * between two machines. * <p> * The actual work of the socket is performed by an instance of the * <code>SocketImpl</code> class. An application, by changing * the socket factory that creates the socket implementation, * can configure itself to create sockets appropriate to the local * firewall. * * @author unascribed * @see java.net.Socket#setSocketImplFactory(java.net.SocketImplFactory) * @see java.net.SocketImpl * @see java.nio.channels.SocketChannel * @since JDK1.0 */ public class Socket implements java.io.Closeable {
//InputStream //从Socket获取的InputStream,要经过BufferedInputStream,DataInputStream //等的包装才可以读数据,注意skip,mark,reset函数 package java.io; /** * This abstract class is the superclass of all classes representing * an input stream of bytes. * * <p> Applications that need to define a subclass of <code>InputStream</code> * must always provide a method that returns the next byte of input. * * @author Arthur van Hoff * @see java.io.BufferedInputStream * @see java.io.ByteArrayInputStream * @see java.io.DataInputStream * @see java.io.FilterInputStream * @see java.io.InputStream#read() * @see java.io.OutputStream * @see java.io.PushbackInputStream * @since JDK1.0 */ public abstract class InputStream implements Closeable { // MAX_SKIP_BUFFER_SIZE is used to determine the maximum buffer size to // use when skipping. private static final int MAX_SKIP_BUFFER_SIZE = 2048; /** * Reads the next byte of data from the input stream. The value byte is * returned as an <code>int</code> in the range <code>0</code> to * <code>255</code>. If no byte is available because the end of the stream * has been reached, the value <code>-1</code> is returned. This method * blocks until input data is available, the end of the stream is detected, * or an exception is thrown. * * <p> A subclass must provide an implementation of this method. * * @return the next byte of data, or <code>-1</code> if the end of the * stream is reached. * @exception IOException if an I/O error occurs. */ public abstract int read() throws IOException; /** * Reads some number of bytes from the input stream and stores them into * the buffer array <code>b</code>. The number of bytes actually read is * returned as an integer. This method blocks until input data is * available, end of file is detected, or an exception is thrown. * * <p> If the length of <code>b</code> is zero, then no bytes are read and * <code>0</code> is returned; otherwise, there is an attempt to read at * least one byte. If no byte is available because the stream is at the * end of the file, the value <code>-1</code> is returned; otherwise, at * least one byte is read and stored into <code>b</code>. * * <p> The first byte read is stored into element <code>b[0]</code>, the * next one into <code>b[1]</code>, and so on. The number of bytes read is, * at most, equal to the length of <code>b</code>. Let <i>k</i> be the * number of bytes actually read; these bytes will be stored in elements * <code>b[0]</code> through <code>b[</code><i>k</i><code>-1]</code>, * leaving elements <code>b[</code><i>k</i><code>]</code> through * <code>b[b.length-1]</code> unaffected. * * <p> The <code>read(b)</code> method for class <code>InputStream</code> * has the same effect as: <pre><code> read(b, 0, b.length) </code></pre> * * @param b the buffer into which the data is read. * @return the total number of bytes read into the buffer, or * <code>-1</code> if there is no more data because the end of * the stream has been reached. * @exception IOException If the first byte cannot be read for any reason * other than the end of the file, if the input stream has been closed, or * if some other I/O error occurs. * @exception NullPointerException if <code>b</code> is <code>null</code>. * @see java.io.InputStream#read(byte[], int, int) */ public int read(byte b[]) throws IOException { return read(b, 0, b.length); } /** * Reads up to <code>len</code> bytes of data from the input stream into * an array of bytes. An attempt is made to read as many as * <code>len</code> bytes, but a smaller number may be read. * The number of bytes actually read is returned as an integer. * * <p> This method blocks until input data is available, end of file is * detected, or an exception is thrown. * * <p> If <code>len</code> is zero, then no bytes are read and * <code>0</code> is returned; otherwise, there is an attempt to read at * least one byte. If no byte is available because the stream is at end of * file, the value <code>-1</code> is returned; otherwise, at least one * byte is read and stored into <code>b</code>. * * <p> The first byte read is stored into element <code>b[off]</code>, the * next one into <code>b[off+1]</code>, and so on. The number of bytes read * is, at most, equal to <code>len</code>. Let <i>k</i> be the number of * bytes actually read; these bytes will be stored in elements * <code>b[off]</code> through <code>b[off+</code><i>k</i><code>-1]</code>, * leaving elements <code>b[off+</code><i>k</i><code>]</code> through * <code>b[off+len-1]</code> unaffected. * * <p> In every case, elements <code>b[0]</code> through * <code>b[off]</code> and elements <code>b[off+len]</code> through * <code>b[b.length-1]</code> are unaffected. * * <p> The <code>read(b,</code> <code>off,</code> <code>len)</code> method * for class <code>InputStream</code> simply calls the method * <code>read()</code> repeatedly. If the first such call results in an * <code>IOException</code>, that exception is returned from the call to * the <code>read(b,</code> <code>off,</code> <code>len)</code> method. If * any subsequent call to <code>read()</code> results in a * <code>IOException</code>, the exception is caught and treated as if it * were end of file; the bytes read up to that point are stored into * <code>b</code> and the number of bytes read before the exception * occurred is returned. The default implementation of this method blocks * until the requested amount of input data <code>len</code> has been read, * end of file is detected, or an exception is thrown. Subclasses are encouraged * to provide a more efficient implementation of this method. * * @param b the buffer into which the data is read. * @param off the start offset in array <code>b</code> * at which the data is written. * @param len the maximum number of bytes to read. * @return the total number of bytes read into the buffer, or * <code>-1</code> if there is no more data because the end of * the stream has been reached. * @exception IOException If the first byte cannot be read for any reason * other than end of file, or if the input stream has been closed, or if * some other I/O error occurs. * @exception NullPointerException If <code>b</code> is <code>null</code>. * @exception IndexOutOfBoundsException If <code>off</code> is negative, * <code>len</code> is negative, or <code>len</code> is greater than * <code>b.length - off</code> * @see java.io.InputStream#read() */ public int read(byte b[], int off, int len) throws IOException { if (b == null) { throw new NullPointerException(); } else if (off < 0 || len < 0 || len > b.length - off) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return 0; } int c = read(); if (c == -1) { return -1; } b[off] = (byte)c; int i = 1; try { for (; i < len ; i++) { c = read(); if (c == -1) { break; } b[off + i] = (byte)c; } } catch (IOException ee) { } return i; } /** * Skips over and discards <code>n</code> bytes of data from this input * stream. The <code>skip</code> method may, for a variety of reasons, end * up skipping over some smaller number of bytes, possibly <code>0</code>. * This may result from any of a number of conditions; reaching end of file * before <code>n</code> bytes have been skipped is only one possibility. * The actual number of bytes skipped is returned. If <code>n</code> is * negative, no bytes are skipped. * * <p> The <code>skip</code> method of this class creates a * byte array and then repeatedly reads into it until <code>n</code> bytes * have been read or the end of the stream has been reached. Subclasses are * encouraged to provide a more efficient implementation of this method. * For instance, the implementation may depend on the ability to seek. * * @param n the number of bytes to be skipped. * @return the actual number of bytes skipped. * @exception IOException if the stream does not support seek, * or if some other I/O error occurs. */ public long skip(long n) throws IOException { long remaining = n; int nr; if (n <= 0) { return 0; } int size = (int)Math.min(MAX_SKIP_BUFFER_SIZE, remaining); byte[] skipBuffer = new byte[size]; while (remaining > 0) { nr = read(skipBuffer, 0, (int)Math.min(size, remaining)); if (nr < 0) { break; } remaining -= nr; } return n - remaining; } /** * Returns an estimate of the number of bytes that can be read (or * skipped over) from this input stream without blocking by the next * invocation of a method for this input stream. The next invocation * might be the same thread or another thread. A single read or skip of this * many bytes will not block, but may read or skip fewer bytes. * * <p> Note that while some implementations of {@code InputStream} will return * the total number of bytes in the stream, many will not. It is * never correct to use the return value of this method to allocate * a buffer intended to hold all data in this stream. * * <p> A subclass' implementation of this method may choose to throw an * {@link IOException} if this input stream has been closed by * invoking the {@link #close()} method. * * <p> The {@code available} method for class {@code InputStream} always * returns {@code 0}. * * <p> This method should be overridden by subclasses. * * @return an estimate of the number of bytes that can be read (or skipped * over) from this input stream without blocking or {@code 0} when * it reaches the end of the input stream. * @exception IOException if an I/O error occurs. */ public int available() throws IOException { return 0; } /** * Closes this input stream and releases any system resources associated * with the stream. * * <p> The <code>close</code> method of <code>InputStream</code> does * nothing. * * @exception IOException if an I/O error occurs. */ public void close() throws IOException {} /** * Marks the current position in this input stream. A subsequent call to * the <code>reset</code> method repositions this stream at the last marked * position so that subsequent reads re-read the same bytes. * * <p> The <code>readlimit</code> arguments tells this input stream to * allow that many bytes to be read before the mark position gets * invalidated. * * <p> The general contract of <code>mark</code> is that, if the method * <code>markSupported</code> returns <code>true</code>, the stream somehow * remembers all the bytes read after the call to <code>mark</code> and * stands ready to supply those same bytes again if and whenever the method * <code>reset</code> is called. However, the stream is not required to * remember any data at all if more than <code>readlimit</code> bytes are * read from the stream before <code>reset</code> is called. * * <p> Marking a closed stream should not have any effect on the stream. * * <p> The <code>mark</code> method of <code>InputStream</code> does * nothing. * * @param readlimit the maximum limit of bytes that can be read before * the mark position becomes invalid. * @see java.io.InputStream#reset() */ public synchronized void mark(int readlimit) {} /** * Repositions this stream to the position at the time the * <code>mark</code> method was last called on this input stream. * * <p> The general contract of <code>reset</code> is: * * <p>[list] * * <li> If the method <code>markSupported</code> returns * <code>true</code>, then: * * [list]<li> If the method <code>mark</code> has not been called since * the stream was created, or the number of bytes read from the stream * since <code>mark</code> was last called is larger than the argument * to <code>mark</code> at that last call, then an * <code>IOException</code> might be thrown. * * <li> If such an <code>IOException</code> is not thrown, then the * stream is reset to a state such that all the bytes read since the * most recent call to <code>mark</code> (or since the start of the * file, if <code>mark</code> has not been called) will be resupplied * to subsequent callers of the <code>read</code> method, followed by * any bytes that otherwise would have been the next input data as of * the time of the call to <code>reset</code>. [/list] * * <li> If the method <code>markSupported</code> returns * <code>false</code>, then: * * [list]<li> The call to <code>reset</code> may throw an * <code>IOException</code>. * * <li> If an <code>IOException</code> is not thrown, then the stream * is reset to a fixed state that depends on the particular type of the * input stream and how it was created. The bytes that will be supplied * to subsequent callers of the <code>read</code> method depend on the * particular type of the input stream. [/list][/list] * * <p>The method <code>reset</code> for class <code>InputStream</code> * does nothing except throw an <code>IOException</code>. * * @exception IOException if this stream has not been marked or if the * mark has been invalidated. * @see java.io.InputStream#mark(int) * @see java.io.IOException */ public synchronized void reset() throws IOException { throw new IOException("mark/reset not supported"); } /** * Tests if this input stream supports the <code>mark</code> and * <code>reset</code> methods. Whether or not <code>mark</code> and * <code>reset</code> are supported is an invariant property of a * particular input stream instance. The <code>markSupported</code> method * of <code>InputStream</code> returns <code>false</code>. * * @return <code>true</code> if this stream instance supports the mark * and reset methods; <code>false</code> otherwise. * @see java.io.InputStream#mark(int) * @see java.io.InputStream#reset() */ public boolean markSupported() { return false; } }
//OutputStream,从socket获取的输出流,需要BufferedOutputStream,DataOutputStream //的包装才可以发送数据,注意,flush函数,将flush函数调用是,立即发送缓冲区里的所有数//据 package java.io; /** * This abstract class is the superclass of all classes representing * an output stream of bytes. An output stream accepts output bytes * and sends them to some sink. * <p> * Applications that need to define a subclass of * <code>OutputStream</code> must always provide at least a method * that writes one byte of output. * * @author Arthur van Hoff * @see java.io.BufferedOutputStream * @see java.io.ByteArrayOutputStream * @see java.io.DataOutputStream * @see java.io.FilterOutputStream * @see java.io.InputStream * @see java.io.OutputStream#write(int) * @since JDK1.0 */ public abstract class OutputStream implements Closeable, Flushable { /** * Writes the specified byte to this output stream. The general * contract for <code>write</code> is that one byte is written * to the output stream. The byte to be written is the eight * low-order bits of the argument <code>b</code>. The 24 * high-order bits of <code>b</code> are ignored. * <p> * Subclasses of <code>OutputStream</code> must provide an * implementation for this method. * * @param b the <code>byte</code>. * @exception IOException if an I/O error occurs. In particular, * an <code>IOException</code> may be thrown if the * output stream has been closed. */ public abstract void write(int b) throws IOException; /** * Writes <code>b.length</code> bytes from the specified byte array * to this output stream. The general contract for <code>write(b)</code> * is that it should have exactly the same effect as the call * <code>write(b, 0, b.length)</code>. * * @param b the data. * @exception IOException if an I/O error occurs. * @see java.io.OutputStream#write(byte[], int, int) */ public void write(byte b[]) throws IOException { write(b, 0, b.length); } /** * Writes <code>len</code> bytes from the specified byte array * starting at offset <code>off</code> to this output stream. * The general contract for <code>write(b, off, len)</code> is that * some of the bytes in the array <code>b</code> are written to the * output stream in order; element <code>b[off]</code> is the first * byte written and <code>b[off+len-1]</code> is the last byte written * by this operation. * <p> * The <code>write</code> method of <code>OutputStream</code> calls * the write method of one argument on each of the bytes to be * written out. Subclasses are encouraged to override this method and * provide a more efficient implementation. * <p> * If <code>b</code> is <code>null</code>, a * <code>NullPointerException</code> is thrown. * <p> * If <code>off</code> is negative, or <code>len</code> is negative, or * <code>off+len</code> is greater than the length of the array * <code>b</code>, then an <tt>IndexOutOfBoundsException</tt> is thrown. * * @param b the data. * @param off the start offset in the data. * @param len the number of bytes to write. * @exception IOException if an I/O error occurs. In particular, * an <code>IOException</code> is thrown if the output * stream is closed. */ public void write(byte b[], int off, int len) throws IOException { if (b == null) { throw new NullPointerException(); } else if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0)) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return; } for (int i = 0 ; i < len ; i++) { write(b[off + i]); } } /** * Flushes this output stream and forces any buffered output bytes * to be written out. The general contract of <code>flush</code> is * that calling it is an indication that, if any bytes previously * written have been buffered by the implementation of the output * stream, such bytes should immediately be written to their * intended destination. * <p> * If the intended destination of this stream is an abstraction provided by * the underlying operating system, for example a file, then flushing the * stream guarantees only that bytes previously written to the stream are * passed to the operating system for writing; it does not guarantee that * they are actually written to a physical device such as a disk drive. * <p> * The <code>flush</code> method of <code>OutputStream</code> does nothing. * * @exception IOException if an I/O error occurs. */ public void flush() throws IOException { } /** * Closes this output stream and releases any system resources * associated with this stream. The general contract of <code>close</code> * is that it closes the output stream. A closed stream cannot perform * output operations and cannot be reopened. * <p> * The <code>close</code> method of <code>OutputStream</code> does nothing. * * @exception IOException if an I/O error occurs. */ public void close() throws IOException { } }
//BufferedInputStream package java.io; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; /** * A <code>BufferedInputStream</code> adds * functionality to another input stream-namely, * the ability to buffer the input and to * support the <code>mark</code> and <code>reset</code> * methods. When the <code>BufferedInputStream</code> * is created, an internal buffer array is * created. As bytes from the stream are read * or skipped, the internal buffer is refilled * as necessary from the contained input stream, * many bytes at a time. The <code>mark</code> * operation remembers a point in the input * stream and the <code>reset</code> operation * causes all the bytes read since the most * recent <code>mark</code> operation to be * reread before new bytes are taken from * the contained input stream. * * @author Arthur van Hoff * @since JDK1.0 */ public class BufferedInputStream extends FilterInputStream { private static int defaultBufferSize = 8192;
//BufferedOutputStream package java.io; /** * The class implements a buffered output stream. By setting up such * an output stream, an application can write bytes to the underlying * output stream without necessarily causing a call to the underlying * system for each byte written. * * @author Arthur van Hoff * @since JDK1.0 */ public class BufferedOutputStream extends FilterOutputStream {
//DataInputStream package java.io; /** * A data input stream lets an application read primitive Java data * types from an underlying input stream in a machine-independent * way. An application uses a data output stream to write data that * can later be read by a data input stream. * <p> * DataInputStream is not necessarily safe for multithreaded access. * Thread safety is optional and is the responsibility of users of * methods in this class. * * @author Arthur van Hoff * @see java.io.DataOutputStream * @since JDK1.0 */ public class DataInputStream extends FilterInputStream implements DataInput {
//DataOutputStream package java.io; /** * A data output stream lets an application write primitive Java data * types to an output stream in a portable way. An application can * then use a data input stream to read the data back in. * * @author unascribed * @see java.io.DataInputStream * @since JDK1.0 */ public class DataOutputStream extends FilterOutputStream implements DataOutput {