網絡編程 04:TCP連接,客戶端與服務器的區別,實現 TCP 聊天及文件上傳,Tomcat 的簡單使用

一、概述

記錄時間 [2025-08-29]

前置文章

網絡編程 01:計算機網絡概述,網絡的作用,網絡通信的要素,以及網絡通信協議與分層模型

網絡編程 02:IP 地址,IP 地址的作用、分類,通過 Java 實現 IP 地址的信息獲取

網絡編程 03:端口的定義、分類,端口映射,通過 Java 實現了 IP 和端口的信息獲取

本文講述網絡編程相關知識——TCP連接,包括客戶端與服務器的區別,如何實現 TCP 聊天及文件上傳等。

同時,文章簡單介紹了 Tomcat(服務器)的相關使用。


關于創作紀念日

維持現狀。512 紀念日快樂。

里程碑專區



二、TCP

1. TCP 聊天

思路整理

客戶端和服務器之間如何進行通信——創建連接 + 收發消息。

客戶端

  • 連接服務器 Socket
  • 發送消息

服務器

  • 建立服務的端口 ServerSocket
  • 等待用戶的連接 accept
  • 接收用戶消息

客戶端和服務器之間收發消息通過 I/O 流來實現。

  • 發送消息,socket.getOutputStream()
  • 接收消息,socket.getInputStream()

為防止接收消息亂碼,接收方需要使用管道流來處理接收到的消息。

  • new ByteArrayOutputStream()

所有資源在使用后都需要正確關閉,如,socket,serverSocket 等。

  • 關閉資源的順序為:先開后關
  • 關閉資源前要先判斷它是否為空,非空則關閉;
  • 關閉資源操作需要拋出異常。

服務器代碼實現

服務器先啟動,處在監聽過程中,等待客戶端的連接。

服務器有一個地址(IP + Port),通過這個地址,客戶端才能和服務器連接。

通過 serverSocket.accept() 獲取連接過來的客戶端,就是客戶端的 socket

然后讀取客戶端的信息。

經過管道處理后,輸出信息。

結束后關閉資源。


import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;// 服務端
public class TcpServerDemo01 {public static void main(String[] args) {// 服務端地址ServerSocket serverSocket = null;// 連接過來的客戶端Socket socket = null;// 輸入流InputStream is = null;// 管道流ByteArrayOutputStream baos = null;try {// 1. 我得有一個地址serverSocket = new ServerSocket(9999);// 循環等待客戶端連接過來while (true) {// 2. 等待客戶端連接過來socket = serverSocket.accept();// 3. 讀取客戶端的消息// 消息從客戶端流出 Out,流進服務器 Inputis = socket.getInputStream();// 管道流// 給流進來的消息套一個管道,得到從管道中流出來的消息,所有用 Outputbaos = new ByteArrayOutputStream();byte[] buffer = new byte[1024];int len;while ((len = is.read(buffer)) != -1) {baos.write(buffer, 0, len);}System.out.println(baos.toString());}} catch (IOException e) {e.printStackTrace();} finally {// 4. 關閉資源, 判非空, 然后先開后關// null 了就沒必要關了if (baos != null) {try {baos.close();} catch (IOException e) {e.printStackTrace();}}if (is != null) {try {is.close();} catch (IOException e) {e.printStackTrace();}}if (socket != null) {try {socket.close();} catch (IOException e) {e.printStackTrace();}}if (serverSocket != null) {try {serverSocket.close();} catch (IOException e) {e.printStackTrace();}}}}
}

客戶端代碼實現

客戶端通過服務器的地址(IP + Port)連接上服務器,連接的方式是 socket

客戶端給服務器發消息。

結束后關閉資源。


import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;// 客戶端
public class TcpClientDemo01 {public static void main(String[] args) {// 客戶端連接Socket socket = null;// 輸出流OutputStream os =  null;try {// 1. 要知道服務器的地址, 端口號InetAddress serverIP = InetAddress.getByName("127.0.0.1");int port = 9999;// 2. 創建一個 socket 連接socket = new Socket(serverIP, port);// 3. 發送 IO 消息流os = socket.getOutputStream();os.write("你好,歡迎".getBytes());} catch (Exception e) {e.printStackTrace();} finally {// 4. 關閉資源, 判非空, 然后先開后關if (os != null) {try {os.close();} catch (IOException e) {e.printStackTrace();}}if (socket != null) {try {socket.close();} catch (IOException e) {e.printStackTrace();}}}}
}

2. TCP 文件上傳

文件流,流的概念

客戶端給服務端傳文件:

  • 文件通過文件管道流出:客戶端中,先流入(In)文件管道,再流出(Out)去到服務端。
  • 文件流入(In)服務端,流入要讀(read);服務端用文件管道流出(Out),流出要寫(write), 就是保存。

就相當于客戶端流出,到服務端流入,然后它們自己可以套管道,管道一頭流入,另一頭流出。


流入要讀(read), 流出要寫(write)

while ((len = fis.read(buffer)) != -1) {os.write(buffer, 0, len);
}

工作目錄

當我們要讀取一個文件時,得先知道該文件的位置,也就是文件路徑。

new File("file"):獲取項目文件的方法,需要傳入的參數是文件路徑,如果是相對路徑的話,起始路徑為當前 Java 項目的工作目錄。

在項目中有一個圖片資源,如何獲取這個圖片的相對路徑呢?需要通過 Java 項目的工作目錄。


獲取當前 Java 項目的工作目錄的方式:

public class TestPath {public static void main(String[] args) {String currentDir = System.getProperty("user.dir");System.out.println("當前工作目錄: " + currentDir);}
}

例如:

當前工作目錄為:C:\JavaSE

NetStudyJavaSE 項目中的一個模塊,圖片資源 tx.jpg 位于 JavaSE/NetStudy 目錄下;

那么 tx.jpg 的獲取方式是:new File("NetStudy/tx.jpg")


服務器代碼實現

服務器監聽、等待客戶端的連接。

接收客戶端發送過來的文件,通過文件管道流處理后,保存文件。(這里的文件是一張圖片)

通知客戶端,文件接收完成。

結束后關閉資源。


import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;// 服務端
public class TcpServerDemo02 {public static void main(String[] args) throws Exception {// 1. 創建服務, 給出連接的端口ServerSocket serverSocket = new ServerSocket(9000);// 2. 監聽客戶端的連接// 一直等待, 會阻塞直到有客戶端連接// 這個 socket 就是客戶端的 socketSocket socket = serverSocket.accept();// 3. 獲取輸入流// 創建一個輸入流,用來輸入客戶端的流InputStream is = socket.getInputStream();// 4. 文件輸出, 接收客戶端的文件// 用文件管道流寫出文件, 給出文件保存到位置和文件名FileOutputStream fos = new FileOutputStream(new File("NetStudy/receive.jpg"));byte[] buffer = new byte[1024];int len;while ((len = is.read(buffer)) != -1) {fos.write(buffer, 0, len);}// 5. 通知客戶端, 文件接收完成// 創建一個輸出流, 用來輸出給客戶端OutputStream os = socket.getOutputStream();// 傳信息給客戶端os.write("文件已被服務端接收完成".getBytes());// 6. 關閉資源os.close();fos.close();is.close();socket.close();serverSocket.close();}
}

客戶端代碼實現

文件先通過文件管道流讀入項目里,然后才能通過 socket 發送。

建立 socket 連接后,向服務器發送文件。

文件發送完畢后,結束輸出流,并告知服務器。(因為服務器和客戶端用的是同一個 socket,如果文件發送完不結束流的話,會影響后面的消息發送和接收)

接收服務器發送的 “完成信號”。

結束后關閉資源。


import java.io.*;
import java.net.InetAddress;
import java.net.Socket;// 客戶端
public class TcpClientDemo02 {public static void main(String[] args) throws Exception {// 1. 建立服務端連接,ip+portSocket socket = new Socket(InetAddress.getByName("127.0.0.1"), 9000);// 2. 創建一個輸出流// 用來輸出給服務端OutputStream os = socket.getOutputStream();// 3. 傳文件給服務端// 讀取文件: 文件輸入流, 先把文件輸入管道,管道才能讀出來// System.getProperty("user.dir"); 獲取項目的工作目錄// 獲取 tx.jpg 的相對位置FileInputStream fis = new FileInputStream(new File("NetStudy/tx.jpg"));// 讀出文件管道流中的文件, 并向服務端寫出文件byte[] buffer = new byte[1024];int len;while ((len = fis.read(buffer)) != -1) {os.write(buffer, 0, len);}// 4. 通知服務端文件傳輸完畢socket.shutdownOutput();System.out.println("通知服務端文件傳輸完畢");// 5. 確定服務端接收完畢, 才能斷開連接// 收到服務端的完成信號后,斷開連接// 創建一個輸入流,用來接收服務端的流InputStream is = socket.getInputStream();// 用管道流寫出文件ByteArrayOutputStream baos = new ByteArrayOutputStream();byte[] buffer2 = new byte[1024];int len2;while ((len2 = is.read(buffer2)) != -1) {baos.write(buffer2, 0, len2);}// 輸出管道流里的內容System.out.println(baos.toString());// 6. 關閉資源baos.close();is.close();fis.close();os.close();socket.close();}
}


三、使用 Tomcat

在前面的 TCP 中,我們講到了客戶端與服務器(Client/Server),服務器就是用來接收客戶端的請求的。

而 Tomcat,就是一個充當服務器的角色。


1. 啟動 Tomcat

可以通過腳本啟動,雙擊 bin 目錄下的 startup.bat 即可。

默認在 8080 端口下啟動,啟動成功后可通過 localhost:8080 進行訪問。

如果端口被占用,則無法成功啟動。

在這里插入圖片描述


2. Tomcat 亂碼

Tomcat 啟動過程中會打印日志信息,不難發現,日志信息中存在亂碼現象

導致亂碼的原因:字符編碼在解碼過程中選擇了錯誤的解碼方式。

解碼規范 / 方式:GBK,UTF-8 等。

文件在計算機中是以字符編碼的形式存儲的,而我們平常看到文字是字符串形式的。這之間就有編碼和解碼兩個操作。

而 GBK 這類規范就是告訴計算機應該用何種方式進行編碼或解碼。


那么,如果一個文件是用 GBK 進行編碼的,卻使用 UTF-8 進行解碼,那么就會導致亂碼。正所謂 “解鈴還須系鈴人”,GBK 的編碼需要用 GBK 來解碼,UTF-8 同理。


conf 目錄下,有日志配置文件 logging.properties,在里面可以修改編碼 / 解碼方式。

  • CMD 選擇 GBK
  • IDEA 選擇 UTF-8

在這里插入圖片描述


在這里插入圖片描述


要解決 IDEA 控制臺亂碼,需要同時設置 JVM 加載 .class 文件時使用 UTF-8 字符集。

-Dfile.encoding=UTF-8

在這里插入圖片描述


3. Tomcat 訪問部署的資源

啟動 Tomcat 后,可以訪問其部署的資源,在 webapps 目錄下。

訪問根目錄:localhost:8080

訪問自定義資源:webapps 目錄下的 test 中的 hello.txt 文件。


http://localhost:8080/test/hello.txt


參考資料

狂神說 - 網絡編程:https://www.bilibili.com/video/BV1LJ411z7vY

Java 8 幫助文檔:https://docs.oracle.com/javase/8/docs/api/

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/94947.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/94947.shtml
英文地址,請注明出處:http://en.pswp.cn/web/94947.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

最小生成樹——Kruskal

標題什么是生成樹? 對于一張無向圖,由nnn個頂點和n?1n-1n?1條邊構成地聯通子圖,叫做這個無向圖 生成樹 最小生成樹就是指邊權之和最小的生成樹 如何求最小生成樹? Kruskal 介紹: 存圖時只存每條邊地起點、終點,…

ADFS 和 OAuth 的區別

ADFS 和 OAuth 的區別 ADFS(Active Directory Federation Services)和 OAuth 都是身份認證與授權領域的技術,但它們的設計目標、應用場景和實現方式有顯著區別。以下從核心定義、技術特性、應用場景等方面詳細對比: 核心定義與設計目標 技術 核心定義 設計目標 ADFS 微軟…

神經網絡參數量計算詳解

1. 神經網絡參數量計算基本原理 1.1 什么是神經網絡參數 神經網絡的參數主要包括: 權重(Weights):連接不同神經元之間的權重矩陣偏置(Bias):每個神經元的偏置項批歸一化參數:BatchNo…

手寫鏈路追蹤

1. 什么是鏈路追蹤 鏈路追蹤是指在分布式系統中,將一次請求的處理過程進行記錄并聚合展示的一種方法。目的是將一次分布式請求的調用情況集中在一處展示,如各個服務節點上的耗時、請求具體到達哪臺機器上、每個服務節點的請求狀態等。這樣就可以輕松了解…

從零開始的python學習——常量與變量

? ? ? ? ? づ?ど 🎉 歡迎點贊支持🎉 個人主頁:勵志不掉頭發的內向程序員; 專欄主頁:python學習專欄; 文章目錄 前言 一、常量和表達式 二、變量類型 2.1、什么是變量 2.2、變量語法 (1&a…

基于51單片機環境監測設計 光照 PM2.5粉塵 溫濕度 2.4G無線通信

1 系統功能介紹 本設計是一套 基于51單片機的環境監測系統,能夠實時采集環境光照、PM2.5、溫濕度等參數,并通過 2.4G無線模塊 NRF24L01 實現數據傳輸。系統具備本地顯示與報警功能,可通過按鍵設置各類閾值和時間,方便用戶進行環境…

【Flask】測試平臺開發,產品管理實現添加功能-第五篇

概述在前面的幾篇開發文章中,我們只是讓數據在界面上進行了展示,但是沒有添加按鈕的功能,接下來我們需要開發一個添加的按鈕,用戶產品功能的創建和添加抽公共數據鏈接方法添加接口掌握post實現和請求數據處理前端掌握Button\Dilog…

循環高級(2)

6.練習3 打印九九乘法表7.練習3 制表符詳解對齊不了原因:name補到8zhangsan本身就是8,補完就變成16解決辦法:1.去掉zhangsan\t,這樣前后都是82.name后面加2個\t加一個\t,name\t就是占8個,再加一個\t,就變成…

盒馬生鮮 小程序 逆向分析

聲明 本文章中所有內容僅供學習交流使用,不用于其他任何目的,抓包內容、敏感網址、數據接口等均已做脫敏處理,嚴禁用于商業用途和非法用途,否則由此產生的一切后果均與作者無關! 逆向分析 部分python代碼 params {&…

【Linux系統】線程控制

1. POSIX線程庫 (pthreads)POSIX線程(通常稱為pthreads)是IEEE制定的操作系統線程API標準。Linux系統通過glibc庫實現了這個標準,提供了創建和管理線程的一系列函數。核心特性命名約定:絕大多數函數都以 pthread_ 開頭&#xff0c…

【Spring Cloud Alibaba】前置知識

【Spring Cloud Alibaba】前置知識1. 微服務介紹1.1 系統架構的演變1.1.1 單體應用架構1.1.2 垂直應用架構1.1.3 分布式架構1.1.3.1 SOA架構1.1.4 微服務架構1. 微服務介紹 1.1 系統架構的演變 隨著互聯網的發展,網站應用的規模也在不斷的擴大,進而導致…

2025互聯網大廠Java面試1000道題目及參考答案

Java學到什么程度可以面試工作? 要達到能夠面試Java開發工作的水平,需要掌握以下幾個方面的知識和技能: 1. 基礎扎實:熟悉Java語法、面向對象編程概念、異常處理、I/O流等基礎知識。這是所有Java開發者必備的基礎,也…

記錄:HSD部署(未完成)

建數據庫 相關文檔:Confluence準備:CA文件和備份用的aws key。 CA文件:在namespace添加trust-injectionenabled的標簽,會自動生成。 aws key:生成cnpg-backup-creds的secret。安裝: 從git倉庫獲取values模…

【AI】提示詞與自然語言處理:從NLP視角看提示詞的作用機制

提示詞與自然語言處理:從 NLP 視角看提示詞的作用機制在人工智能快速發展的今天,大模型成為了人們關注的焦點。而要讓大模型更好地理解人類意圖、完成各種任務,提示詞扮演著關鍵角色。從自然語言處理(NLP)的角度來看&a…

2025.8.29機械臂實戰項目

好久沒給大家更新了,上周末大學大四開學,所以停更了幾天,回來后在做項目,接下來的幾篇文章,給大家帶來幾個項目,第一個介紹的是機械臂操作,說是機械臂操作,簡單來說,就是…

【機器學習基礎】機器學習的要素:任務T、性能度量P和經驗E

第一章 機器學習的本質與理論框架 機器學習作為人工智能領域的核心支柱,其理論基礎可以追溯到20世紀中葉的統計學習理論。Tom Mitchell在其1997年的經典著作《Machine Learning》中給出了一個至今仍被廣泛引用的學習定義:"對于某類任務T和性能度量P,一個計算機程序被認…

wav音頻轉C語言樣點數組

WAV to C Header Converter 將WAV音頻文件轉換為C語言頭文件的Python腳本,支持將音頻數據嵌入到C/C項目中。 功能特性 音頻格式支持 PCM格式:支持8位、16位、24位、32位PCM音頻IEEE Float格式:支持32位浮點音頻多聲道:支持單聲道、…

01.《基礎入門:了解網絡的基本概念》

網絡基礎 文章目錄網絡基礎網絡通信核心原理網絡通信定義信息傳遞過程關鍵術語解釋網絡的分類網絡參考模型OSI 參考模型各層核心工作分層核心原則TCP/IP 參考模型(4 層 / 5 層,實際應用模型)TCP/IP 與 OSI 模型的對應關系傳輸層核心協議&…

基于vue駕校管理系統的設計與實現5hl93(程序+源碼+數據庫+調試部署+開發環境)帶論文文檔1萬字以上,文末可獲取,系統界面在最后面。

系統程序文件列表:項目功能:學員,教練,教練信息,預約信息,場地信息,時間安排,車輛信息,預約練車,時間段,駕校場地信息,駕校車輛信息,預約報名開題報告內容:一、選題背景與意義背景隨著汽車保有量持續增長,駕校行業規模不斷擴大&am…

灰度思維:解鎖世界原有本色的密碼

摘要本文深入探討灰度思維的概念內涵及其在處理他人評價中的應用價值。研究指出,灰度思維作為一種超越非黑即白的思維方式,能夠幫助個體以更客觀、全面的態度接受他人評價的片面性,從而促進個人成長和人際關系和諧。文章分析了他人評價片面性…