Java中TCP通信的實現(xiàn)方法詳解
0、TCP通信
傳輸控制協(xié)議(TCP,Transmission Control Protocol)是一種面向連接的、可靠的、基于字節(jié)流的傳輸層通信協(xié)議,
如果使用了 WireShark 工具,可以看到一次TCP連接建立時的整個過程。
1、單向通信
單向通信中,一方固定為信息發(fā)送方,另外一方則固定為信息的接收方。
1.1 單向通信中的服務(wù)端
服務(wù)端即為信息的接收方。
使用 ServerSocket 類創(chuàng)建服務(wù)端,并將服務(wù)的端口設(shè)置為 9527;
serverSocket.accept() 方法用于監(jiān)聽對 9527 端口的連接,該方法為阻塞式方法,當(dāng)接收到數(shù)據(jù)后,程序才會繼續(xù)向下執(zhí)行,否則一直處于等待狀態(tài);
當(dāng)接收到數(shù)據(jù)后,因是使用字節(jié)流傳輸,這里使用 使用 InputStreamReader 的轉(zhuǎn)換流將字節(jié)數(shù)據(jù)轉(zhuǎn)換為字符串,并使用 BufferedReader 進(jìn)行讀取和輸出;
當(dāng)服務(wù)端接收到客戶端的請求后,需要向客戶端發(fā)出響應(yīng)數(shù)據(jù),使用 PrintWriter 發(fā)送響應(yīng)報文,需要使用 flush() 方法,將消息發(fā)出;
當(dāng)客戶端發(fā)出的消息為“再見”時,服務(wù)端即退出通信,關(guān)閉服務(wù)。
import java.io.*; import java.net.ServerSocket; import java.net.Socket; public class Server { public static void main(String[] args) { System.out.println("服務(wù)器啟動!"); try { ServerSocket serverSocket = new ServerSocket(9527); Socket socket = serverSocket.accept(); BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintWriter pw = new PrintWriter(socket.getOutputStream()); System.out.println("接收客戶端消息"); while (true){ String in = br.readLine(); System.out.println("接收到客戶端發(fā)來的請求:" + in); if("再見".equals(in)){ break; } pw.print(in + "回報"); pw.flush(); } } catch (IOException e) { System.out.println("服務(wù)啟動失?。?); e.printStackTrace(); } } }
啟動后,服務(wù)端輸出為:
服務(wù)器啟動!
1.2 單向通信中的客戶端
客戶端即為信息的發(fā)送方。
- 創(chuàng)建 Socket 對象,?
?Socket("localhost", 9527)?
? 和端口為 9527 的服務(wù)建立通信; - 接收和發(fā)送消息的方法,和服務(wù)端相同;
- 為了能夠向服務(wù)端循環(huán)發(fā)送消息,使用了死循環(huán),當(dāng)用戶輸入“再見”時,終止循環(huán);
- 使用 Scanner 對象接收鍵盤輸入。
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; import java.util.Scanner; public class Client { public static void main(String[] args) { try { Socket socket = new Socket("localhost", 9527); //讀取輸入流 BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); //獲取輸出流 PrintWriter pw = new PrintWriter(socket.getOutputStream()); //從鍵盤獲取輸入 Scanner scanner = new Scanner(System.in); while (true){ //從控制臺獲取向服務(wù)端發(fā)送的消息 String next = scanner.next(); pw.println(next); pw.flush(); String s = br.readLine(); System.out.println("收到服務(wù)器響應(yīng):" + s); if("再見".equals(next)){ break; } } } catch (IOException e) { e.printStackTrace(); } } }
1.3 建立通信
啟動客戶端后,并在客戶端的控制臺輸入“你好”,觀察服務(wù)端和客戶端的控制臺
在客戶端的控制臺輸入“再見”,觀察服務(wù)端和客戶端的控制臺
2、雙向通信
雙向通信中,雙方都可以既是信息的發(fā)送方,也可以是信息的接收方。
2.1 雙向通信中的服務(wù)端
在服務(wù)端設(shè)置發(fā)消息和收消息。
在服務(wù)端也使用了 Scanner ,用來接收控制臺輸入,并將其發(fā)送給客戶端。
import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.Scanner; public class Server { public static void main(String[] args) { try{ ServerSocket serverSocket = new ServerSocket(9528); Socket socket = serverSocket.accept(); //獲取客戶端請求 BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); //獲取鍵盤輸入 Scanner scanner = new Scanner(System.in); //發(fā)送消息到客戶端 PrintWriter pw = new PrintWriter(socket.getOutputStream()); while (true){ String input = br.readLine(); System.out.println("收到客戶端請求: " + input); String output = scanner.nextLine(); pw.println(output); pw.flush(); if("再見".equals(input)){ break; } } }catch (Exception e){ e.printStackTrace(); System.out.println("服務(wù)啟動失敗!"); } } }
2.2 雙向通信中的客戶端
在客戶端設(shè)置發(fā)消息和收消息
import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; import java.util.Scanner; public class Client { public static void main(String[] args) { try{ Socket socket = new Socket("127.0.0.1", 9528); //獲取服務(wù)端響應(yīng) BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); //獲取客戶端用戶輸入 Scanner scanner = new Scanner(System.in); //向服務(wù)端發(fā)送請求 PrintWriter pw = new PrintWriter(socket.getOutputStream()); System.out.println("準(zhǔn)備接收請求……"); while (true){ String output = scanner.next(); pw.println(output); pw.flush(); String input = br.readLine(); System.out.println("來自服務(wù)端的響應(yīng): " + input); if("再見".equals(output)){ break; } } }catch (Exception e){ e.printStackTrace(); } } }
2.3 建議通信
啟動服務(wù)端及客戶端,并在控制臺輸入內(nèi)容:
存在的問題:
這樣的通信,需要客戶端發(fā)一次消息 -》 服務(wù)端回一次消息,如果客戶端同時發(fā)送兩條消息,就會導(dǎo)致消息不同步。
比如下邊的情況:
這個問題可以先思考下,應(yīng)該如何解決,后邊將會給出解決方案。
總結(jié)
到此這篇關(guān)于Java中TCP通信的實現(xiàn)方法的文章就介紹到這了,更多相關(guān)Java TCP通信實現(xiàn)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java commons-httpclient如果實現(xiàn)get及post請求
這篇文章主要介紹了Java commons-httpclient如果實現(xiàn)get及post請求,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-09-09java開發(fā)分布式服務(wù)框架Dubbo服務(wù)引用過程詳解
這篇文章主要為大家介紹了java開發(fā)分布式服務(wù)框架Dubbo服務(wù)引用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2021-11-11JAVA調(diào)用Deepseek的api完成基本對話簡單代碼示例
這篇文章主要介紹了JAVA調(diào)用Deepseek的api完成基本對話的相關(guān)資料,文中詳細(xì)講解了如何獲取DeepSeek?API密鑰、添加HTTP客戶端依賴、創(chuàng)建HTTP請求并使用示例代碼來對接DeepSeek?API,需要的朋友可以參考下2025-02-02