TCP与UDP通信协议及Java实现
概述
TCP (Transmission Control Protocol):傳輸控制協議
UDP(User Datagram Protocol):用戶數據報協議
TCP 與 UDP 都是 運輸層(Transport Layer)上的因特網協議,運輸層協議的功能就是為運行在不同主機上的應用進程之間提供 邏輯通信 ,使得運行不同進程的主機即使分隔于地球兩側,也能像是直接相連一樣。
而具體做法是,它為來自應用層的報文添加上運輸層首部來創建運輸層報文段,這個首部中包含了以下信息
通過這些首部字段,不同主機之間的進程就可以通信了
UDP 為調用它的應用程序提供了一種 不可靠的 無連接 服務
TCP 為調用它的應用程序提供了一種 可靠的 面向連接 服務
UDP
UDP 可以說是一種極簡的運輸層協議,它的功能僅僅包括運輸層必備的功能,即:多路復用/多路分解,差錯檢測
在后面的講解中我們會知道 TCP 進行通信時,發送方與接收方先要進行“三次握手”來確認連接,而 UDP 則沒有這一流程,所以說 UDP 是無連接的
在 TCP 中,如果消息沒有成功發送,發送方是會收到發送失敗的反饋的,而 UDP 中,發送方發出數據后無法確認是否成功發送,只能靠接收方是否回復信息來確認上一次發送成功與否,因此在應用 UDP 時,通常會加入一個延時,如果超過額定時間未收到回復,就重新發送
DNS(Domain Name System,域名系統)就是一個應用 UDP 的例子,當我們輸入網址訪問網站時,DNS 就是通過 UDP 發送域名查詢報文的。所以,如果長時間沒有得到回復,我們就會看到“連接超時”的錯誤頁面。
UDP 檢驗和,就是用來做差錯檢驗的數據。
方法實現是,發送方的 UDP 對報文段中的所有 16 比特字的和進行反碼運算,求和時遇到溢出要回卷。
例:有 3 個 16 比特字
0110 0110 0110 0000
0101 0101 0101 0101
1000 1111 0000 1100
①:前兩個相加
0110 0110 0110 0000
0101 0101 0101 0101
————————————
1011 1011 1011 0101
②:和與第三個相加
1011 1011 1011 0101
1000 1111 0000 1100
————————————
(1)0100 1010 1100 0001
③:有溢出,進行回卷
0100 1010 1100 0001 + 1 = 0100 1010 1100 0010
④:轉為反碼,存入檢驗和
1011 0101 0011 1101
接收端收到數據后,會再次將數據取和,再與檢驗和相加,若結果為1111 1111 1111 1111則表示無差錯,若出現 0 則表示有差錯
UDP 雖然提供差錯檢測,但是不會進行錯誤修復,它要么直接丟棄錯誤段,要么將錯誤段上報應用程序
看到這里,不由得會產生一個疑問:UDP 這么的精簡,功能不夠強大,為什么還要用它呢?
原因是:
TCP
應用 TCP 時,一個應用進程可以開始向另一個應用進程發送數據之前,這兩個進程必須先進行“握手”,所以說,TCP 是面向連接的
TCP 連接提供的是 點對點,全雙工服務
TCP 提供的是 可靠數據傳輸
TCP 通過使用 流量控制、序號、確認和定時器 等技術,確保正確地、按序地將數據從發送進程交付給接收進程
TCP 還提供了 擁塞控制 ,它允許 TCP 連接通過一條擁塞的網絡鏈路,平等地共享網絡鏈路帶寬。
TCP 建立連接有三次握手
終止連接有四次握手
TCP 報文段結構
代碼示例
UDP
UDPClient.java
package test;import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress;/** * UDPCLient deom* @author <dht925nerd@126.com>*/ public class UDPClient {public static void main(String[] args) throws Exception {DatagramSocket clientSocket = new DatagramSocket();BufferedReader inFromUser =new BufferedReader(new InputStreamReader(System.in));//獲取本地 IP 地址InetAddress IPAddress = InetAddress.getLocalHost();byte[] sendData;byte[] receiveData = new byte[1024];System.out.println("請輸入一句英文,服務器會返回其大寫形式(輸入exit退出)");while (true) {String sentence = inFromUser.readLine();if (sentence.equals("exit")) break;sendData = sentence.getBytes();//創建發送數據報包,并標注源地址#,目的地址#DatagramPacket sendPacket =new DatagramPacket(sendData, sendData.length, IPAddress, 9876);//發送數據報包clientSocket.send(sendPacket);//創建接收數據報包DatagramPacket receivePacket =new DatagramPacket(receiveData, receiveData.length);//接收服務器的數據報包clientSocket.receive(receivePacket);String modifiedSentence = new String(receivePacket.getData());System.out.println("FROM SERVER: " + modifiedSentence);}clientSocket.close();} }UDPServer.java
package test;import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.text.SimpleDateFormat; import java.util.Date;/*** UDPServer Demo* @author <dht925nerd@126.com>*/ public class UDPServer {public static void main(String[] args) throws Exception {DatagramSocket serverSocket =new DatagramSocket(9876);byte[] sendData;SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");while (true) {byte[] receiveData = new byte[1024];//創建接收數據報包DatagramPacket receivePacket =new DatagramPacket(receiveData, receiveData.length);//接收客戶端數據報包serverSocket.receive(receivePacket);String sentence = new String(receivePacket.getData());//獲取客戶端地址InetAddress IPAddress = receivePacket.getAddress();if (sentence != null) System.out.println(df.format(new Date()) + " from " + IPAddress + ": " + sentence );//獲得客戶端端口號int port = receivePacket.getPort();String capitalizedSentence = sentence.toUpperCase();sendData = capitalizedSentence.getBytes();DatagramPacket sendPacket =new DatagramPacket(sendData, sendData.length, IPAddress, port);//向客戶端發送數據報包serverSocket.send(sendPacket);}} }測試方法:
① 先編譯運行UDPServer.java
② 再運行 UDPClient.java
③ 在UDPClient的控制板面輸入字符串,回車
④ 在UDPClient 和 UDPServer 控制板面觀察運行信息
運行信息:
客戶端
服務器端
TCP
TCPClient.java
package test;import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.InputStreamReader; import java.net.Socket;/*** TCPClient demo* @author <dht925nerd@126.com>*/ public class TCPClient {public static void main(String[] args) throws Exception {String sentence;String modifiedSentence;System.out.println("請輸入一個英文字符串,服務器將返回其大寫形式(輸入exit退出)");while (true) {BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in));//創建客戶端 Socket 并指明需要連接的服務器端的主機名及端口號Socket clientSocket = new Socket("localhost", 6789);DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));sentence = inFromUser.readLine();if (sentence.equals("exit")) break;//向服務器發送數據outToServer.writeBytes(sentence + '\n');//接收服務器返回數據modifiedSentence = inFromServer.readLine();System.out.println("FROM SERVER: " + modifiedSentence);clientSocket.close();}} }TCPServer.java
package test;import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.InputStreamReader; import java.net.ServerSocket; import java.net.Socket; import java.text.SimpleDateFormat; import java.util.Date;/*** TCPServer demo* @author <dht925nerd@126.com>*/ public class TCPServer {public static void main(String[] args) throws Exception {String clientSentence;String capitalizedSentence;SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//創建服務器端 Socket 并指明端口號ServerSocket welcomeSocket = new ServerSocket(6789);while(true) {//接收客戶端連接Socket connectionSocket = welcomeSocket.accept();BufferedReader inFromClient = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));DataOutputStream outToClient = new DataOutputStream(connectionSocket.getOutputStream());//獲取客戶端傳入的字符串clientSentence = inFromClient.readLine();if (clientSentence != null)System.out.println(df.format(new Date()) + " from " + connectionSocket.getInetAddress() + ": " + clientSentence );capitalizedSentence = clientSentence.toUpperCase() + '\n';//向客戶端發送修改后的字符串outToClient.writeBytes(capitalizedSentence);}} }測試方法:同上
總結
以上是生活随笔為你收集整理的TCP与UDP通信协议及Java实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 不用羡慕BAT,自己手工也能搭建伪基站监
- 下一篇: This Jenkins instanc