聲明:本文為原創,如需轉載請說明出處:http://www.cnblogs.com/gudu1/p/7669175.html
首先為什么要寫這個呢?因為在幾個月之前我還使用Socket做一個小項目,而在今天我回想起Socket的操作細節,在我腦海里使勁挖掘Socket的痕跡,竟然絲毫沒有找到,所以立即寫了一個小Demo來記錄一下,有些東西長時間不用肯定要忘的,人的腦容量有限,跟電腦緩存一樣,不夠用的時候會把那些不用的占內存的給釋放掉, 就到這吧,說正題。
Socket 和 ServerSocket 的官方API解釋:
Socket : 此類實現客戶端套接字(也可以就叫“套接字”)。套接字是兩台機器間通信的端點。
ServerSocket:此類實現服務器套接字。服務器套接字等待請求通過網絡傳入。它基於該請求執行某些操作,然后可能向請求者返回結果。
套接字的實際工作由 SocketImpl
類的實例執行。應用程序通過更改創建套接字實現的套接字工廠可以配置它自身,以創建適合本地防火牆的套接字。
在這個Demo中我使用了java.net包下的兩個類:Socket 和 ServerSocket ,使用到的自定義類有3個:Service 、 Client 、ServiceThread,下面配合代碼來解釋一下
ServiceThread.java ,就把它當做一個服務器處理程序就好了
import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.io.IOException; import java.io.*; public class ServiceThread implements Runnable { Socket s = null; public ServiceThread(Socket socket) { // ① super(); this.s = socket; } @Override public void run() { String ip = s.getInetAddress().getHostName(); // ② System.out.println("ip:"+ip); try{ InputStream is = s.getInputStream(); // ③ byte[] buf = new byte[1024]; int len = 0; File file = new File("D:/heheCopy.java"); // ④ OutputStream os = new FileOutputStream(file); System.out.println("開始上傳"); while((len = is.read(buf)) != -1){ // ⑤ os.write(buf,0,len); // ⑥ } System.out.println("上傳完畢"); is.close(); os.close(); } catch (Exception e){ e.printStackTrace(); } } }
① :類只有一個構造函數,參數是Socket對象(即一個用戶),因為在服務器和客戶端是通過 I/O 流來交互,所以服務器端要獲取客戶端的IO對象(即輸入輸出流)。
②: 獲取客戶端的IP地址
③: 獲取客戶端的輸入流,
④: 創建一個File對象,並指定客戶端傳輸過來的數據存放的位置,如果不存在該文件就自動創建
⑤: 開始從流中讀取數據,並存放在byte數組緩沖區中,在客戶端的輸出流未寫入之前此方法一直處於阻塞狀態(即等待狀態)
⑥: 開始寫入服務器本地文件
Client.java ,當做一個客戶端
public class Client { public static void main(String[] args) throws Exception { Socket s = new Socket("127.0.0.1", 10001); // ① InputStream is = new FileInputStream("D:/hehe.java"); // ② byte[] buf = new byte[1024]; int len = 0; while((len = is.read(buf))!=-1){ s.getOutputStream().write(buf,0,len); // ③ } s.shutdownOutput(); // ④ System.out.println("讀取完畢"); is.close(); } }
①: 創建 Socket 對象,傳入要連接服務器的 IP 和 端口
②: 創建一個輸入流對象讀取要上傳的文件路徑
③: 獲取 Socket 輸出流對象並將讀取到的數據寫入輸出流中
④: 任何以前寫入的數據都將被發送,如果不調用這個方法,那么在服務器端就不會知道數據已經傳輸完畢,將繼續調用此 Socket 輸入流的 read 方法,那么此時客戶端只是一個Java程序,已經執行完畢,虛擬機將釋放資源,這時,此Socket已經被 close掉,程序將拋出 SocketException 異常。
Serivce.java ,服務器
public class Service{ public static void main(String[] args)throws Exception{ ServerSocket ss = new ServerSocket(10001); // ① while(true){ Socket s = ss.accept(); // ② new Thread(new ServiceThread(s)).start(); // ③ } } }
①: 創建服務器對象,指定該服務器的端口號
②: 獲得請求連接到該服務器的客戶端對象Socket
③: 啟動服務器處理程序線程,因為程序是無限循環,所以每當一個客戶端連接進來都會創建一個新的線程
The End。。。。。