1、首先先來看下基於TCP協議Socket服務端和客戶端的通信模型:
Socket通信步驟:(簡單分為4步)
1.建立服務端ServerSocket和客戶端Socket
2.打開連接到Socket的輸出輸入流
3.按照協議進行讀寫操作
4.關閉相對應的資源
2、相關聯的API:
1.首先先來看下ServerSocket
類 ServerSocket
此類實現服務器套接字。服務器套接字等待請求通過網絡傳入。它基於該請求執行某些操作,然后可能向請求者返回結果。
服務器套接字的實際工作由 SocketImpl
類的實例執行。應用程序可以更改創建套接字實現的套接字工廠來配置它自身,從而創建適合本地防火牆的套接字。
一些重要的方法:(具體大家查看官方api吧)
ServerSocket(int port, int backlog)
利用指定的 backlog 創建服務器套接字並將其綁定到指定的本地端口號。
bind(SocketAddress endpoint, int backlog)
將 ServerSocket
綁定到特定地址(IP 地址和端口號)。
accept()
偵聽並接受到此套接字的連接
getInetAddress()
返回此服務器套接字的本地地址。
close()
關閉此套接字。
2.再來看下Socket
類 Socket
此類實現客戶端套接字(也可以就叫“套接字”)。套接字是兩台機器間通信的端點。
套接字的實際工作由 SocketImpl
類的實例執行。應用程序通過更改創建套接字實現的套接字工廠可以配置它自身,以創建適合本地防火牆的套接字。
一些重要的方法:(具體大家查看官方api吧)
Socket(InetAddress address, int port)
創建一個流套接字並將其連接到指定 IP 地址的指定端口號。
getInetAddress()
返回套接字連接的地址。
shutdownInput()
此套接字的輸入流置於“流的末尾”。
shutdownOutput()
禁用此套接字的輸出流。
close()
關閉此套接字。
3、代碼實現:(注釋很全,這里就不詳細多說了)
服務端Server.java
1.創建ServerSocket對象,綁定並監聽端口
2.通過accept監聽客戶端的請求
3.建立連接后,通過輸出輸入流進行讀寫操作
4.關閉相關資源
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; public class Server { /** * Socket服務端 */ public static void main(String[] args) { try { ServerSocket serverSocket=new ServerSocket(8888); System.out.println("服務端已啟動,等待客戶端連接.."); Socket socket=serverSocket.accept();//偵聽並接受到此套接字的連接,返回一個Socket對象 //根據輸入輸出流和客戶端連接 InputStream inputStream=socket.getInputStream();//得到一個輸入流,接收客戶端傳遞的信息 InputStreamReader inputStreamReader=new InputStreamReader(inputStream);//提高效率,將自己字節流轉為字符流 BufferedReader bufferedReader=new BufferedReader(inputStreamReader);//加入緩沖區 String temp=null; String info=""; while((temp=bufferedReader.readLine())!=null){ info+=temp; System.out.println("已接收到客戶端連接"); System.out.println("服務端接收到客戶端信息:"+info+",當前客戶端ip為:"+socket.getInetAddress().getHostAddress()); } OutputStream outputStream=socket.getOutputStream();//獲取一個輸出流,向服務端發送信息 PrintWriter printWriter=new PrintWriter(outputStream);//將輸出流包裝成打印流 printWriter.print("你好,服務端已接收到您的信息"); printWriter.flush(); socket.shutdownOutput();//關閉輸出流 //關閉相對應的資源 printWriter.close(); outputStream.close(); bufferedReader.close(); inputStream.close(); socket.close(); } catch (IOException e) { e.printStackTrace(); } } }
客戶端Client.java
1.創建Socket對象,指定服務端的地址和端口號
2.建立連接后,通過輸出輸入流進行讀寫操作
3.通過輸出輸入流獲取服務器返回信息
4.關閉相關資源
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintWriter; import java.net.Socket; import java.net.UnknownHostException; public class Client { /** * Socket客戶端 */ public static void main(String[] args) { try { //創建Socket對象 Socket socket=new Socket("localhost",8888); //根據輸入輸出流和服務端連接 OutputStream outputStream=socket.getOutputStream();//獲取一個輸出流,向服務端發送信息 PrintWriter printWriter=new PrintWriter(outputStream);//將輸出流包裝成打印流 printWriter.print("服務端你好,我是Balla_兔子"); printWriter.flush(); socket.shutdownOutput();//關閉輸出流 InputStream inputStream=socket.getInputStream();//獲取一個輸入流,接收服務端的信息 InputStreamReader inputStreamReader=new InputStreamReader(inputStream);//包裝成字符流,提高效率 BufferedReader bufferedReader=new BufferedReader(inputStreamReader);//緩沖區 String info=""; String temp=null;//臨時變量 while((temp=bufferedReader.readLine())!=null){ info+=temp; System.out.println("客戶端接收服務端發送信息:"+info); } //關閉相對應的資源 bufferedReader.close(); inputStream.close(); printWriter.close(); outputStream.close(); socket.close(); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
4、效果截圖:
服務端:
客戶端:
以上代碼實現了單客戶端和服務端的連接,若要實現多客戶端操作,需要涉及到多線程,只要你把每個接收到的Socket對象單獨開一條線程操作,然后用一個死循環while(true)去監聽端口就行,這邊直接給代碼了

線程操作類:SocketThread.java
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintWriter; import java.net.Socket; /** * Socket多線程處理類 用來處理服務端接收到的客戶端請求(處理Socket對象) */ public class SocketThread extends Thread { private Socket socket; public SocketThread(Socket socket) { this.socket = socket; } public void run() { // 根據輸入輸出流和客戶端連接 try { InputStream inputStream = socket.getInputStream(); // 得到一個輸入流,接收客戶端傳遞的信息 InputStreamReader inputStreamReader = new InputStreamReader( inputStream);// 提高效率,將自己字節流轉為字符流 BufferedReader bufferedReader = new BufferedReader( inputStreamReader);// 加入緩沖區 String temp = null; String info = ""; while ((temp = bufferedReader.readLine()) != null) { info += temp; System.out.println("已接收到客戶端連接"); System.out.println("服務端接收到客戶端信息:" + info + ",當前客戶端ip為:" + socket.getInetAddress().getHostAddress()); } OutputStream outputStream = socket.getOutputStream();// 獲取一個輸出流,向服務端發送信息 PrintWriter printWriter = new PrintWriter(outputStream);// 將輸出流包裝成打印流 printWriter.print("你好,服務端已接收到您的信息"); printWriter.flush(); socket.shutdownOutput();// 關閉輸出流 // 關閉相對應的資源 bufferedReader.close(); inputStream.close(); printWriter.close(); outputStream.close(); } catch (IOException e) { e.printStackTrace(); } } }
服務端類:Server.java
import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; public class Server { /** * Socket服務端 */ public static void main(String[] args) { try { ServerSocket serverSocket = new ServerSocket(8888); System.out.println("服務端已啟動,等待客戶端連接.."); while (true) { Socket socket = serverSocket.accept();// 偵聽並接受到此套接字的連接,返回一個Socket對象 SocketThread socketThread = new SocketThread(socket); socketThread.start(); } } catch (IOException e) { e.printStackTrace(); } } }
客戶端類:Client.java
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintWriter; import java.net.Socket; import java.net.UnknownHostException; public class Client { /** * Socket客戶端 */ public static void main(String[] args) { try { //創建Socket對象 Socket socket=new Socket("localhost",8888); //根據輸入輸出流和服務端連接 OutputStream outputStream=socket.getOutputStream();//獲取一個輸出流,向服務端發送信息 PrintWriter printWriter=new PrintWriter(outputStream);//將輸出流包裝成打印流 printWriter.print("服務端你好,我是客戶1"); printWriter.flush(); socket.shutdownOutput();//關閉輸出流 InputStream inputStream=socket.getInputStream();//獲取一個輸入流,接收服務端的信息 InputStreamReader inputStreamReader=new InputStreamReader(inputStream);//包裝成字符流,提高效率 BufferedReader bufferedReader=new BufferedReader(inputStreamReader);//緩沖區 String info=""; String temp=null;//臨時變量 while((temp=bufferedReader.readLine())!=null){ info+=temp; System.out.println("客戶端接收服務端發送信息:"+info); } //關閉相對應的資源 bufferedReader.close(); inputStream.close(); printWriter.close(); outputStream.close(); socket.close(); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
看下效果實現圖:
這里只是拋磚引玉,在實際開發中,基於Socket編程,一般傳遞的並非字符串,很多情況下是對象,我們可以使用ObjectOutputStream將輸出流對象序列化。
例如:
OutputStream outputStream = socket.getOutputStream(); ObjectOutputStream objectOutputStream=new ObjectOutputStream(outputStream); User user=new User("admin","123456"); objectOutputStream.writeObject(user);