前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >22. 网络编程(1)——UDP 协议

22. 网络编程(1)——UDP 协议

作者头像
小雨的分享社区
发布2022-10-26 15:47:54
2200
发布2022-10-26 15:47:54
举报
文章被收录于专栏:小雨的CSDN

网络编程需要依靠Socket API,在java标准库中有两种风格: 1.(UDP)DatagramSocket:面向数据报(发送接收数据,必须以一定的数据报为单位进行传输) 2.(TCP)ServerSocket:面向字节流

UDP和TCP就是传输层的两个最重要的协议

UDP

实现一个最简单的服务器(回显服务器 echo server),客户端给服务器发送一个字符串,服务器把这个字符串返回显示出来

对于一个服务器程序,核心流程分成两步

1.进行初始化操作 2,进入主循环,接收并处理请求(主循环就是死循环) a)读取数据并解析 b)根据请求计算响应 c)把响应结果写回到客户端

服务器:

代码语言:javascript
复制
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

/**
 * UDP 服务器
 */
public class UdpEchoServer {
    //对于一个服务器程序,核心流程分成两步
    //1.进行初始化操作
    //2,进入主循环,接收并处理请求(主循环就是死循环)
    //  a)读取数据并解析
    //  b)根据请求计算响应
    //  c)把响应结果写回到客户端
    private DatagramSocket socket = null;
    //DatagramSocket 本质上是一个文件,这个文件是网卡的抽象

    //构造方法
    public UdpEchoServer(int port) throws SocketException {
        socket = new DatagramSocket(port);
        //new的时候就会让socket对象和一个端口号和一个IP地址关联在一起(绑定端口)
        //未来的客户端就按照这个IP和端口号来访问服务器
        //如果在构造socket的时候没有写IP,就是 0.0.0.0(会关联到这个主机的所有网卡IP)
        //IP是决定互联网的某个主机的位置,port是决定数据交给这个主机的哪个位置
    }

    public void start() throws IOException {
        System.out.println("服务器启动");
        while (true){
            //  a)读取数据并解析
            DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);
            //new byte[4096],4096  相当于关联了缓冲区
            // DatagramPacket是发送和接收数据的基本单位
            socket.receive(requestPacket);
            //程序启动之后马上就能执行到receive
            //大多时候调用receive的时候,客户端还没有发送请求,这时receive就会阻塞,当真的有客户端数据过来之后,就会把收到的数据放入缓冲区
            String request = new String(requestPacket.getData(), 0,requestPacket.getLength()).trim();
            //此处需要把请求数据转成string(本来是byte[])
            //requestPacket.getData()获取到缓冲区,也就是byte数组,然后从0开始,到缓冲区长度处结束
            //.trim():用户实际发送的数据可能远远小于4096,此时getLength()获取到的都是4096,此时就可以通过trim来去掉一些空白空间

            //  b)根据请求计算响应
            String response = process(request);
            //  c)把响应结果写回到客户端
            DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),
                    response.getBytes().length, requestPacket.getSocketAddress());
            //response.getBytes():响应数据就是response,需要包装成一个Packet对象
            //request.getBytes().length:获取长度,得到的是字符数
            //requestPacket.getSocketAddress():指定当前数据发给谁,这个方法就把IP端口号全部获取到,就设置到了responsePacket里面
            socket.send(responsePacket);

            //以下部分可省略
            System.out.printf("[%s:%d] req: %s; resp: %s\n",requestPacket.getAddress().toString(),
                    requestPacket.getPort(),request,response);
        }
    }

    private String process(String request) {
        //由于此处是一个回显服务器,所以只需要原分不动的返回
        //但是如果是其他复杂的服务器,就需要在这里有更多的逻辑
        return request;
    }

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

对于一个客户端程序,核心流程分成两步

1.从用户这里读取输入的数据 2.构造一个请求发送给服务器 3.从服务器读取响应 4.把响应写回给客户端

客户端:

代码语言:javascript
复制
import java.io.IOException;
import java.net.*;
import java.util.Scanner;

/**
 * UDP 客户端
 */
public class UdpEchoClient {
    //客户端的主要流程分为4步
    //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();//客户端创建socket的时候不需要绑定端口号,由操作系统自动分配一个空闲端口
    }

    public void start() throws IOException {
        Scanner scanner = new Scanner(System.in);
        while (true){
            //1.读取用户输入的数据
            System.out.print("->");//提示符:提示用户输入字符
            String request = scanner.nextLine();//作为请求
            if (request.equals("exit")){
                //结束
                break;
            }
            
            //2.构造一个请求发送给服务器
            DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),
                    request.getBytes().length, InetAddress.getByName(serverIP), serverPort);
            //InetAddress.getByName(serverIP), serverPort: 要把数据报发给哪个服务器:指定IP和端口号
            socket.send(requestPacket);

            //3.从服务器读取响应
            DatagramPacket responsePacket = new DatagramPacket(new byte[4096],4096);
            socket.receive(responsePacket);
            String response = new String(responsePacket.getData(),0,responsePacket.getLength()).trim();
            
            //4.把响应写回给客户端
            System.out.println(response);
        }
    }


    public static void main(String[] args) throws IOException {
        UdpEchoClient client = new UdpEchoClient("127.0.0.1",9090);
        //"127.0.0.1":是环回IP,因为此时客户端和服务器在一台主机上
        //9090:这个端口要和服务器绑定的端口相匹配
        client.start();
    }
}

如果想要完成较为复杂的逻辑,就可以通过继承,重写process方法实现 例如现在想要完成词典翻译的服务器:

代码语言:javascript
复制
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("find","找到");
    }

    @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();
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-03-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • UDP
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档