點我跳過黑哥的卑鄙廣告行為,進入正文。
Java多線程系列更新中~
正式篇:
- Java多線程(一) 什么是線程
- Java多線程(二)關於多線程的CPU密集型和IO密集型這件事
- Java多線程(三)如何創建線程
- Java多線程(四)java中的Sleep方法
- Java多線程(五)線程的生命周期
番外篇(神TM番外篇):
Socket是客戶端和服務器端交流的端點。通過它可以實現客戶端和服務器端的通信。順着這篇文章操作下來,你應該會對Socket編程有比較系統的了解。注意,跟着敲代碼,有什么不懂而我又沒提到的地方,隨時百度,不要積累誤差。
客戶端編程
Socket是有連接的,所以雙方建立通信,需要知道彼此的網絡位置(IP和端口)。
創建Socket對象:
Socket socket = new Socket("127.0.0.1",8852);
- 第一個參數:服務器的IP地址(這里用的是本機地址)
- 第二個參數:TCP端口號,其中0~1023是系統保留端口。
為什么需要端口號?例如你想要去找你的暗戀對象告白,你知道她的學校地址(IP地址),但是一個學校不會只有你暗戀對象一個人(一個主機不會只進行一個任務),你需要知道她的宿舍號(端口號),這樣才能方便告白。
使用本機既做客戶端,又做服務器是個什么情況?就是你和你暗戀對象在同一個學校,這沒什么區別,你仍然需要她的宿舍號(端口號)才能找到她告白(客戶端和服務前通信)。
初始版本代碼
public class MyClient { public static void main(String[] args) throws Exception{ Socket socket = new Socket("127.0.0.1",8852); DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream()); dataOutputStream.writeUTF("Hello socket"); socket.close(); } }
注意別忘了拋出異常,這里只是個演示作用,直接throws Exception了。這里你直接運行肯定是不能建立連接的,因為服務器端還沒寫。
這里,假如你知道服務器監聽的是8852端口,你創建了一個socket來和它進行通信。socket.getOutputStream()得到這個socket的輸出流,當你調用writeUTF()方法時,便會向其中寫一個字符串。
典型三段式要牢記:打開、通信、關閉。
服務器端編程
注意了注意了,要開始造女票了。
初始版本代碼
import java.io.DataInputStream; import java.net.ServerSocket; import java.net.Socket; public class MyServer { public static void main(String[] args) throws Exception{ ServerSocket serverSocket = new ServerSocket(8852); System.out.println("Server 等待接收數據~"); Socket socket = serverSocket.accept(); DataInputStream dataInputStream = new DataInputStream(socket.getInputStream()); String string = dataInputStream.readUTF(); System.out.println(string); System.out.println("Server 接收數據完畢,拜拜了您~"); socket.close(); serverSocket.close(); } }
這里服務器端用到了ServerSocket,負責接收客戶端的連接請求。你的暗戀對象可能有好多人要向她告白,一個Socket自然無法處理。通過ServerSocket的accept方法從連接請求隊列中取出一個進行連接。那這個ServerSocket就是你暗戀對象的室友,幫助她管理諸多“告白”。
這里只是把服務器端接收到的數據打印了一下便關閉了。至此,一個簡單的服務器-客戶端通信便建立了。但是這個服務器只能處理一個連接便關閉了,我們可以改進一下。
往下看之前請確保你大致理解了上述過程,最好自己敲一下代碼
到這里你可能會想,只處理一個就關閉了,那我加個while循環,讓它一直運行怎么樣?
聽着還可以,那我們來試驗一下(下面只是分析一下,不用跟着敲)。
將服務器端代碼更改為:
while(true) { Socket socket = serverSocket.accept(); DataInputStream dataInputStream = new DataInputStream(socket.getInputStream()); String string = dataInputStream.readUTF(); System.out.println(string); socket.close(); serverSocket.close(); }
這個會出現什么問題?客戶端正連着呢,啪,你服務器給人家斷開了,而且accept()接受的是socket請求,所以這種情況,除非客戶端再連一次,否則二者的通信就斷了。
你可能會說,那我把Socket移到外面呢?
其實吧,這個仔細理一下就會明白,如果放到外面的話,只要你想接收多個socket,就要把
Socket socket = serverSocket.accept();放到while循環中,但是你只要把它放到while循環中,它就只能和一個socket進行通信。這里有興趣可以再查閱一下資料,下面直接進入線程階段。
服務器端線程代碼
import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; public class MyServer { public static void main(String[] args) throws Exception{ ServerSocket serverSocket = new ServerSocket(8852); System.out.println("Server 等待接收數據~"); while(true) { Socket socket = serverSocket.accept();
//這里來一個連接請求就讓deal去處理,自己在這里等下一個連接請求 deal(socket); } } public static void deal(Socket client){
//這里創建了一個新的線程 new Thread(new Runnable() { @Override public void run() { DataInputStream dataInputStream=null; DataOutputStream dataOutputStream = null; String receiveFromClient=""; try { dataInputStream = new DataInputStream(client.getInputStream()); dataOutputStream = new DataOutputStream(client.getOutputStream()); //只是這個線程中一直while循環,不影響其他的線程。 while(true) { receiveFromClient = dataInputStream.readUTF(); System.out.println("receive: "+receiveFromClient); if(receiveFromClient.equals("bye")) { dataOutputStream.writeUTF("終於厭倦我了嗎?客戶端都是大豬蹄子!!"); dataOutputStream.flush(); break; } else { dataOutputStream.writeUTF("你TM給我發 "+receiveFromClient+" 干什么?"); dataOutputStream.flush(); } } }catch (Exception e) { e.printStackTrace(); }finally { try { dataInputStream.close(); dataOutputStream.close(); client.close(); } catch (IOException e) { e.printStackTrace(); } } } }).start(); } }
客戶端代碼:
import java.io.BufferedReader; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.InputStreamReader; import java.net.Socket; public class MyClient { public static void main(String[] args) throws Exception{ Socket socket = new Socket("127.0.0.1",8852); DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream()); DataInputStream dataInputStream = new DataInputStream(socket.getInputStream()); BufferedReader bReader = new BufferedReader(new InputStreamReader(System.in)); String string; while(true) { string=bReader.readLine(); dataOutputStream.writeUTF(string); System.out.println(dataInputStream.readUTF()); dataOutputStream.flush(); if(string.equals("bye")) break; } socket.close(); } }
結果展示:
服務器端:
客戶端: