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

使用 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,不然服务器就连错了

运行结果

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

RGB与gray图互转

参考博客 https://www.cnblogs.com/alex-bn-lee/p/15140708.html 显示图片 import cv2 from PIL import Imageimg cv2.imread("./mingyu.png") img cv2.cvtColor(img, cv2.COLOR_BGR2RGB)display(Image.fromarray(img)) RGB 转gray gray cv2.cvtColor(img, cv2…

【从零开始学习Redis | 第八篇】认识Redis底层数据结构(下)

目录 前言&#xff1a; ZipList&#xff1a; Ziplist的特性: QucikList: QuicList特征&#xff1a; SkipList&#xff1a; 跳表特征&#xff1a; RedisObijct&#xff1a; 小心得&#xff1a; 总结&#xff1a; 前言&#xff1a; 在现代软件开发中&#xff0c;数据…

NGINX 反向代码 CORS

我遇到了一个问题就是 Nginx 是作为反向代理服务器部署的&#xff0c;但因为 Nginx 的配置导致 CORS 问题。 在这个时候我们可以对 Nginx 的配置文件进行修改&#xff1a; 在 location 后添加下面的内容&#xff1a; add_header Access-Control-Allow-Origin *; add_header A…

浏览器https受信任证书生成——openssl颁发受信任证书

站点常常由于没有受信任的第三方CA机构颁发证书,使用https访问时,浏览器常常会弹出不安全的提示,为解决该问题,可以使用openssl颁发个人证书来解决该问题。 1openssl安装及使用方式参考:32.9 x509_OpenSSL 中文手册https://www.openssl.net.cn/docs/230.html2.本文章所有生…

快速匹配和编译NXP官方uboot-imx

目录 概述 1 搭建编译环境 2 下载和编译uboot-imx 2.1 下载软件包 2.2 编译代码 3 总结 概述 本文主要讲述如何快速匹配和编译NXP官方uboot-imx。文中总结了生成u-boot文件的整个流程&#xff0c;笔者通过实操的方法&#xff0c;一步步从编译器下载&#xff0c;编译环境…

使用postman调用Vcenter-Api

一、下载postman Postman API Platform 二、Vcenter-APi-文档 Create Session | CIS | vSphere CIS REST APIs 三、如何调用&#xff1f; 一、获取访问凭证 两种方式进行鉴权&#xff0c;这里讲第一种。 二、使用postman调用Api获取凭证 下面就是vmware-api-session-id …

Linux Php 连接 SAP Hana数据库客户端

下载地址 : SAP Development Tools https://tools.hana.ondemand.com/#hanatools 进入hanaclient-2.19.21-linux-x64 无需编译&#xff0c;运行 ./hdbinst 提示没有权限&#xff0c;执行chmod x * 有个子目录里面的也是没有权限&#xff0c;进入那个子目录 执行chmod …

MySQL WHERE 条件查询

我们通常要求在执行 SELECT 查询时&#xff0c;都要带上查询条件。那这一节&#xff0c;我们就来学习一些简单的 WHERE 条件查询。 我们仍然以技术派文章表 article 为例&#xff0c;比如说我们要查找标题为“聊聊分库分表”的文章&#xff0c;可以这么写&#xff1a; SELECT *…

Nginx(Docker 安装的nginx)配置域名SSL证书

1.首先确保Linux环境上已经安装了docker&#xff08;可参考VMware使用和Linux安装Docker_wmware直接部署linux和安装docker后-CSDN博客 2.通过docker 安装nginx&#xff08;可参考Linux 环境安装Nginx—源码和Dokcer-CSDN博客&#xff09; 3.安装SSL证书 3.1 在宿主机中创建…

DaisyDisk for mac 苹果电脑磁盘清理工具

DaisyDisk for Mac是一款直观易用的磁盘空间分析工具&#xff0c;专为Mac用户设计&#xff0c;旨在帮助他们快速识别和管理磁盘上的文件与文件夹&#xff0c;从而释放存储空间。 软件下载&#xff1a;DaisyDisk for mac 激活版 DaisyDisk采用独特的可视化界面&#xff0c;将磁盘…

R语言使用函数随机抽取并求均值和做T检验,最后输出随机抽取50次均值和pvalue的结果

1.输入数据&#xff1a;“5utr-5d做ABD中有RG4和没有RG4的TE之间的T检验.csv” 2.代码&#xff1a; setwd("E:\\R\\Rscripts\\5UTR_extended_TE") # 载入必要的库 library(tidyverse) library(dplyr) library(openxlsx) # 读取数据 data <- read.csv("5ut…

机器学习笔记(4)—逻辑回归(Logistic Regression)

文章目录 逻辑回归&#xff08;Logistic Regression&#xff09;分类问题假说表示判定边界代价函数简化的成本函数和梯度下降多类别分类&#xff1a;一对多 逻辑回归&#xff08;Logistic Regression&#xff09; 分类问题 分类问题中&#xff0c;我们要预测的变量 y y y是一…

第2章 进程与线程(4)

2.4 死锁 多个进程因竞争资源而造成的一种僵局。若无外力,这些进程都无法推进。 2.4.1 死锁的概念 死锁,饥饿,死循环的对比 死锁产生的原因: (1)系统资源的竞争 (2)进程不合理的推进顺序 (3)信号量使用不恰当也会造成死锁 总结:对不可剥夺的资源的不合理分配导致死锁 死锁产…

吴恩达机器学习笔记 二十九 树的增强 XGBoost 极端梯度提升 什么时候使用决策树 决策树和神经网络的比较

增强树&#xff1a;和随机森林类似&#xff0c;但再抽取时每个样本被抽到的概率不是相同的&#xff0c;而是让算法更容易选到使之前训练的树错误分类的样本。这种方式被称为刻意练习(deliberate practice)&#xff0c;相当于把做的不好的部分再拿出来练习一遍。 XGBoost&#x…

基于nodejs+vue文学创作的社交论坛python-flask-django-php

课题主要采用nodejs技术和MySQL数据库技术以及express框架进行开发。系统主要包括个人中心、用户管理、文章类型管理、文章信息管理、文章举报管理、警告信息管理、系统管理等功能&#xff0c;从而实现智能化的社交论坛管理方式&#xff0c;提高社交论坛管理的效率。 前端技术&…

R折线图(自备)

目录 折线图基础 创建散点和折线图 复杂折现加图例 折线图柱状图 数据处理 进行差异检验 基础绘图折线 基础绘图箱线 进行合并 双轴柱状与折线图 数据 折线图基础 创建散点和折线图 rm(list ls()) opar <-par(no.readonlyTRUE)##自带orange数据集 par(mfrowc…

科技引领趋势:3D元宇宙展厅在各行业中的应用及其未来展望

随着技术的不断进步&#xff0c;3D元宇宙展厅正逐渐成为各行各业展示产品的新选择。相较于传统的线下展厅&#xff0c;3D元宇宙展厅以其独特的优势&#xff0c;为产品展示和品牌推广提供了全新的可能性。 一、虚拟与现实的完美融合 3D元宇宙展厅是指在虚拟世界中构建的三维展览…

小程序接入第三方信息流流程 下载SDK

由第三方信息流提供相应的SDK下载链接以及接入说明和开发文档或其他方式接入&#xff0c;如果第三方能支持小程序SDK&#xff0c;则不需要后面步骤&#xff0c;只需要提供相关开发文档和接入方式接口 接入SDK 后台开发人员接入第三方提供的SDK&#xff0c;并进行相关接口开发…

DFS深度优先搜索刷题(二)

一.P1683 入门 算法思想&#xff1a;设置瓷砖状态st&#xff0c;这里瓷砖状态是否走过决定计数与否&#xff0c;因为可以重复走过但只记一次&#xff0c;所以可以不用回溯。每一次dfs都记录此时的坐标与进入可能的新坐标。 const int N 25;int W, H; char map[N][N];//存地图…

二叉树的遍历、存储、性质、定义——数据结构——day7

树的定义 树的定义&#xff1a;树(Tree)是n(n≥0)个结点的有限集。n0 时称为空树。在任意一棵非空树中&#xff1a; (1)有且仅有一个特定的称为根(Root)的结点&#xff1b; (2)当n>1时&#xff0c;其余结点可分为m(m>0)个互不相交的有限集T1、T2、……、Tm,其中每一个集…