網絡編程——套接字

目錄

一、Socket套接字

(一)概念

(二)分類

1.流套接字:

2.數據報套接字

3.原始套接字

二、TCP協議VSUDP協議

(一)有連接VS無連接

(二)可靠傳輸VS不可靠傳輸

(三)面向字節流VS面向數據報

(四)全雙工VS半雙工

三、UDP協議中的socket api

(一)DatagramSocket類

(二)DatagramPacket類

(三)InetSocketAddress類

四、UDP協議的回顯服務器

(一)UdpEchoServer回顯服務器

(二)UdpEchoClient客戶端?

(三)拓展:英譯漢服務器?

五、TCP協議中的socket api

(一)ServerSocket類

(二)Socket類

六、TCP協議的回顯服務器

(一)TcpEchoServer回顯服務器

(二)TcpEchoClient客戶端


一、Socket套接字

(一)概念

Socket套接字,是有系統提供用于網絡通信的技術,是基于TCP/IP協議的網絡通信的基本操作單元。基于Socket套接字的網絡程序開發就是網絡編程。

(二)分類

1.流套接字:

使用傳輸層TCP協議,是以字節流的格式來通信的。對于字節流來說,可以簡單的理解為傳輸數據是基于IO流,流失數據的特征就是在IO流沒有關閉的情況下,是無邊界的數據,可以多次發送,也可以分開多次發送。

2.數據報套接字

使用傳輸層UDP協議,是以數據報的格式來通信的。對于數據報來說,可以簡單的理解為,傳輸數據是一塊一塊的,發送一塊數據假如100個字節,必須一次發送,接收也必須一次接收100個字節,而不能分100次,每次接收1個字節。

3.原始套接字

原始套接字用于自定義傳輸層協議,用于讀寫內核沒有處理的IP協議數據。

二、TCP協議VSUDP協議

TCP的特點:

  • 有連接
  • 可靠傳輸
  • 面向字節流
  • 全雙工

UDP的特點:

  • 無連接
  • 不可靠傳輸
  • 面向數據報
  • 全雙工

(一)有連接VS無連接

這是抽象的概念,指的是虛擬的/邏輯上的連接。

  • 對于TCP來說,TCP協議中,就保存了對端的信息:?A和B通信,A和B先建立連接,讓A保存B的信息,B保存A的信息(彼此之間知道要連接的是哪個)。
  • 對于UDP來說,UDP協議本身,不保存對方的信息,就是無連接。

(二)可靠傳輸VS不可靠傳輸

在網絡上,數據是非常容易出現丟失的情況的(丟包),光信號/電信號都可能受到外界的干擾。

在進行通信時,不能指望一個數據包100%地到達對方。

  • 可靠傳輸指的是,雖然不能保證數據包100%到達,但是能盡可能提高傳輸成功的概率。
  • 不可靠傳輸只是把數據發了,就不管了。

(三)面向字節流VS面向數據報

  • 面向字節流指的是在讀寫數據時,以字節為單位。
  • 面向數據報指的是讀寫數據時,以數據報為單位。

(四)全雙工VS半雙工

  • 全雙工指的是 一個通信鏈路中,支持雙向通信(能讀也能寫)。
  • 半雙工指的是 一個通信鏈路中,只支持單向通信(要么讀,要么寫)。

三、UDP協議中的socket api

計算機中的“文件”,是一個廣義的概念,文件還能代指一些硬件設備(操作系統管理硬件設備,也是抽象成文件,統一管理的)。

UDP協議是用來操作網卡的,將網卡抽象成socket文件,操作網卡的時候,流程和操作普通文件差不多。

(一)DatagramSocket類

DatagramSocket類是用來操作socket文件,發送和接收數據報的。

構造方法:

方法簽名方法說明
DatagramSocket()創建一個UDP數據報套接字的Socket,綁定到主機的任意一個隨機端口號(一般用于客戶端)。
DatagramSocket(int port)創建一個UDP數據報套接字的Socket,綁定到主機的一個指定的端口號(一般用于服務端)。

成員方法:?

方法簽名方法說明
void receive(DatagramPacket p)從此套接字接收數據報(如果沒有接受到數據報,該方法會阻塞等待)。
void send(DatagramPacket p)從此套接字發送數據報(不會阻塞等待,直接發送)。
void close()關閉此數據報套接字。

(二)DatagramPacket類

DatagramPacket就是UDP發送和接收的數據報。

構造方法:

方法簽名方法說明
DatagramPacket(byte[]buf,int length)構造一個DatagramPacket用來接收數據報,接收的數據報保存在字節數組中(第一個參數buf),接收的指定長度(第二個參數length)。
DatagramPacket(byte[]buf,int offset,int length,SocketAddress address)構造一個DatagramPacket用來接收數據報,接收的數據報保存在字節數組中(第一個參數buf),指定起點(第二個參數offset),接收的指定長度(第三個參數length)。address指定目的主機的IP和端口號。

成員方法:

方法簽名方法說明
InetAddress getAddress()從接收的數據報中,獲取發送端的主機IP地址;或從發送的數據報中,獲取接收端的主機IP地址。
int getPort()從接收的數據報中,獲取發送端的主機的端口號;或從發送的數據報中,獲取接收端的主機的端口號。
byte[] getData()獲取數據報中的數據。

(三)InetSocketAddress類

構造UDP發送的數據報時,需要傳入SocketAddress(父類),該對象可以使用InetSocketAddress(子類)來創建。

InetSocketAddress的構造方法:

方法簽名方法說明
InetSocketAddress(InetAddress addr,int port)創建一個Socket地址,包含IP地址和端口號

四、UDP協議的回顯服務器

Java數據報套接字通信模型:

(一)UdpEchoServer回顯服務器

package NetWork;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;//UDP協議的回顯服務器
//服務器端
public class UdpEchoServer {private DatagramSocket socket=null;//指定了一個固定端口號, 讓服務器來使用.public UdpEchoServer(int port) throws SocketException {socket=new DatagramSocket(port);}//啟動服務器public void start() throws IOException {System.out.println("服務器啟動");while(true){//循環一次,就相當于處理一次請求。//1.讀取請求并解析//創建請求數據報DatagramPacket RequestPacket=new DatagramPacket(new byte[4096],4096);//開始接收,并更新數據報socket.receive(RequestPacket);//2.根據請求, 計算響應. (服務器最關鍵的邏輯)//把讀取到的二進制數據, 轉成字符串. 只是構造有效的部分.String request=new String(RequestPacket.getData(),0, RequestPacket.getLength());String response=process(request);//3.把響應返回給客戶端//根據 response 構造 DatagramPacket, 發送給客戶端.//此處不能使用 response.length(),因為這是String的長度而不是byte數組的長度DatagramPacket ResponsePacket=new DatagramPacket(response.getBytes(),response.getBytes().length,RequestPacket.getSocketAddress());//發送構建好的數據報socket.send(ResponsePacket);//4.打印日志System.out.printf("[%s:%d] req: %s, resp: %s\n", RequestPacket.getAddress().toString(), RequestPacket.getPort(), request, response);}}//服務器根據請求,處理業務public String process(String request){return request;}public static void main(String[] args) throws IOException {UdpEchoServer server=new UdpEchoServer(9090);server.start();}}

(二)UdpEchoClient客戶端?

package NetWork;import java.io.IOException;
import java.net.*;
import java.util.Scanner;//UDP協議的回顯服務器
//客戶端
public class UdpEchoClient {DatagramSocket socket=null;// 客戶端要給服務器發送數據報,首先得知道服務器的IP和端口號private String ServerIp;//目的IPprivate int ServerPort;//目的端口號// 和服務器不同, 此處的構造方法是要指定訪問的服務器的地址.public UdpEchoClient(String serverIp, int serverPort) throws SocketException {this.ServerIp = serverIp;this.ServerPort = serverPort;socket = new DatagramSocket();}public void start() throws IOException {Scanner sc=new Scanner(System.in);while(true){// 1.讀取用戶輸入的內容System.out.println("請輸入要發送的內容:");if(!sc.hasNext()){break;}String request=sc.next();// 2. 把請求發送給服務器, 需要構造 DatagramPacket 對象.// 構造過程中, 不光要構造載荷, 還要設置服務器的 IP 和端口號DatagramPacket RequestPacket=new DatagramPacket(request.getBytes(),request.getBytes().length, InetAddress.getByName(ServerIp),ServerPort);// 3. 發送數據報socket.send(RequestPacket);// 4. 接收服務器的響應DatagramPacket ResponsePacket = new DatagramPacket(new byte[4096], 4096);socket.receive(ResponsePacket);// 5. 從服務器讀取的數據進行解析, 打印出來.String response = new String(ResponsePacket.getData(), 0, ResponsePacket.getLength());System.out.println(response);}}public static void main(String[] args) throws IOException {UdpEchoClient client = new UdpEchoClient("127.0.0.1", 9090);client.start();}
}

(三)拓展:英譯漢服務器?

當我們需要實現另外一個簡單的服務器時,例如英譯漢服務器,只需要繼承然后重寫process方法就可以了。

package NetWork;import java.io.IOException;
import java.net.SocketException;
import java.util.HashMap;//英譯漢服務器
public class UdpDictServer extends UdpEchoServer{private HashMap<String,String> dict=new HashMap<>();//要在子類的構造方法中調用父類的構造方法//構造方法初始化字典public UdpDictServer(int port) throws SocketException {super(port);dict.put("apple","蘋果");dict.put("boy","男孩");dict.put("cat","小貓");dict.put("dog","小狗");}//重寫process方法public String process(String request){return dict.getOrDefault(request,"沒有找到該詞匯");}public static void main(String[] args) throws IOException {UdpDictServer DictServer=new UdpDictServer(9090);DictServer.start();}
}

五、TCP協議中的socket api

(一)ServerSocket類

ServerSocket是創建TCP服務器端Socket的API。

構造方法:

方法簽名方法說明
ServerSocket(int port)創建一個服務器端套接字Socket,并綁定到指定端口。

成員方法:

方法簽名方法說明
Socket accept()開始監聽指定端口(創建時綁定的端口),有客戶端連接后,返回一個服務器端Socket對象,并基于該Socket建立與客戶端的連接,否則阻塞等待。
void close()關閉此套接字

(二)Socket類

Socket類是客戶端socket,或服務器端中接收到客戶端建立連接(accept方法)的請求后,返回的服務端Socket。

不管是客戶端還是服務器端Socket,都是雙方建立連接以后,保存的對端信息,及用來與對方收發數據的。

構造方法:

方法簽名方法說明
Socket(String host,int port)創建一個客戶端套接字Socket,并對應IP的主機上對應端口的進程進行連接。

成員方法:

方法簽名方法說明

InetAddress getInetAddress()

返回套接字所連接的地址
InputStream getInputStream()返回此套接字的輸入流
OutputStream getOutPutStream()返回此套接字的輸出流

六、TCP協議的回顯服務器

Java流套接字通信模型:

(一)TcpEchoServer回顯服務器

package NetWork;import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class TcpEchoServer {private ServerSocket serverSocket=null;public TcpEchoServer(int port) throws IOException {serverSocket=new ServerSocket(port);}public void start() throws IOException {System.out.println("啟動服務器");// 這種情況一般不會使用 fixedThreadPool, 意味著同時處理的客戶端連接數目就固定了.ExecutorService executorService = Executors.newCachedThreadPool();while (true) {// tcp 來說, 需要先處理客戶端發來的連接.// 通過讀寫 clientSocket, 和客戶端進行通信.// 如果沒有客戶端發起連接, 此時 accept 就會阻塞.// 主線程負責進行 accept, 每次 accept 到一個客戶端, 就創建一個線程, 由新線程負責處理客戶端的請求.Socket clientSocket = serverSocket.accept();// 使用多線程的方式來調整// Thread t = new Thread(() -> {// processConnection(clientSocket);// });// t.start();// 使用線程池來調整executorService.submit(() -> {processConnection(clientSocket);});}}private void processConnection(Socket clientSocket){//對clientSocket進行讀寫操作System.out.printf("[%s:%d] 客戶端上線!\n", clientSocket.getInetAddress(), clientSocket.getPort());try(InputStream inputStream=clientSocket.getInputStream();OutputStream outputStream=clientSocket.getOutputStream()){// 針對 InputStream 套了一層Scanner scanner = new Scanner(inputStream);// 針對 OutputStream 套了一層PrintWriter writer = new PrintWriter(outputStream);while(true){//因為輸入流中的數據是持續讀取的,要加上循環// 1. 讀取請求并解析. 可以直接 read, 也可以借助 Scanner 來輔助完成.if (!scanner.hasNext()) {//scanner.hasNext():判斷輸入流中是否還有 “下一個令牌”(默認以空白字符分割,如空格、換行等)。// 連接斷開了System.out.printf("[%s:%d] 客戶端下線!\n", clientSocket.getInetAddress(), clientSocket.getPort());break;}// 2. 根據請求計算響應String request=scanner.next();String response=process(request);// 3. 返回響應到客戶端// outputStream.write(response.getBytes());writer.println(response);//將緩存區中的數據都發送出去,避免殘留writer.flush();// 打印日志System.out.printf("[%s:%d] req: %s, resp: %s\n", clientSocket.getInetAddress(), clientSocket.getPort(),request, response);}} catch (IOException e) {throw new RuntimeException(e);} finally {try {//服務器連接一個客戶端就要創建一個clientSocket,使用完就要關閉.clientSocket.close();} catch (IOException e) {throw new RuntimeException(e);}}}private String process(String request){return request;}public static void main(String[] args) throws IOException {TcpEchoServer tcpEchoServer=new TcpEchoServer(9090);tcpEchoServer.start();}
}

(二)TcpEchoClient客戶端

package NetWork;import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;public class TcpEchoClient {private Socket socket = null;public TcpEchoClient(String serverIp, int serverPort) throws IOException {// 直接把字符串的 IP 地址, 設置進來.// 127.0.0.1 這種字符串socket = new Socket(serverIp, serverPort);}public void start()throws IOException{Scanner scanner=new Scanner(System.in);try(InputStream inputStream=socket.getInputStream();OutputStream outputStream=socket.getOutputStream()){//給inPutStream套一層Scanner scannerNet= new Scanner(inputStream);//給outPutStream套一層PrintWriter writer=new PrintWriter(outputStream);while (true){//1.讀取用戶輸入String request=scanner.next();//2.發送請求并刷新緩存區數據writer.println(request);writer.flush();//3.接收服務器的響應String response=scannerNet.next();//4.打印出響應System.out.println(response);}}}public static void main(String[] args) throws IOException {TcpEchoClient client = new TcpEchoClient("127.0.0.1", 9090);client.start();}
}

注意點:

  • 在服務器中,采用多線程的方式來處理客戶端的請求(使用線程池)。因為如果是單線程有多個客戶端連接,當程序處理processConnection請求時,就可能阻塞在processConnection,而不能accpet。
  • 因為服務器中有scanner.hasNext來判斷發來的請求,所以客戶端發送的請求要以換行符/空白符號結束,因此發送時用writer.println。
  • 發送請求后記得使用flush刷新緩沖區的數據。

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

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

相關文章

Git 基礎操作筆記(速查)

1. 初始化倉庫git init在當前文件夾初始化一個新的 Git 倉庫。2. 克隆倉庫git clone <倉庫地址>從遠程倉庫復制項目到本地。3. 查看文件狀態git status查看工作區和暫存區的文件狀態。4. 添加文件到暫存區git add <文件名> git add . # 添加所有改動文件5. 提…

【并查集】P3367 【模板】并查集

P3367 【模板】并查集 題目背景 本題數據范圍已經更新到 1≤N≤21051\le N\le 2\times 10^51≤N≤2105&#xff0c;1≤M≤1061\le M\le 10^61≤M≤106。 題目描述 如題&#xff0c;現在有一個并查集&#xff0c;你需要完成合并和查詢操作。 輸入格式 第一行包含兩個整數 N,MN,M…

MyBatis流式查詢詳解

MyBatis 流式查詢詳解&#xff1a;ResultHandler 與 Cursor 在業務中&#xff0c;如果一次性查詢出百萬級數據并返回 List&#xff0c;很容易造成 OOM 或 長時間 GC。 MyBatis 提供了 流式查詢&#xff08;Streaming Query&#xff09; 能力&#xff0c;讓我們可以邊讀邊處理&a…

1Panel Agent 證書繞過實現遠程命令執行漏洞復現(CVE-2025-54424)

免責申明: 本文所描述的漏洞及其復現步驟僅供網絡安全研究與教育目的使用。任何人不得將本文提供的信息用于非法目的或未經授權的系統測試。作者不對任何由于使用本文信息而導致的直接或間接損害承擔責任。如涉及侵權,請及時與我們聯系,我們將盡快處理并刪除相關內容。 前…

kettle插件-kettle http post plus插件,輕松解決https post接口無法調用文件流下載問題

場景&#xff1a;小伙伴在使用kettle調用https post接口過程中無法正常調用&#xff0c;程序出錯問題&#xff0c;今天演示下用自研插件輕松解決這個問題。1、使用openssl 生成自簽名證書openssl req -x509 -newkey rsa:4096 -nodes -out cert.pem -keyout key.pem -days 3652、…

劍指offer第2版——面試題2:實現單例

文章目錄一、題目二、考察點三、答案3.1 C11寫法3.2 C98寫法&#xff08;線程安全只存在于懶漢模式&#xff09;3.2.1 小菜寫法3.2.2 小菜進階寫法3.2.3 中登寫法3.2.3 老鳥寫法四、擴展知識4.1 餓漢模式和懶漢模式的區別4.1.1 餓漢模式&#xff08;Eager Initialization&#…

OpenAI開源大模型gpt-oss系列深度解析:從120B生產級到20B桌面級應用指南

引言&#xff1a;OpenAI開源里程碑&#xff0c;AI民主化加速到來 2025年8月&#xff0c;OpenAI正式宣布開源其兩款重磅大語言模型——gpt-oss-120b&#xff08;1200億參數生產級模型&#xff09;和gpt-oss-20b&#xff08;200億參數桌面級模型&#xff09;&#xff0c;引發全球…

本地部署文檔管理平臺 BookStack 并實現外部訪問( Windows 版本)

BookStack 是一款專注于書籍、文檔管理的開源平臺&#xff0c;它界面設計直觀簡潔&#xff0c;功能強大且易于使用&#xff0c;允許用戶創建、組織和分享文檔資料&#xff0c;特別適合用于構建內部文檔系統、知識庫或公開的文檔站點。本文將詳細介紹如何在 Windows 系統本地部署…

VS Code編輯器

實際上&#xff0c;?Visual Studio Code&#xff08;簡稱VS Code&#xff09;?是由微軟開發的免費、開源、跨平臺的代碼編輯器&#xff0c;支持多種編程語言和框架&#xff0c;廣泛應用于現代Web和云應用開發。這也是個編輯器&#xff0c;可能是繼 GitHub 的 Atom 之后的一枝…

自動化測試篇--BUG篇

目錄 一.軟件測試的生命周期 二.bug是什么&#xff1f; 三.如何描述一個bug&#xff1f; 四.bug的級別 五.bug的生命周期 六.測試與開發產生爭執怎么辦&#xff1f;&#xff08;重要&#xff01;&#xff01;&#xff01;&#xff09; 一.軟件測試的生命周期 軟件測試人員…

Solidity智能合約基礎

基礎學習使用 remix&#xff1a;ide Remix - Ethereum IDE evm&#xff1a;ethreum virtual machine evm字節碼 強類型腳本語言 compile >evm bytescode >evm hello的樣例 聲明的關鍵字&#xff1a;contract // SPDX-License-Identifier: MIT pragma solidi…

Unity跨平臺超低延遲的RTSP/RTMP播放器技術解析與實戰應用

?? 引言&#xff1a;為什么說 Unity 中的視頻能力是“可視化神經元”&#xff1f; 隨著“可視化 實時性”成為工業數字化的關鍵支撐&#xff0c;Unity 正從傳統游戲引擎&#xff0c;演進為數字孿生系統、智能機器人中控、虛擬交互平臺、XR 可視引擎等領域的底層核心。它不再…

python學智能算法(三十三)|SVM-構建軟邊界拉格朗日方程

【1】引用 在前序學習進程中&#xff0c;我們初步了解了SVM軟邊界&#xff0c;今天就更進一步&#xff0c;嘗試構建SVM軟邊界的拉格朗日函數。 【2】基本問題 在SVM軟邊界中&#xff0c;我們已經獲得此時的最優化幾何距離的表達式&#xff1a; fmin?12∣∣w∣∣2C∑i1nξif…

【YOLOv5】

Focus模塊&#xff1a;早期再yolov5版本提出&#xff0c;后期被常規卷積替換&#xff0c;作用是圖像進入主干網絡之前&#xff0c;進行隔行隔列采樣&#xff0c;把空間維度堆疊到通道上&#xff0c;減少計算量。 SPPF:SPP的改進版本&#xff0c;把SPP的不同池化核改變為K 5 的…

Pytest項目_day05(requests加入headers)

headers 由于每個請求都需要加入一些固定的參數&#xff0c;例如&#xff1a;cookies、user-agent&#xff0c;那么將這些固定參數放入URL或params中會顯得很臃腫&#xff0c;因此一般將這些參數放在request headers中headers的反爬作用 在豆瓣網站中&#xff0c;如果我們不加入…

安全引導功能及ATF的啟動過程(四)

安全引導功能及ATF的啟動過程&#xff08;四&#xff09; ATF中bl31的啟動 在bl2中觸發安全監控模式調用后會跳轉到bl31中執行&#xff0c;bl31最主要的作用是建立EL3運行態的軟件配置&#xff0c;在該階段會完成各種類型的安全監控模式調用ID的注冊和對應的ARM核狀態的切換&am…

從手工到智能決策,ERP讓制造外貿企業告別“數據孤島“降本增效

在全球化競爭加劇的當下&#xff0c;制造型外貿企業正面臨訂單碎片化、供應鏈復雜化、合規風險上升等多重挑戰。數字化轉型已成為企業突破增長瓶頸、構建核心競爭力的必選項。然而&#xff0c;許多企業在推進過程中因選型不當陷入“系統孤島”“數據失真”“流程低效”等困境。…

DMETL簡單介紹、安裝部署和入門嘗試

一、DMETL的介紹1.1 概述我們先來簡單了解一下DMETL。DMETL是什么&#xff1f;說的簡單一點&#xff0c;DMETL一款數據處理與集成平臺&#xff1b;從功能來說&#xff0c;那DMETL就是對數據同步、數據處理以及數據交換共享提供一站式支持的平臺&#xff1b;從它的意義來說&…

NLP 人工智能 Seq2Seq、K-means應用實踐

基于Java和人工智能的Web應用 以下是基于Java和人工智能的Web應用實例,涵蓋自然語言處理、計算機視覺、數據分析等領域。這些案例結合了沈七星AI或其他開源框架(如TensorFlow、Deeplearning4j)的實現思路,供開發參考: 自然語言處理(NLP) 1. 智能客服系統 使用Java的Op…

Docker 從入門到實戰(一):全面解析容器化革命 | 2025 終極指南

2025 年,全球容器市場規模突破 200 億美元,超過 80% 的企業生產環境運行在容器之上。掌握 Docker 已成為開發、運維乃至架構師的核心競爭力。本文帶你徹底搞懂 Docker 的底層邏輯與核心價值! 一、Docker 是什么?為什么它能改變世界? 想象一下:你開發時運行完美的 Pytho…