JavaWeb~使用UDP網絡編程 簡單實現漢譯英服務器與客戶端

通信瞭解五元組

  • 源IP
  • 源端口
  • 目的IP
  • 目的端口
  • 協議類型

端口號(port)是傳輸層協議的內容.
端口號是一個32位的整數;
端口號用來標識一個進程, 告訴操作系統, 當前的這個數據要交給哪一個進程來處理;
IP地址 + 端口號能夠標識網絡上的某一臺主機的某一個進程;
一個端口號只能被一個進程佔用

源IP就好比發件人的地址 源端口就好比發件人的姓名
目的IP就好比收件人的地址 目的端口就好比收件人的姓名

socket編程接口

  • DatagramSocket(int port,InetAddress laddr) 創建一個數據報套接字,綁定到指定的本地地址
  • DatagramSocket(SocketAddress bindaddr) 創建一個數據報套接字,綁定到指定的本地套接字地址
  • void bind(SocketAddress addr) 將此DatagramSocket綁定到特定的地址和端口
  • void connect(InetAddress address, int port) 將套接字連接到此套接字的遠程地址
  • void receive(DatagramPacket p) 從此套接字接收數據報包
  • void close() 關閉此數據報套接字
  • void send(DatagramPacket p) 從此套接字發送數據報包

使用簡單的UDP網絡程序實現服務器\

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

//服務器程序
public class MyUDPServer {
    // 對於一個服務器程序來說, 核心流程也是要分成兩步.
    // 1. 進行初始化操作 (實例化 Socket 對象)
    // 2. 進入主循環, 接受並處理請求. (主循環就是一個 "死循環")
    //   a) 讀取數據並解析
    //   b) 根據請求計算響應
    //   c) 把響應結果寫回到客戶端.

    //需要一個udp的連接
    private DatagramSocket socket = null;
    //map去存儲我們的漢譯英數據
    private Map<String, String> map = new HashMap<>();

    //在構造函數裏初始化操作實現連接 並指定端口號
    public MyUDPServer(int port) throws SocketException {
        //添加數據
        initDates();
        //服務器new socket對象的時候需要和一個ip地址和端口號綁定起來
        //如果沒有寫ip 則默認時0.0.0.0 (一個特殊的ip會關聯到這個主機的國有網卡的ip)
        //socket對象本省就是一個文件
        socket = new DatagramSocket(port);
    }

    private void initDates() {
        map.put("貓", "cat");
        map.put("豬", "pig");
        map.put("狗", "dog");
        map.put("人", "people");
        map.put("筆", "pen");
        map.put("坐", "sit");
        map.put("手", "hand");
        map.put("腿", "leg");
    }

    //進入主循環實現接收 處理 響應
    public void start() throws IOException {
        System.out.println("服務器啓動");
        while (true) {
            //接收請求
            //這是一個接受數據的緩衝區 地址是接受數據的時候有內存填充
            DatagramPacket requestPacket = new DatagramPacket(new byte[4096], 4096);
            //程序啓動會很快到達receive操作 如果客戶端沒有發送任何數據 此時receive操作會阻塞直到有客戶端發送數據過來
            //當整的有哭換端發送過來數據時 receive就會將數據保證到DategramPAcket對象的緩衝區裏
            socket.receive(requestPacket);
            //原本請求的數據時byte[]需要將其轉換成String 並且如果發來的數據小於我們緩衝區的大小就會默認添加空格 我們得去掉無用空格
            String request = new String(requestPacket.getData(), 0, requestPacket.getLength()).trim();
            //處理請求
            String respond = process(request);
            //把響應寫回給客戶端, 響應數據就是 response, 需要包裝成一個 Packet 對象
            //此時這個用於send 不僅需要指定緩衝區還不要忘記在Packet對象的最後加上請求數據包裏的Socket地址
            //填寫ip和port還可以自己手動設置將ip和port分開寫(如下面案例) 還可以直接定義InetAddress對象(裏面包含ip和port)
            DatagramPacket respondPacket = new DatagramPacket(respond.getBytes(),
                    respond.getBytes().length, requestPacket.getSocketAddress());
            socket.send(respondPacket);

            //打印請求訪問日誌
            System.out.println(requestPacket.getAddress().toString() + "  " + requestPacket.getPort() + "  request: "
                    + request + "  respond: " + respond);
        }

    }

    private String process(String request) {

        // 由於此處是一個 echo server, 請求內容是啥, 響應內容就是啥.
        // 如果是一個更復雜的服務器, 此處就需要包含很多的業務邏輯來進行具體的計算.
        return map.getOrDefault(request, "未學習");
    }

    //一個主函數去設置該服務器的端口 並讓其開始執行
    public static void main(String[] args) {
        try {
            MyUDPServer myUDPServer = new MyUDPServer(9090);
            try {
                myUDPServer.start();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } catch (SocketException e) {
            e.printStackTrace();
        }
    }
}

使用簡單的UDP網絡程序實現客戶端


import java.io.IOException;
import java.net.*;
import java.util.Scanner;

//客戶端程序
public class MyUDPClient {
    //核心操作有倆步
    //啓動客戶端的時候需要指定連接那臺服務器
    //執行任務主要流程分4步
    // 1. 從用戶這裏讀取輸入的數據.
    // 2. 構造請求發送給服務器
    // 3. 從服務器讀取響應
    // 4. 把響應寫回給客戶端.

    //需要客戶端知道要發往哪臺服務器的ip 和端口 還需要一個udp的連接對象
    private String severIP = null;
    private int severPort = 0;
    private DatagramSocket socket = null;

    //需要在啓動客戶端的時候來指定需要連接哪個服務器
    public MyUDPClient(String severIP, int severPort) throws SocketException {
        this.severIP = severIP;
        this.severPort = severPort;
        //客戶端在創建socket的時候不需要綁定端口號 但是服務器必須綁定端口號
        //因爲服務器綁定了端口號 客戶端才能找到去訪問它
        //客戶端不綁定是爲了可以在一臺主機上啓動多個客戶端
        this.socket = new DatagramSocket();
    }

    public void start() throws IOException {
        Scanner scanner = new Scanner(System.in);
        while (true) {
            //讀取用戶輸入的消息
            System.out.print("輸入字符串->");
            String request = scanner.nextLine();
            if ("exit".equals(request)) {
                break;
            }
            //發送請求
            //注意ip和port要分開寫並且前後位置要注意
            DatagramPacket requstPacket = new DatagramPacket(request.getBytes(),
                    request.getBytes().length, InetAddress.getByName(this.severIP), this.severPort);
            socket.send(requstPacket);
            //接收服務器的響應
            DatagramPacket respondPacket = new DatagramPacket(new byte[4096], 4096);
            socket.receive(respondPacket);
            String respond = new String(respondPacket.getData(), 0, respondPacket.getLength()).trim();
            //顯示響應
            System.out.println(respond);
        }
    }

    public static void main(String[] args) {
        try {
            //此時我們用於自己主機實驗 127.0.0.1是一個特殊的ip(環回ip) 自己訪問自己
            //如果服務器和客戶端在同一臺主機上舊使用環回ip 如果不在同一臺主機上就必須填寫服務器的ip
            //端口號必須與服務器的端口號一致
            MyUDPClient client = new MyUDPClient("127.0.0.1", 9090);
            try {
                client.start();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } catch (SocketException e) {
            e.printStackTrace();
        }
    }
}

測試

在這裏插入圖片描述

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