网络编程(1)写一个简单的UDP网络通信程序【回显服务器】,并且实现一个简单的翻译功能

news2024/12/26 22:03:46

使用 JAVA 自带的api

目录

一、回显服务器 UdpEchoServer

服务器代码

客户端代码

二、翻译功能 UdpDictServer

在UdpDictServer里重写process方法


一、回显服务器 UdpEchoServer

/**
 * 回显服务器
 * 写一个简单的UDP的客户端/服务器 通信的程序
 * 这个程序没有啥业务逻辑,只是单纯的调用socket api
 * 让客户端给服务器发送一个请求,从控制台输入的字符串
 * 服务器收到字符串后,会把这个字符串原封不动的返回给客户端,客户端再显示出来

   运行过程
 * 1.先启动服务器 ,程序会进入while循环,执行到receive()阻塞,等待客户端的请求
 * 2.再启动客户端,程序也会进入while循环,执行到scanner 等待用户输入
 *      当用户输入字符串之后,next就会返回,构造请求数据,并发送给服务器
 * 3.客户端发送数据之后
 *      服务器就会从receive中返回,进一步执行解析请求UDP报,执行process计算响应操作,最后执行send操作,发送响应结果
 *      客户端接着执行到receive,等待服务器的响应
 * 4.客户端接收到服务器响应的数据之后,从receive中返回,执行打印操作,把响应的内容显示出来了
 * 5. 服务器执行完后,重新进入while循环,又执行到receive这里阻塞
 *    客户端执行完后,也重新进入while循环,执行到scanner这里阻塞
 *
 */

服务器代码

package network;

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


public class UdpEchoServer {
    //创建一个DatagramSocket对象,后续操作网卡的基础
        //socket 就是把网卡抽象成了文件
        //往socket文件中 写数据 ,就相当于通过网卡 发送数据
        //从socket文件中 读数据 ,就相当于通过网卡 接收数据
        //把网络通信和文件操作给统一了
    //在Java中就使用这个类,来表示系统内部的 socket 文件了
    //常用的socket的方法:receive(DatagramPacket P) ,send(DatagramPacket P), close

    //DatagramPacket 这个类,用来表示一个UDP数据报
    //UDP是面向数据报的
    //每次进行传输,都要以UDP数据包为基本单位
    private DatagramSocket socket = null;

    //构造方法
    //服务器需要手动 显示指定端口号,可以避免端口号冲突
    //客户端的socket 一般不能显示指定(系统会随机分配一个端口)
    //传入参数为 int port
    public UdpEchoServer(int port) throws SocketException {
        //手动指定端口号
        socket = new DatagramSocket(port);
        //不带参数就是系统自动分配端口号
//        socket = new DatagramSocket();
    }
    //服务器启动方法
    //通过这个方法来启动服务器
    public void start() throws IOException {
        //服务器启动提示
        System.out.println("服务器启动!");
        //服务器一般开了就不关了,7*24小时不停歇运转,所以是while(true)形式
        while(true){
            //1.读取请求并解析
            //创建UDP数据报 DatagramPacket对象 接收 客户端的数据
            //收到的数据需要用内存空间保存,而DatagramPacket 内部不能自行分配内存空间
            //于是需要程序员手动把空间创建好,交给DatagramPacket 进行处理,使用字节数组创建
            DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);//保存请求信息
            socket.receive(requestPacket);//接收请求信息。数据没来的时候,会先阻塞,直到客户端把请求发来为止
            //接收到的数据,是以二进制的形式存储到DatagramPacket中了
            //要想显示出来,需要将这个二进制数据转换成字符串
            String request = new String(requestPacket.getData(),0,requestPacket.getLength());
            //参数为 二进制数据,偏移量从0开始到requestPacket.getLength()这个数据结尾

            //2.根据请求计算响应
            //实际开发项目中,服务器中最核心的步骤,绝大数程序都是在完成这一部分
            String response = process(request);

            //3.把响应写回到客户端
            // 创建响应对象,DatagramPacket
            // 往这个对象里构造刚才的数据,再通过send返回
            DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),response.getBytes().length,requestPacket.getSocketAddress());
            //传入的参数 获取 数据的起始地址response.getBytes(),数据的字节长度response.getBytes().length,响应给 客户端的ip地址requestPacket.getSocketAddress()
            //指定字节数组缓冲区,同时指定 客户端UDP请求报中的网卡信息requestPacket.getSocketAddress()(其中包含了ip和端口号)
            //网络传输,使用字节,以字节为单位
            socket.send(responsePacket);

            //4.打印一个日志,把这次数据交互的详情打印出来
            System.out.printf("[%s:%d] request=%s response=%s\n",requestPacket.getAddress().toString(),
                    requestPacket.getPort(),request,response);
            //打印的内容:客户端的ip:客户端的端口号 请求内容 响应内容
        }

    }
    //响应程序
    //这里只是简单回显
//这里写public才能被重写
    public String process(String request) {
        return request;
    }

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

客户端代码

package network;

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

public class UdpEchoClient {
    private DatagramSocket socket = null;//对网卡进行操作,接收或发送数据报,或者关闭
    //因为UDP报不会建立链接,也不会存储对端的信息
    //所以在应用程序里把它存储起来
    private  String serverIp = "";
    private int serverPort = 0;
    public UdpEchoClient(String ip , int port) throws SocketException {
        //客户端不能指定端口号码,会端口冲突
        socket = new DatagramSocket();//客户端 系统随机分配端口,不写参数就是系统随机分配
        //因为UDP报不会建立链接,也不会存储对端的信息
        //所以在应用程序里把它存储起来
        //这里主要记录对端的 ip 和 端口
        serverIp = ip;
        serverPort = port;
    }
    //启动客户端程序
    public void start() throws IOException {
        //启动客户端提示
        System.out.println("客户端启动!");
        //用户输入字符串
        Scanner scanner = new Scanner(System.in);
        while(true){
            //1.从控制台读取数据,作为请求
            System.out.print("->");//输入提示符
            String request = scanner.next();//请求信息的内容

            //2.把请求内容构造成一个DatagramPacket对象,发送给服务器
            DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),request.getBytes().length,
                    InetAddress.getByName(serverIp),serverPort);
            //request.getBytes(),request.getBytes().length指定字节数组缓冲区,同时指定 ip 和 端口号 InetAddress.getByName(serverIp),serverPort
            socket.send(requestPacket);//发送UDP数据报

            //3.尝试读取客户端的响应
            DatagramPacket responsePacket = new DatagramPacket(new byte[4096],4096);//创建一个空的UDP数据报来接收服务器的响应数据
            socket.receive(responsePacket);

            //4.把接收的响应数据 由二进制 转换成 字符串 显示出来
            String response = new String(responsePacket.getData(),0,responsePacket.getLength());
            System.out.println(response);
        }
    }

    public static void main(String[] args) throws IOException {
        UdpEchoClient client = new UdpEchoClient("127.0.0.1",9090);//该参数为对端(服务器)的ip和端口
        client.start();
    }
}

运行结果:

* 1.先启动服务器 ,程序会进入while循环,执行到receive()阻塞,等待客户端的请求

* 2.再启动客户端,程序也会进入while循环,执行到scanner 等待用户输入

* 当用户输入字符串之后,next就会返回,构造请求数据,并发送给服务器

* 3.客户端发送数据之后

* 服务器就会从receive中返回,进一步执行解析请求UDP报,执行process计算响应操作,最后执行send操作,发送响应结果

* 客户端接着执行到receive,等待服务器的响应

* 4.客户端接收到服务器响应的数据之后,从receive中返回,执行打印操作,把响应的内容显示出来了

* 5. 服务器执行完后,重新进入while循环,又执行到receive这里阻塞 * 客户端执行完后,也重新进入while循环,执行到scanner这里阻塞 * */ 

二、翻译功能 UdpDictServer

在回显服务器的基础上,创建一个新的类,继承回显服务器

在UdpDictServer里重写process方法

package network;

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("今天","today");
        dict.put("cat","猫");
        dict.put("dog","狗");
        dict.put("today","今天");
    }



    //重写父类 UdpEchoServer 的process方法
    //完成翻译逻辑,翻译本质上是“查表”
    //刚才再dict哈希表里添加了一些键值对元素

    //刚才在重写的地方报错
    //原因是 父类的process方法之前用的是private
    //而private封装特性,不能被重写
    //改成public之后就可以了
    @Override
    public String process(String request) {
//        return dict.get(request);
        return dict.getOrDefault(request,"该单词目前不在表中,无法查看!!");//差不到表中信息,可以给默认值
    }

    public static void main(String[] args) throws IOException {
        //如果端口号也是9090就与父类的端口号冲突了
        UdpDictServer dictServer = new UdpDictServer(6666);//指定这个翻译功能 的端口是6666
        dictServer.start();//此时,这里调用start的是子类UdpDictServer,所以后面调用的process也是子类重写的方法
        //这里就是之前学到的多态
    }
}

 注意:

翻译服务器里main方法里的端口要与父类不一样,避免端口号冲突

同时客户端开启的时候,要把端口号修改过来6060,不然服务器就连错了

运行结果

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1547287.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Windows版 CUDA安装

目录 一、说明 二、安装工具下载 三、CUDA安装 四、cuDNN配置 五、验证安装是否成功 一、说明 windows10 版本安装 CUDA &#xff0c;首先需要下载两个安装包 CUDA toolkitcuDNN 官方教程 CUDA&#xff1a;https://docs.nvidia.com/cuda/cuda-installation-guide-micro…

1.4.1 着色器

着色器&#xff08;Shader&#xff09;是运行在GPU上的小程序&#xff0c;这些小程序为图形渲染管线的某个特定部分而运行&#xff0c;从基本意义上来说&#xff0c;着色器只是一种把输入转化为输出的程序。 一、着色器类QOpenGLShaderProgram QOpenGLShaderProgram是Qt中对着…

[WTL/Win32]_[初级]_[如何设置ListView的列宽不出现水平滚动条]

场景 开发WTL/Win32的程序时&#xff0c;经常会用到表格控件CListViewCtrl。这个控件需要设置列的宽度&#xff0c;当用完100%的宽度来平均分配给列宽时&#xff0c;一加载数据多&#xff0c;就会出现垂直滚动条后&#xff0c;水平滚动条也会同时出现的问题。怎么设置才能让水…

标题:深入了解 ES6 模块化技术

在 ES6 版本之前&#xff0c;JavaScript 一直缺乏一个内置的模块系统&#xff0c;这给大型项目的开发带来了一些挑战。ES6 引入了模块化的概念&#xff0c;为 JavaScript 开发者提供了一种更好的组织和管理代码的方式。 模块是 JavaScript 的一种代码组织方式&#xff0c;它将代…

【Python】输出一个 Python 项目下需要哪些第三方包

方法一 pycharm 方法二 要分析一个 Python 项目下需要哪些第三方包并生成 requirements.txt 文件&#xff0c;你可以使用 pipreqs 工具。以下是具体的步骤&#xff1a; 首先&#xff0c;确保你已经安装了 pipreqs 工具。如果未安装&#xff0c;可以使用以下命令进行安装&a…

Python包管理工具 pip 及其常用命令和参数用法

目录 PIP 主要功能 安装包 升级包 卸载包 列出包 检查依赖 pip的配置和环境 主要用法 1&#xff1a;版本 2&#xff1a;安装 Python 库 3&#xff1a;升级库 4&#xff1a;卸载库 5&#xff1a;搜索库 6&#xff1a;查看已安装库详细信息 7&#xff1a;只下载库…

海格里斯助推实体制造业转型升级 “算法定义硬件”解题AIoT市场

随着自动化的发展&#xff0c;电子商务和智能制造推动了自动化立体仓库的快速发展与创新&#xff0c;产生了“密集仓储”的概念。对于一个实体企业来讲&#xff0c;其数智物流转型正在趋向于“去伪存真”&#xff0c;企业追求高ROI与真实经济价值&#xff0c;具有降本增效的业务…

Day48:WEB攻防-PHP应用文件上传中间件CVE解析第三方编辑器已知CMS漏洞

目录 PHP/ASP-中间件-上传相关-IIS&Apache&Nginx(解析漏洞) IIS Apache Nginx PHP-编辑器-上传相关-第三方处理引用 PHP-CMS源码-上传相关-已知识别到利用 知识点&#xff1a; 1、PHP-中间件-文件上传-CVE&配置解析 2、PHP-编辑器-文件上传-第三方引用安全 3…

2024.3.26 QT

思维导图 实现闹钟 头文件&#xff1a; #define ALARM_CLOCK_H#include <QWidget> #include <QTime> #include <QTimerEvent> #include <QTimer> #include <QtTextToSpeech> //文本转语音类 #include <QDebug>QT_BEGIN_NAMESPACE namespa…

工业镜头常用参数之实效F(Fno.)和像圈

Fno. 工业镜头中常用到的参数F&#xff0c;有时候用F/#&#xff0c;Fno.来表示&#xff0c;指的是镜头通光能力的参数。它可用镜头焦距及入瞳直径来表示&#xff0c;也可通过镜头数值孔径&#xff08;NA&#xff09;和光学放大倍率&#xff08;β&#xff09;来计算。有效Fno.…

微软开源项目Garnet:Redis的竞争者还是替代者?

对于开源社区&#xff0c;最近的一大新闻就是Redis宣布从7.4版本开始&#xff0c;将采用Redis源代码可用许可证&#xff08;RSALv2&#xff09;和服务器端公共许可证&#xff08;SSPLv1&#xff09;的双重许可证&#xff0c;取代原有的BSD三条款许可证。这一变化引发了开发者社…

前端日期组件layui使用,月模式

初学前端&#xff0c;实战总结 概要 有一个日期组件&#xff0c;我的谷歌浏览器选完日期后&#xff0c;偶尔获取不到最新数据&#xff0c;有一个客户&#xff0c;是经常出不来数据。 日期组件是Wdate&#xff1a;调用的方法是WdatePicker onpicking&#xff0c;代码片段如下…

基于Python实现多功能翻译助手(下)

为了将上述步骤中的功能增强与扩展具体化为代码&#xff0c;我们将实现翻译历史记录功能、翻译选项配置以及UI的改进。 翻译历史记录功能 import json # 假设有一个用于存储历史记录的json文件 HISTORY_FILE translation_history.json # 初始化历史记录列表 translati…

HarmonyOS网格布局:List组件和Grid组件的使用

简介 在我们常用的手机应用中&#xff0c;经常会见到一些数据列表&#xff0c;如设置页面、通讯录、商品列表等。下图中两个页面都包含列表&#xff0c;“首页”页面中包含两个网格布局&#xff0c;“商城”页面中包含一个商品列表。 上图中的列表中都包含一系列相同宽度的列表…

【Unity人机交互】人工智能之爬虫开章

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;Uni…

如何使用WordPress插件保护网站的安全

前段时间我们的网站受到了黑客的攻击&#xff0c;网站丢失了一些重要的数据&#xff0c;为了防止这种情况的再次发生&#xff0c;我们准备将网站全部迁移到高防服务器&#xff0c;经过一番对比后&#xff0c;我们选择了Hostease提供的高防服务器。它可以有效地抵御各种类型的网…

存内计算:释放潜能的黑科技

什么是存内计算&#xff1f; 存内计算技术是一种新型的计算架构&#xff0c;它将存储器和计算单元融合在一起&#xff0c;以实现高效的数据处理。存内计算技术的优势在于能够消除数据搬运的延迟和功耗&#xff0c;从而提高计算效率和能效比。目前&#xff0c;存内计算技术正处…

Web APIs知识点讲解(阶段三)

DOM- 节点操作 一.节点操作 1.DOM节点 目标&#xff1a;能说出DOM节点的类型 DOM节点 DOM树里每一个内容都称之为节点 节点类型 元素节点 所有的标签 比如 body、 div html 是根节点 属性节点 所有的属性 比如 href 文本节点 所有的文本 document树&#xff1a; 总结&…

代码随想录 Day58 单调栈

今天新学了单调栈&#xff0c;个人感觉蛮简单&#xff0c;只是在栈的基础上加了一条限制条件&#xff08;即递增或递减&#xff09;

苹果Find My产品需求增长迅速,伦茨科技ST17H6x芯片供货充足

苹果的Find My功能使得用户可以轻松查找iPhone、Mac、AirPods以及Apple Watch等设备。如今Find My还进入了耳机、充电宝、箱包、电动车、保温杯等多个行业。苹果发布AirTag发布以来&#xff0c;大家都更加注重物品的防丢&#xff0c;苹果的 Find My 就可以查找 iPhone、Mac、Ai…