NIO与Socket笔记 :实现Socket 通信[ 一 ]
基于TCP的Socket通信
TCP 是一种 流协议,以流为单位进行数据传输 。
什么是长连接?
长连接可以实现当服务端与客户端连接成功后连续地传输数据,在这 个过程中,连接保持开启的状态,数据传输完毕后连接不关闭 。
长连接是指建立 Socket 连 接后,无论是否使用这个连接,该连接都保持连接的状态 。
什么是短连接?
短连接是当服务端与客户端连接成功后开始传输数据,数据传输完毕 后则连接立即关闭,如果还想再次传输数据,
则需要再创建新的连接进行数据传输 。
什么是连接?
在 TCP/IP 中, 连接可以认为是服务端与客户端确认彼 此都存在的过程 。
由于 UDP 是无连接协议,也就是服务端与客户端 没有确认彼此都存在的握手过程,因此在 UDP 里面不存在长连接与短连接的概念 。
长连接的优缺点
优点: 除了第一次之外,客户端不需要每次传输数据时都先与服务端进行握手,这样就减少了握手确认的时间,直接传输数据,提高程序运行效率 。
缺点: 在服务端保存多个 Socket对象,大量占用服务器资源。
短连接的优缺点
优点 : 在服务端不需要保存多个 Socket对象,降低内存占用率 。
缺点 : 每次传输数据前都要重新创建连接,也就是每次都要进行 3 次握手,增加处理的时间 。
验证 ServerSocket 类的 accept()方法具有阻塞特性
ServerSocket类的作用是创建 Socket (套接字)的服务端,而 Socket类的作用是创建 Socket 的客户端 。 在代码层面使用的方式就是使用 Socket类去连接 ServerSocket类,也就是客户端要主动连接服务端 。
ServerSocket 类中的 public Socket accept()方法的作用是侦听并接受此套接字的连接 。
此方法在连接传人之前一直阻塞。
有客户端连接到服务 端时就不再出现阻塞 了,服务端的程序会继续运行 。
import java.io.*; import java.net.ServerSocket; import java.net.Socket; public class CreateWebServer { public static void main(String[] args) throws Exception { ServerSocket serverSocket = new ServerSocket(7777) ; Socket socket= serverSocket.accept() ; InputStream inputStream = socket.getInputStream() ; InputStreamReader inputStreamReader = new InputStreamReader(inputStream); BufferedReader bufferedReader = new BufferedReader(inputStreamReader) ; String getString = ""; while (!"".equals(getString = bufferedReader.readLine())) { System.out.println(getString); OutputStream outputStream = socket.getOutputStream(); outputStream.write("HTTP/1.1 200 OK\r\n\r\n".getBytes()); outputStream.write("<html><body><a href='http://www.baidu.com'> i am baidu.com welcome you ! </a> </body></html> ".getBytes()); outputStream.flush(); inputStream.close(); outputStream.close(); socket.close (); serverSocket.close(); } } }
在 IE 浏览器地址栏中输入以下网址 : http://127.0.0.1:7777/
验证 Socket 中 lnputStream 类的 read()方法也具有阻塞特性
除了 ServerSocket类 中的 accept()方法具 有阻塞特性外, InputStream类中的 read()方法 也同样具有阻塞特性 。
read()方法阻塞 的原因是客户端并未发送数据到服务端,
服务端一 直在尝试读取从客户端传递过来的数据,
因为客户端从未发送数据给服务端,所以服务端一直在阻塞。
客户端向服务端传递字符串
package com.nio.socket; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.ServerSocket; import java.net.Socket; public class Server { public static void main(String[] args) throws Exception { char [] charArray = new char [3] ; ServerSocket serverSocket = new ServerSocket(7777) ; System.out.println(" accept begin "+ System.currentTimeMillis() ) ; Socket socket = serverSocket . accept(); System.out.println("accept end " + System.currentTimeMillis()) ; InputStream inputStream = socket.getInputStream(); InputStreamReader inputStreamReader = new InputStreamReader(inputStream); System. out. println ("read begin" + System.currentTimeMillis()); int readLength = inputStreamReader . read(charArray) ; while (readLength != -1) { String newString = new String(charArray, 0, readLength); System.out.println(newString); readLength = inputStreamReader.read(charArray); System.out.println("read end " + System.currentTimeMillis()); inputStreamReader.close(); inputStream.close(); socket.close(); serverSocket.close(); } } }
package com.nio.socket; import java.io.IOException; import java.io.OutputStream; import java.net.Socket; public class Client { public static void main(String[] args) throws Exception { System.out.println ("socket begin "+ System.currentTimeMillis()) ; Socket socket = new Socket("localhost", 7777) ; System.out.println( "socket end " + System.currentTimeMillis()); ; Thread.sleep(3000); OutputStream outputStream = socket .getOutputStream() ; outputStream.write (" 我是外星人 " . getBytes()) ; outputStream.close() ; socket .close(); } }
服务端向客户端传递字符串
package com.nio.socket.test41; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; public class Server { public static void main(String[] args) throws Exception { ServerSocket serverSocket = new ServerSocket(7777) ; System.out.println(" accept begin "+ System.currentTimeMillis() ) ; Socket socket = serverSocket . accept(); System.out.println("accept end " + System.currentTimeMillis()) ; OutputStream outputStream = socket.getOutputStream() ; outputStream.write ( " 我来自 server 端 ! ".getBytes() ); outputStream.close(); socket .close(); serverSocket .close(); } }
package com.nio.socket.test41; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.Socket; public class Client { public static void main(String[] args) throws Exception { System.out.println ("socket begin "+ System.currentTimeMillis()) ; Socket socket = new Socket("localhost", 7777) ; System.out.println( "socket end " + System.currentTimeMillis()); char [] charBuffer = new char [3]; InputStream inputStream = socket.getInputStream(); InputStreamReader inputStreamReader = new InputStreamReader(inputStream) ; System.out.println("serverB begin "+ System.currentTimeMillis()) ; int readLength = inputStreamReader . read(charBuffer) ; System.out.println("serverB begin " + System.currentTimeMillis()); while (readLength != 1) { System.out.print(new String(charBuffer, 0, readLength)); readLength = inputStreamReader.read(charBuffer); } System.out.println(); ; inputStream.close() ; socket .close(); } }
允许多次调用 write()方法进行写入操作
write()方法允许多次被调用 ,每执行一次就代表传递一次数据。
实现服务端与客户端多次的往来通信
package com.nio.socket.test5; import java.io.*; import java.net.ServerSocket; import java.net.Socket; public class Server { public static void main(String[] args) throws Exception { char [] charArray = new char [3] ; ServerSocket serverSocket = new ServerSocket(7777) ; System.out.println(" accept begin "+ System.currentTimeMillis() ) ; Socket socket = serverSocket . accept(); System.out.println("accept end " + System.currentTimeMillis()) ; //输入开始 InputStream inputStream = socket .getInputStream ( ) ; ObjectInputStream objectInputStream = new ObjectInputStream (inputStream) ; int byteLength = objectInputStream.readInt(); byte [] byteArray = new byte [byteLength] ; objectInputStream . readFully(byteArray) ; String newString = new String (byteArray); System .out. println(newString ); //输入结束 //输出开始 OutputStream outputStream = socket .getOutputStream() ; String strA = "客户端你好 A\n" ; String strB = "客户端你好 B\n"; String strC = "客户端你好 C\n"; int allStrByteLength = (strA + strB + strC) .getBytes().length ; ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream) ; objectOutputStream.write (allStrByteLength); objectOutputStream.flush() ; objectOutputStream.write(strA . getBytes()); objectOutputStream.write(strB.getBytes()) ; objectOutputStream.write(strC .getBytes()) ; objectOutputStream .flush() ; //输出结束 //输入开始 byteLength = objectInputStream.readInt() ; byteArray = new byte [byteLength] ; objectInputStream .readFully(byteArray) ; newString = new String(byteArray) ; System.out.println(newString) ; // 输入结束 //输出开始 strA ="客户端你好 D\n" ; strB= "客户端你好E\n"; strC = " 客户端你好 F\n"; allStrByteLength = (strA + strB + strC) .getBytes() . length ; objectOutputStream .writeInt (allStrByteLength); objectOutputStream . flush () ; objectOutputStream .write(strA .getBytes()) ; objectOutputStream .write(strB .getBytes()) ; objectOutputStream .write(strC .getBytes()) ; objectOutputStream.flush() ; //输出结束 inputStream . close () ; socket.close(); serverSocket.close(); } }
package com.nio.socket.test5; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.net.Socket; public class Client { public static void main(String[] args) throws Exception { System.out.println ("socket begin "+ System.currentTimeMillis()) ; Socket socket = new Socket("localhost", 7777) ; System.out.println( "socket end " + System.currentTimeMillis()); OutputStream outputStream = socket .getOutputStream(); InputStream inputStream = socket.getInputStream() ; // 输出开始 ObjectOutputStream objectOutputStream = new ObjectOutputStream (outputStream) ; String strA = "服务端你好A\n"; String strB = " 服务端你好 B\n"; String strC = "服务端你好 C\n"; int allStrByteLength = (strA + strB + strC) . getBytes() .length ; objectOutputStream.write(allStrByteLength) ; objectOutputStream.flush() ; objectOutputStream .write(strA.getBytes()) ; objectOutputStream.write(strB.getBytes()) ; objectOutputStream .write(strC.getBytes()) ; objectOutputStream.flush() ; //输出结束 // 输入开始 ObjectInputStream objectInputStream = new ObjectInputStream(inputStream); int byteLength = objectInputStream.readInt() ; byte [] byteArray = new byte [byteLength] ; objectInputStream .readFully(byteArray); String newString = new String(byteArray) ; System .out.println(newString); //输入结束 //输出开始 strA = "服务端你好D\n"; strB ="服务端你好 E\n"; strC = "服务端你好F\n"; allStrByteLength = (strA + strB + strC) .getBytes() . length ; objectOutputStream .writeInt(allStrByteLength) ; objectOutputStream.flush(); objectOutputStream .write(strA.getBytes()) ; objectOutputStream .write(strB.getBytes()) ; objectOutputStream.write(strC.getBytes()) ; objectOutputStream.flush () ; //输出结束 //输入开始 byteLength = objectInputStream.readInt(); byteArray = new byte[byteLength] ; objectInputStream.readFully(byteArray) ; newString = new String(byteArray) ; System . out .println(newString) ; //输入结束 objectOutputStream.close() ; outputStream.close() ; socket .close(); } }
调用 Stream 的 close()方法造成 Socket 关闭
/** * Closes the stream. */ private boolean closing = false; public void close() throws IOException { // Prevent recursion. See BugId 4484411 if (closing) return; closing = true; if (socket != null) { if (!socket.isClosed()) socket.close(); } else impl.close(); closing = false; }
使用Socket传递PNG图片文件