[JavaEE] 网络编程----UDP / TCP 回显服务器

Author:MTingle

major:人工智能


Build your hopes like a tower!

文章目录

文章目录

一.客户端VS服务器

[二.TCP / UDP 特点](#二.TCP / UDP 特点)

[三.UDP 回显服务器](#三.UDP 回显服务器)

[UDP 服务器](#UDP 服务器)

[UDP 客户端](#UDP 客户端)

UDP字典

[四.TCP 回显服务器](#四.TCP 回显服务器)

[TCP 服务器](#TCP 服务器)

[TCP 客户端](#TCP 客户端)




一.客户端VS服务器

在网络中,主动发起通信的一方称为"客户端",被动接受的这一方,称为"服务器".同一个程序在不同场景中,可以是客户端,也可能是服务器.客户端给服务器发送的数据,称为"请求"(request),服务器给客户端返回的数据,称为"响应"(response);

客户端与服务器之间的交互有多种模式.

1.一问一答 :一个请求对应一个响应.最常见,例如在"web开发"中.

2.一问多答 :一个请求对应多个相应.这个场景最要涉及到"下载".

3.多问一答 :多个请求对应一个响应.这个场景主要涉及到"上传".

4.多问多答 :一个请求可能对应多个响应,一个响应也可能对应多个请求,主要涉及到"远程控制/远程桌面"

二.TCP / UDP 特点

TCP 的特点是:有连接 可靠传输 面向字节流 全双工

UDP 的特点是:无连接 不可靠传输 面向数据报 全双工

有连接 / 无连接: 此处的连接不是物理意义上的连接,而是抽象,虚拟的连接,举个简单的例子,当我们打电话时,一边拨号,一边接通,此时才能通话,如果一方不接通,就无法进行通话,这就叫做有连接,连接首先的特点是双方都能认同 .无连接类似发短信,无论你是否同意,我都能给你将信息发过去.计算机中的"网络连接"即是通信双方,各自保存对方的信息,客户端中,有一些数据结构记录了谁是他的服务器,服务器中也有一些数据结构,记录了谁是他的客户端~~

可靠传输 / 不可靠传输: 网络上"异常情况"很多,无论使用什么样的软硬件的技术手段,都无法保证网络数据100%从A运送到B .此处我们的"可靠传输"指的是尽可能的完成数据传输,虽然无法保证数据到达对方,但至少可以知道这个数据对方是否收到了,此处的可靠传输,主要指的是发送的数据没收到,发送方能否清楚地感知到.

面向字节流 / 面向数据报 : 此处的字节流和文件中的字节流完全一致,网络中传输的数据的基本单位是字节 .面向数据报,每次传输的单位就是一个数据报(特定的结构,数据报由一系列的字节构成).

全双工 / 半双工: 一个信息渠道可以双向通信称为全双工,只能单向通信成为半双工.

三.UDP 回显服务器

核心的类有两个:

1.DatagramSocket: 负责对 socket 文件读写,也就是借助网卡发送数据

2.DatagramPacket: 面向数据报,每次发送接收数据的基本单位,就是一个UDP数据报

UDP 服务器

java 复制代码
public class UdpEchoServer {

    DatagramSocket socket=null;

// 第一步: 创建DatagramSocket对象,而后的操作针对socket对象完成
    public UdpEchoServer(int port) throws IOException {
        socket=new DatagramSocket(port);
    }

    public void start() throws IOException {
        System.out.println("服务器启动!");
        while (true) {  // 对于服务器,需要不断接受请求,返回响应,于是需要用一个 while 循环
            // 1.接受请求并解析,byte可以保存收到的消息正文
            DatagramPacket requestPacket=new DatagramPacket(new byte[4096],4096);
            socket.receive(requestPacket);
            String request=new String(requestPacket.getData(),0,requestPacket.getLength());
            // 2.根据请求响应计算
            String response=process(request);
            DatagramPacket responsePacket=new DatagramPacket(response.getBytes(),response.getBytes().length,
                    requestPacket.getSocketAddress());
            // 3.返回响应
            socket.send(responsePacket);
            System.out.printf("[%s:%d] req:%s, resp:%s\n",responsePacket.getAddress(),responsePacket.getPort(),
                    request,response);
        }
    }

    public String process(String request) {
        return request;
    }

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

}

UDP 客户端

java 复制代码
public class UdpEchoClient {

    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 {
        System.out.println("客户端启动!");
        Scanner scanner=new Scanner(System.in);
        while (true) {
            System.out.printf("-> ");
            // 1.从控制台读取流程
            if (!scanner.hasNext()) {
                break;
            }
            String request=scanner.next();
            // 2.构造请求并发送
            DatagramPacket requestPacket=new DatagramPacket(request.getBytes(),request.getBytes().length,
                    InetAddress.getByName(serverIp),serverPort);
            socket.send(requestPacket);
            // 3.读取服务器响应
            DatagramPacket responsePacker=new DatagramPacket(new byte[4096],4096);
            socket.receive(responsePacker);
            // 4.把响应显示在控制台上
            String response=new String(responsePacker.getData(),0,responsePacker.getLength());
            System.out.println(response);
        }

    }

    public static void main(String[] args) throws IOException {
        UdpEchoClient client=new UdpEchoClient("127.0.0.1",9090);
        client.start();
    }


}

UDP字典

java 复制代码
public class UdpDictServer extends UdpEchoServer {
    private HashMap<String,String> hashMap=new HashMap<>();
    public UdpDictServer(int port) throws IOException {
        super(port);
        hashMap.put("小鸡","chicken");
        hashMap.put("小猫","cat");
        hashMap.put("小狗","dog");
    }

    @Override
    public String process(String request) {
        return hashMap.getOrDefault(request,"该词典中没有这个单词");
    }

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

四.TCP 回显服务器

TCP 服务器

java 复制代码
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("服务端启动!\n");
        while (true) {
            // 通过accept"接听电话"后才能进行通信
            Socket clientSocket=serverSocket.accept();
            Thread t=new Thread(()->{  // 引入多线程,可以同时服务多个服务器
                processConnection(clientSocket);

            });
            t.start();
        }
    }

    private void processConnection(Socket clientSocket) {
        System.out.printf("[%s:%d] 客户端上线!\n",clientSocket.getInetAddress(),clientSocket.getPort());
        // 循环读取客户请求并反映
       try (InputStream inputStream= clientSocket.getInputStream();
            OutputStream outputStream=clientSocket.getOutputStream()){
           while (true) {
               // 通过inputStream读取数据
               Scanner scanner=new Scanner(inputStream);
               if (!scanner.hasNext()) {
                   System.out.printf("[%s:%d] 客户端下线!\n",clientSocket.getInetAddress(),clientSocket.getPort());
                   break;
               }

               // 1.读取请求并解析,这里有隐藏约定,next读的时候要以 空格 或 换行符 结束;
               String request=scanner.next();
               // 2.响应请求并计算
               String response=process(request);
               // 3.把响应返回给客户端
                //通过这种方式可以写回,但是这种方式不方便给返回的响应中添加\n
                // outputStream.write(response.getBytes(),0,response.getBytes().length);
                // 也可以给 outputstream 套上一层,完成更方便的写入。
               PrintWriter printWriter=new PrintWriter(outputStream);
               printWriter.println(response);
               printWriter.flush();
               System.out.printf("[%s:%d] req:%s, resp:%s\n",clientSocket.getInetAddress(),clientSocket.getPort(),
                       request,response);

           }
       } catch (IOException e) {
           throw new RuntimeException(e);
       }
    }

    private String process(String request) {
        return  request;
    }

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

TCP 客户端

java 复制代码
public class TcpEchoClient {

    private Socket socket=null;

    public TcpEchoClient(String serverIP, int serverPort) throws IOException {

        socket=new Socket(serverIP,serverPort);
    }

    public void start() throws IOException {
        System.out.println("客户端上线!\n");

        // 1.从控制台读取输入的字符串
        try (InputStream inputStream=socket.getInputStream();
             OutputStream outputStream=socket.getOutputStream()){
            Scanner scannerConsole=new Scanner(System.in);
            Scanner scannerNetwork=new Scanner(inputStream);
            PrintWriter writer=new PrintWriter(outputStream);
            while (true) {
                System.out.print("-> ");
                if (!scannerConsole.hasNext()) {
                    break;
                }
                String request=scannerConsole.next();
                // 2.把请求发送给服务器,这里需要有 println 来发送,为了让发送结尾带 \n
                // 这里是和 scanner.next() 呼应
                writer.println(request);
                // 主动刷新缓冲器,确保数据发送
                writer.flush();
                // 3.从服务器读取响应
                String response=scannerNetwork.next();
                // 4.把响应显示出来
                System.out.println(response);
            }
        }finally {
            socket.close();
        }
    }

    public static void main(String[] args) throws IOException {
        TcpEchoClient client=new TcpEchoClient("127.0.0.1",9090);
        client.start();
    }

}

相关推荐
百成Java3 分钟前
基于springboot的旅游网站
java·spring boot·后端·mysql·spring·智能家居·旅游
昭著12 分钟前
优先级队列(堆)
java·数据结构
cc77521020 分钟前
【常见框架漏洞】ThinkPHP、struts2、Spring、Shiro
java·struts·spring
NiNg_1_23420 分钟前
计算机网络中的VLAN详解
网络·计算机网络·智能路由器
月临水23 分钟前
JavaEE: 深入探索TCP网络编程的奇妙世界(四)
网络·tcp/ip·java-ee
Pandaconda24 分钟前
【计算机网络 - 基础问题】每日 3 题(二十三)
开发语言·网络·笔记·后端·计算机网络·面试·职场和发展
来自人间的烟火26 分钟前
centos离线安装nvm
linux·运维·服务器
野生派蒙27 分钟前
IDEA 关闭自动补全功能(最新版本)
java·开发语言·ide·后端·学习·intellij-idea
林小果127 分钟前
观察者模式
java·开发语言·观察者模式·设计模式
xplidelphi30 分钟前
Idea开发Gradle多模块项目踩坑纪实之一:Java模块无法执行
java·ide·intellij-idea