Java中TCP通信的實(shí)現(xiàn)方法詳解
0、TCP通信
傳輸控制協(xié)議(TCP,Transmission Control Protocol)是一種面向連接的、可靠的、基于字節(jié)流的傳輸層通信協(xié)議,

如果使用了 WireShark 工具,可以看到一次TCP連接建立時(shí)的整個(gè)過(guò)程。

1、單向通信
單向通信中,一方固定為信息發(fā)送方,另外一方則固定為信息的接收方。
1.1 單向通信中的服務(wù)端
服務(wù)端即為信息的接收方。
使用 ServerSocket 類創(chuàng)建服務(wù)端,并將服務(wù)的端口設(shè)置為 9527;
serverSocket.accept() 方法用于監(jiān)聽(tīng)對(duì) 9527 端口的連接,該方法為阻塞式方法,當(dāng)接收到數(shù)據(jù)后,程序才會(huì)繼續(xù)向下執(zhí)行,否則一直處于等待狀態(tài);
當(dāng)接收到數(shù)據(jù)后,因是使用字節(jié)流傳輸,這里使用 使用 InputStreamReader 的轉(zhuǎn)換流將字節(jié)數(shù)據(jù)轉(zhuǎn)換為字符串,并使用 BufferedReader 進(jìn)行讀取和輸出;
當(dāng)服務(wù)端接收到客戶端的請(qǐng)求后,需要向客戶端發(fā)出響應(yīng)數(shù)據(jù),使用 PrintWriter 發(fā)送響應(yīng)報(bào)文,需要使用 flush() 方法,將消息發(fā)出;
當(dāng)客戶端發(fā)出的消息為“再見(jiàn)”時(shí),服務(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ù)器啟動(dòng)!");
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ā)來(lái)的請(qǐng)求:" + in);
if("再見(jiàn)".equals(in)){
break;
}
pw.print(in + "回報(bào)");
pw.flush();
}
} catch (IOException e) {
System.out.println("服務(wù)啟動(dòng)失?。?);
e.printStackTrace();
}
}
}啟動(dòng)后,服務(wù)端輸出為:
服務(wù)器啟動(dòng)!
1.2 單向通信中的客戶端
客戶端即為信息的發(fā)送方。
- 創(chuàng)建 Socket 對(duì)象,?
?Socket("localhost", 9527)?? 和端口為 9527 的服務(wù)建立通信; - 接收和發(fā)送消息的方法,和服務(wù)端相同;
- 為了能夠向服務(wù)端循環(huán)發(fā)送消息,使用了死循環(huán),當(dāng)用戶輸入“再見(jiàn)”時(shí),終止循環(huán);
- 使用 Scanner 對(duì)象接收鍵盤輸入。
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){
//從控制臺(tái)獲取向服務(wù)端發(fā)送的消息
String next = scanner.next();
pw.println(next);
pw.flush();
String s = br.readLine();
System.out.println("收到服務(wù)器響應(yīng):" + s);
if("再見(jiàn)".equals(next)){
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}1.3 建立通信
啟動(dòng)客戶端后,并在客戶端的控制臺(tái)輸入“你好”,觀察服務(wù)端和客戶端的控制臺(tái)

在客戶端的控制臺(tái)輸入“再見(jiàn)”,觀察服務(wù)端和客戶端的控制臺(tái)

2、雙向通信
雙向通信中,雙方都可以既是信息的發(fā)送方,也可以是信息的接收方。
2.1 雙向通信中的服務(wù)端
在服務(wù)端設(shè)置發(fā)消息和收消息。
在服務(wù)端也使用了 Scanner ,用來(lái)接收控制臺(tái)輸入,并將其發(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();
//獲取客戶端請(qǐng)求
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("收到客戶端請(qǐng)求: " + input);
String output = scanner.nextLine();
pw.println(output);
pw.flush();
if("再見(jiàn)".equals(input)){
break;
}
}
}catch (Exception e){
e.printStackTrace();
System.out.println("服務(wù)啟動(dòng)失??!");
}
}
}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ā)送請(qǐng)求
PrintWriter pw = new PrintWriter(socket.getOutputStream());
System.out.println("準(zhǔn)備接收請(qǐng)求……");
while (true){
String output = scanner.next();
pw.println(output);
pw.flush();
String input = br.readLine();
System.out.println("來(lái)自服務(wù)端的響應(yīng): " + input);
if("再見(jiàn)".equals(output)){
break;
}
}
}catch (Exception e){
e.printStackTrace();
}
}
}2.3 建議通信
啟動(dòng)服務(wù)端及客戶端,并在控制臺(tái)輸入內(nèi)容:

存在的問(wèn)題:
這樣的通信,需要客戶端發(fā)一次消息 -》 服務(wù)端回一次消息,如果客戶端同時(shí)發(fā)送兩條消息,就會(huì)導(dǎo)致消息不同步。
比如下邊的情況:

這個(gè)問(wèn)題可以先思考下,應(yīng)該如何解決,后邊將會(huì)給出解決方案。
總結(jié)
到此這篇關(guān)于Java中TCP通信的實(shí)現(xiàn)方法的文章就介紹到這了,更多相關(guān)Java TCP通信實(shí)現(xiàn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MyBatis攔截器實(shí)現(xiàn)分頁(yè)功能實(shí)例
本篇文章主要介紹了MyBatis攔截器實(shí)現(xiàn)分頁(yè)功能實(shí)例,這里整理了詳細(xì)的代碼,有需要的小伙伴可以參考下。2017-04-04
Java生成格式化的Word統(tǒng)計(jì)報(bào)告
這篇文章主要為大家詳細(xì)介紹了如何使用Java從數(shù)據(jù)庫(kù)查詢圖書數(shù)據(jù),并生成格式化的Word統(tǒng)計(jì)報(bào)告,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以參考一下2025-04-04
詳解json在SpringBoot中的格式轉(zhuǎn)換
這篇文章主要介紹了詳解json在SpringBoot中的格式轉(zhuǎn)換,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11
Java中實(shí)現(xiàn)在一個(gè)方法中調(diào)用另一個(gè)方法
下面小編就為大家分享一篇Java中實(shí)現(xiàn)在一個(gè)方法中調(diào)用另一個(gè)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-02-02
Spring的@Validation和javax包下的@Valid區(qū)別以及自定義校驗(yàn)注解
這篇文章主要介紹了Spring的@Validation和javax包下的@Valid區(qū)別以及自定義校驗(yàn)注解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01
java實(shí)現(xiàn)微信公眾號(hào)消息推送的方法詳解
這篇文章主要為大家詳細(xì)介紹了如何利用java實(shí)現(xiàn)微信公眾號(hào)消息推送的功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-10-10

