Java后端學(xué)習(xí)精華之TCP通信傳輸協(xié)議詳解
上篇教程回顧
ServerSocket --監(jiān)聽客戶端的連接,他的作用主要是建立一個(gè)連接
-ServerSocket -建立連接,拿到一個(gè)Socket
-Telnet 127.0.0.1 8888- 客戶端使用Telnet訪問服務(wù)端 建立連接
-服務(wù)端可以拿到一個(gè)Socket的對象
-獲取這個(gè)對象的輸入輸出流
-寫入和讀取數(shù)據(jù)
Socket連接模型
服務(wù)端和客戶端通過Socket進(jìn)行連接,雖然是一個(gè)Socket,但是相當(dāng)于把這一個(gè)Socket分成了兩個(gè)管道,服務(wù)端拿著這兩根管道的一段,客戶端拿著這兩根管道的另一端。
- Server的input與Client的output相連
- 客戶端發(fā)送數(shù)據(jù),從Client的output發(fā)送,傳輸?shù)絊erver的input接收
- 服務(wù)端發(fā)送數(shù)據(jù),從Server的output發(fā)送,傳輸?shù)紺lient的input接收
- 如果實(shí)現(xiàn)雙端收發(fā)通信,每個(gè)程序至少需要兩個(gè)線程
消息協(xié)議
TCP:面向連接
UDP:不需要建立連接 類似數(shù)據(jù)報(bào)
TCP:穩(wěn)定,要求發(fā)送數(shù)據(jù)前必須確認(rèn)雙方都可以收發(fā)消息
連接過程 : 三次握手
Server--------------------- Client
1: 監(jiān)聽-----------------------發(fā)送請求
這步之后,服務(wù)端知道客戶端可以發(fā)數(shù)據(jù)
2:收到請求,應(yīng)答------------收到應(yīng)答消息,發(fā)送應(yīng)答包給s
這步之后,客戶端知道服務(wù)端可收發(fā)數(shù)據(jù)
3:收到應(yīng)答
這步之后,服務(wù)端知道客戶端可以收數(shù)據(jù)
傳輸過程中數(shù)據(jù)類型需要了解的細(xì)節(jié)
char:16bit 兩個(gè)字節(jié)Byte
數(shù)據(jù)發(fā)送的單位:數(shù)據(jù)每次發(fā)送一個(gè)byte,一個(gè)char需要發(fā)送兩次單字節(jié)
發(fā)送文字消息
- 第一部分應(yīng)發(fā)送字符串的長度,以便確定字節(jié)數(shù)組的長度
- 對方,讀取的第一個(gè)字節(jié)是消息長度,定義一個(gè)固定容量大小的容器
- 第二部分為消息內(nèi)容
- 對方,讀取對應(yīng)長度的字節(jié)后,將其轉(zhuǎn)成對應(yīng)的數(shù)據(jù)(String對象)
數(shù)據(jù)類型:
- 整數(shù)型:byte short int long
- 浮點(diǎn)型:float double
- 字符型:char
- 布爾型:boolean
- char=16bit=2 byte unicode編碼
- utf-8:1-6個(gè)字節(jié)組成一個(gè)漢字
1100 1101 1010
如這個(gè)數(shù)據(jù)第一個(gè)字節(jié)有兩個(gè)1,則代表它是一個(gè)漢子,并且后面兩個(gè)字節(jié)都表示這個(gè)漢字,如果有111就讀取后面三個(gè)字節(jié)
因?yàn)橛⑽挠肁SCII碼存儲0-127,第一位不可能是1,通過第一個(gè)字節(jié)可以判斷是中文還是英文
- 英文字母全部兼容:ASCII 0-127 二進(jìn)制碼:0-255,所以0-127一定以0開頭,漢字是16bit 0-65536
TCP通信代碼
通過自己編寫一個(gè)客戶端和服務(wù)端,實(shí)現(xiàn)消息的首發(fā),這里的核心主要是自己編寫通信協(xié)議,我在這里第一次發(fā)送到是數(shù)據(jù)的長度,并且做了數(shù)據(jù)加密,客戶端需要解析這個(gè)數(shù)據(jù)長度,并創(chuàng)建對應(yīng)長度的數(shù)組,才能正確讀取消息內(nèi)容
MsgClient
package com.lding.net; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; import java.util.Scanner; /** * @program: Net * @description: Tcp客戶端測試 * @author: 王丁 * @date: 2021-09-20 10:04 **/ public class TcpClient { public static void main(String[] args) throws IOException { Socket socket=new Socket("127.0.0.1",8888); OutputStream output=socket.getOutputStream(); InputStream input=socket.getInputStream(); InputStreamReader inputStreamReader = new InputStreamReader(input); // byte[] msgbyte=new byte[30]; // input.read(msgbyte); // System.out.println("服務(wù)器說:"+new String(msgbyte)); int length1=input.read(); int length2=input.read(); int msglength=length2*3+length1; System.out.println("消息長度為:"+msglength); byte[] msgbytes=new byte[msglength]; input.read(msgbytes); String getmsg=new String(msgbytes); System.out.println("服務(wù)器說:"+getmsg); } }
MsgServer
package com.lding.net; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; /** * @program: Net * @description: Tcp服務(wù)端測試 * @author: 王丁 * @date: 2021-09-20 10:03 **/ public class TcpServer { public static void main(String[] args) throws IOException { ServerSocket serverSocket = new ServerSocket(8888); //監(jiān)聽客戶端的Socket連接 System.out.println("服務(wù)端開啟:ip:"+serverSocket.getInetAddress().getHostAddress()+"端口號:"+serverSocket.getLocalSocketAddress()); System.out.println("正在等待有緣人......"); Socket socketClient = serverSocket.accept(); System.out.println("客戶端已連接:"+socketClient.getInetAddress()); System.out.println("客戶端端口"+socketClient.getPort()); OutputStream output=socketClient.getOutputStream(); InputStream input=socketClient.getInputStream(); // output.write("服務(wù)器連接成功?。?!".getBytes()); // output.flush();//刷新緩沖,管道強(qiáng)制刷出 String msg="服務(wù)器連接成功?。。≈星锟鞓?!<include/bits/stdc++.h> using namespace std"; byte[] msgBytes=msg.getBytes(); int length1=msgBytes.length%3; int length2=msgBytes.length/3; output.write(length1); output.write(length2); output.write(msgBytes); output.flush(); // while(input.read()!=-1){ // System.out.println((char) input.read()); // } } }
運(yùn)行結(jié)果
還可以完善的地方
1、之后通信協(xié)議可以加入,通過客戶端列表,轉(zhuǎn)發(fā)消息內(nèi)容到多個(gè)客戶端
2、攜帶用戶名、目標(biāo)用戶名等等
到此這篇關(guān)于Java后端學(xué)習(xí)精華之TCP通信傳輸協(xié)議詳解的文章就介紹到這了,更多相關(guān)Java TCP通信內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
IDEA如何使用spring-Initializr快速搭建SpringBoot
這篇文章主要介紹了IDEA如何使用spring-Initializr快速搭建SpringBoot問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05Java的Spring框架中bean的繼承與內(nèi)部bean的注入
這篇文章主要介紹了Java的Spring框架中bean的繼承與內(nèi)部bean的注入,Spring框架是Java的SSH三大web開發(fā)框架之一,需要的朋友可以參考下2015-12-12java 算法之歸并排序詳解及實(shí)現(xiàn)代碼
這篇文章主要介紹了java 算法之歸并排序詳解及實(shí)現(xiàn)代碼的相關(guān)資料,需要的朋友可以參考下2017-03-03java使用JDBC動態(tài)創(chuàng)建數(shù)據(jù)表及SQL預(yù)處理的方法
這篇文章主要介紹了java使用JDBC動態(tài)創(chuàng)建數(shù)據(jù)表及SQL預(yù)處理的方法,涉及JDBC操作數(shù)據(jù)庫的連接、創(chuàng)建表、添加數(shù)據(jù)、查詢等相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-08-08Sentinel Dashboard限流規(guī)則保存方式
這篇文章主要介紹了Sentinel Dashboard限流規(guī)則保存方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06SpringMVC @RequestBody Date類型的Json轉(zhuǎn)換方式
這篇文章主要介紹了SpringMVC @RequestBody Date類型的Json轉(zhuǎn)換方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10java使用CountDownLatch等待多線程全部執(zhí)行完成
這篇文章主要為大家詳細(xì)介紹了使用CountDownLatch等待多線程全部執(zhí)行完成,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-10-10java中servlet實(shí)現(xiàn)登錄驗(yàn)證的方法
做web開發(fā),登錄驗(yàn)證是免不了的,今天學(xué)習(xí)了servlet的登錄驗(yàn)證,當(dāng)然是很簡單的,沒有使用session,request等作用域?qū)ο?,所以還是可以直接通過地址訪問網(wǎng)頁的。2013-05-05