UDP客戶端和服務端

IP地址(源IP,目的IP)
用來識別互聯網上一臺主機的位置

端口號(源端口,目的端口)
用來區分一臺主機上的哪個應用程序
(佔兩個字節的整數)

五元組:
源IP,
目的IP
源端口,
目的端口
協議類型

通過一個五元組表示一個唯一的通信

Socket API本質是一個文件,網卡的抽象
Java標準庫中提供了兩種風格:
1.UDP DatagramSocket:面向數據報(發送接收數據,必須以一定的數據包爲單位進行傳輸)
2.TCP ServerSocket:面向字節流

這兩個是傳輸層中最重要的兩個協議。

UDP服務器

現在以回顯服務器爲例(echo server)

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

public class UdpEchoServer {
    //對於一個服務器,核心流程爲兩步
    //1.初始化操作(實例化Socket對象)
    //2.進入主循環,接受並處理請求
    //讀取數據並解析
    //根據請求計算響應
    //吧響應結果返回到客戶端
    private DatagramSocket socket = null;
    //綁定端口號
    //構造Socket時如果沒寫IP,默認是0.0.0.0(特殊IP)會關聯到這個主機的所有網卡IP
    public UdpEchoServer(int port) throws SocketException {
        socket = new DatagramSocket(port);
    }
    public void start() throws IOException {
        System.out.println("服務器啓動");
        while (true) {
            //UDP socket發送接受數據的基本單位
            DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);
            //當客戶端沒發任何數據,receive就會阻塞
            socket.receive(requestPacket);
            //當有客戶端數據過來了,receive就會把數據放到DatagramPacket對象的緩衝區
            //吧數據轉成String
            //用戶實際發送的數據可能遠小於4096,而此處得到的長度就是4096,
            //可以通過trim就可以去掉不必要的空白字符
            String request = new String(requestPacket.getData(),
                    0,requestPacket.getLength()).trim();
            String response = process(request);
            //requestPacket.getSocketAddress()就是客戶端的地址和端口
            //response.getBytes().length得到的是字節數
            DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),
                    response.getBytes().length,requestPacket.getSocketAddress());
            socket.send(requestPacket);
            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();
    }
}
import java.io.IOException;
import java.net.*;
import java.util.Scanner;

public class UdpEchoClient {
    //客戶端分四步
    //1.從用戶這裏讀取數據
    //2.構造請求發給服務器
    //3.從服務器讀取響應
    //4.吧響應寫回給客戶端
    private DatagramSocket socket = null;
    private String serverIp;
    private 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 scanner = new Scanner(System.in);
        while (true) {
            System.out.print("->");
            String request = scanner.nextLine();
            if (request.equals("exit")) {
                break;
            }
            //構造請求
            DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),
                    request.getBytes().length, InetAddress.getByName(serverIp),serverPort);
            socket.send(requestPacket);
            DatagramPacket responsePacket = new DatagramPacket(new byte[4096],4096);
            socket.receive(requestPacket);
            String response = new String(requestPacket.getData(),0,requestPacket.getLength()).trim();
            System.out.println(response);
        }
    }

    public static void main(String[] args) throws IOException {
        //這裏的IP是特殊IP,環回IP,由於這裏服務器和客戶端在同一主機
        //如果不在同一主機,要寫成服務器IP
        UdpEchoClient client = new UdpEchoClient("127.0.0.1",9090);
        client.start();
    }
}

在這裏插入圖片描述
在這裏插入圖片描述
客戶端服務器是爲了跨主機通信
要把服務器部署到雲服務器上
部署主要是兩個步驟:

1.把代碼打成jar包
2.把jar包拷貝到服務器上運行

用idea打jar包:
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

現在寫一個翻譯服務器來體會服務器裏面process的業務邏輯,一般比較複雜的服務器,process裏面的代碼往往很複雜。

import java.io.IOException;
import java.net.SocketException;
import java.util.HashMap;
import java.util.Map;

public class UdpDictServer extends UdpEchoServer {
    private Map<String,String> dict = new HashMap<>();
    public UdpDictServer(int port) throws SocketException {
        super(port);
        dict.put("cat","小貓");
        dict.put("dog","小狗");
        dict.put("bird","小鳥");

    }

    @Override
    public String process(String request) {
        return dict.getOrDefault(request,"這超出了我的知識範圍");
    }

    public static void main(String[] args) throws IOException {
        UdpDictServer server = new UdpDictServer(9090);
        server.start();
    }
}

在這裏插入圖片描述
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章