【JavaEE】——回显服务器的实现

news2024/11/22 16:33:24

 8e19eee2be5648b78d93fbff2488137b.png

阿华代码,不是逆风,就是我疯

你们的点赞收藏是我前进最大的动力!!

希望本文内容能够帮助到你!!

目录

一:引入

1:基本概念

二:UDP socket API使用

1:socket文件

2:DatagramSocket类

(1)构造方法

(2)方法

3:DatagramPacket类

三:回显服务器——服务器

1:引入(必看)

2:服务器响应代码

(1)注释版本

(2)无注释版本

3:细节补充

4:特点

四:回显服务器——客户端

1:代码

(1)注释版本

(2)无注释版本

2:注意点

五:回显服务器过程文字梳理

六:知识补充


前引:本文代码建议反复敲打至少3遍!!!!

一:引入

1:网络编程的基本概念

网络编程就是通过写代码来完成基于网络的跨主机通信

本质上是学习传输层给应用层提供的一系列的API,通过API把数据交给传输层,在经过层层封装之后,通过网卡,把数据发送出去。

这里使用的API是传输层提供的,传输层涉及到的主要协议有两个:TCP和UDP

后面通过代码详细理解这些特点

①有/无连接:这里的“连接”是虚拟的,抽象的连接

例:打电话——打过去对方接才能通话;微信发消息不管对面在不在线,消息都发出去了

②可/不可靠传输:可以知道数据到没到达对方

③面向字节流:传输数据的基本单位就是字节

④面向数据报:传输的的基本单位是一个“数据报”——由一系列字节构成的特定结构UDP

⑤全双工:可以双向通信

⑥半双工:只能单向通信

客户端:发送请求的一方,发送的数据叫做“请求”

服务器:被动接受请求的一方,给客户端返回的数据叫做“响应”

客户端和服务器之间的交互有这几种模式:“一问一答”,“一问多答”,“多问一答”,“多问多答”,

二:UDP socket API使用

引入:UDP核心类有两个DatagramSocket,DatagramPacket

1:socket文件

操作系统中有一类文件就叫做socket文件,区别于放在硬盘上的普通文件,socket文件是放在“网卡”这样的硬件设备上——通过网卡发送数据,就是写socket文件;接受数据,就是读socket文件

2:DatagramSocket类

(1)构造方法

(2)方法

3:DatagramPacket类

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

(1)构造方法

(2)方法

三:回显服务器——服务器

1:引入(必看)

以下代码是实现一个“回显服务器”——是网络编程中的“hello world”,但是对新手小白并不友好

大致流程为:客户端发出请求,服务器收到客户端的请求,完成业务并返回响应,客户端接受响应

先附赠上服务器的代码,(按照步骤去边理解边敲)(重在理解,重在理解)

2:服务器响应代码

(1)注释版本

package network;

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

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: Hua YY
 * Date: 2024-10-07
 * Time: 17:20
 */
public class UdpEchoServer {
    //1:创建DatagramSocket对象
    private DatagramSocket socket = null;//socket:插槽插座
    //2:构造方法,服务器一启动,就要关联/绑定上一个操作系统中的端口号(服务器的端口号哦啊通常由程序员指定)
    //抛出的异常通常为scoket创建失败
    public UdpEchoServer(int port) throws SocketException {
        socket = new DatagramSocket(port);//端口号port
    }
    //3:服务器启动逻辑
    //5:抛异常,网络编程socket本质上也是IO
    public void start() throws IOException {
        System.out.println("服务器启动");
        while(true){
            //3:创建一个数据报,它是每次发送数据和接收数据的一个基本单位
            // 参数为输出型参数,字节数组,对应UDP的载荷部分,一开始是空的
            DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);
            //4;socket读网卡能读到一个UDP数据报(里面会包含数据源IP,源端口),放到requestPacket(数据报)对象中
            //如果没有接受到请求那么就会阻塞等待,此处收到的数据是先存到socket文件的内存缓冲区中。非硬盘
            socket.receive(requestPacket);
            //5:基于字节数组构造String对象,数组中的数据可能是文本数据(给String刚好)也可能是二进制数据(Java也能保存)
            //这里的长度是有效长度
            String request = new String(requestPacket.getData(),0,requestPacket.getLength());
            //6:根据请求计算响应
            String response = process(request);
            //7:把响应(String)字节给拎出来,构造成一个DatagramPacket数据报,在传入socket对象(因为4中我们说过收到请求时,socket能读到源IP和源端口)
            //这时我们把这个源IP和源端口,作为响应的目的IP和目的端口(确认客户端的发出请求的位置),返回回去
            //注:response.length()单位是字符,此处单位是字节
            DatagramPacket responsePacket = new DatagramPacket(response.getBytes() , response.getBytes().length , requestPacket.getSocketAddress());
            socket.send(responsePacket);

        }
    }
    //7:构造响应,这里是回显服务器,所以就是单纯的return

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

}

(2)无注释版本

package repeat2;

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

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: Hua YY
 * Date: 2024-10-10
 * Time: 18:28
 */
public class UdpServer {
    private DatagramSocket socket = null;
    public UdpServer(int port) throws SocketException {
        socket = new DatagramSocket(port);
    }
    public void start() throws IOException {
        System.out.println("服务器启动");
        while(true){
            DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);
            socket.receive(requestPacket);
            //转化为字符串
            String request = new String(requestPacket.getData(),0,requestPacket.getLength());
            String response = process(request);
            DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),response.getBytes().length,
                    requestPacket.getSocketAddress());
            socket.send(responsePacket);
            System.out.printf("[%s,%d]  request: %s  response: %s\n ",
                    requestPacket.getAddress().toString(),requestPacket.getPort(),request,response);
        }
    }
    public String process(String request){
        return request;
    }

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

3:细节补充

这里在补充一些细节:

①创建完socket对象后,可以通过socket对象来操作网卡(具体:因为socket对象是在内存中的,针对这个内存对象进行操作就可以影响到网卡)

②构造方法(还有无参的上面有写)中的参数,是我们指定的,进程一启动就要绑定上操作系统中的端口号,这个端口号是一个整数,用来区分一个主机上的进行网络通信的不同程序

一个端口号只能被一个进程绑定,但是一个进程可以绑定多个端口号(像极了爱情~~,爱情中宁死不做端口号~~)

③SocketException,类似端口号被别的进程占用就会报异常

④因为服务器需要不停的运作,所以while一直循环

⑤数据报中的数组就是载荷部分

⑥receive有阻塞等待功能

⑧数据报的位置在socket对象的内存缓冲区中

⑨构造响应数据报

4:特点

上述代码可以体现出UDP是——

(1)无连接通信

UDP的DAtagramSocket自身并不需要保存对端的IP和端口,对端IP和端口在数据报中就已经包含,另外代码中也没有“建立连接”和“接受连接”这种操作

(2)不可靠数据——代码没体现(略)

(3)面向数据报

send方法和receive方法都是以DatagramPacket为基本单位的

(4)全双工

一个socket既可以发送数据报又可以接受数据报(属于是自力更生了)

四:回显服务器——客户端

1:代码

(1)注释版本

package network;

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

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: Hua YY
 * Date: 2024-10-07
 * Time: 17:20
 */
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();//传入参数为请求的目的ip和目的端口,源ip为本机ip源端口为系统分配的端口


    }
    public void start() throws IOException {
        System.out.println("客户端启动");
        Scanner scanner = new Scanner(System.in);
        while(true){
            System.out.print("->");
            if (!scanner.hasNext()){//如果没有输入的话就结束循环
                break;
            }
            String request = scanner.next();//人为输入请求
            DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),request.getBytes().length,
                    InetAddress.getByName(serverIp),serverPort);//指定服务器的ip和端口,分开的
            socket.send(requestPacket);
            DatagramPacket responsePacket = new DatagramPacket(new byte[4096] , 4096);
            socket.receive(responsePacket);
            //转化为字符串
            String response = new String(responsePacket.getData(),0,responsePacket.getLength());//内置getLength()获取length成员变量
            System.out.println(response);



        }
    }

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

(2)无注释版本

package repeat2;

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

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: Hua YY
 * Date: 2024-10-10
 * Time: 18:29
 */
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.print("->");
            if(!scanner.hasNext()){
                break;
            }
            String request = scanner.next();
            DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),
                    request.getBytes().length, InetAddress.getByName(serverIp),serverPort);
            socket.send(requestPacket);
            //接收响应
            DatagramPacket responsePacket = new DatagramPacket(new byte[4096] , 4096);
            socket.receive(responsePacket);
            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",9096);
        client.start();
    }
}

2:注意点

(1)服务器端口号需要手动指定是确保,客户端可以找到服务器,客户端的端口号是操作系统的内核随机分配的 (确保分配的端口号是空闲可用的)

(2)Scanner从控制台读取字符串最好使用next非nextLine

(如果是从文件读取就无所谓了)

①next读取

②nextLine读取

(3).length和.length()方法的区别

五:回显服务器过程文字梳理

六:知识补充

1:.length和.length()的区别

引用文章java中length和length()的区别_length变量与length函数 java-CSDN博客

2:字符串转数组

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

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

相关文章

zookeeper ——watcher

这应该不是目录 1.watcher定义和说明1.1定义1.2特性1.3watcher的通知状态Watcher.Event.KeeperState1.4watcher的事件类型Event.EventType1.5基本流程 1.watcher定义和说明 1.1定义 在ZooKeeper中,Watcher是一种机制,用于在节点(znode&#…

2024百度云智大会|百度大模型内容安全合规探索与实践

9月25日,2024百度云智大会在北京举办。会上,百度智能云分别针对算力、模型、AI 应用,全面升级百舸 AI 异构计算平台 4.0、千帆大模型平台 3.0 两大 AI 基础设施,并升级代码助手、智能客服、数字人三大 AI 原生应用产品。 在大模型…

网络编程(17)——asio多线程模型IOThreadPool

十七、day17 之前我们介绍了IOServicePool的方式,一个IOServicePool开启n个线程和n个iocontext,每个线程内独立运行iocontext, 各个iocontext监听各自绑定的socket是否就绪,如果就绪就在各自线程里触发回调函数。为避免线程安全问题&#xf…

Auto-Animate:是一款零配置、即插即用的动画工具,可以为您的 Web 应用添加流畅的过渡效果

嗨,大家好,我是小华同学,关注我们获得“最新、最全、最优质”开源项目和高效工作学习方法 用户体验成为了检验产品成功与否的关键因素。而动画效果,作为提升用户体验的重要手段,在网页和应用开发中扮演着举足轻重的角色…

【笔记学习篇】一篇文章搞定Mybatis-快速回顾

概述 5.1.1 Mybatis简介 Mybatis是一款优秀的持久层框架,它以sql为中心,支持定制化sql、存储过程以及高级映射。 使用Mybatis框架,可以无需手动编写基础的JDBC代码、无需手动设置参数和转换结果集到对象。 Mybatis可以使用简单的xml或注解来…

App测试时常用的adb命令

adb 全称为 Android Debug Bridge(Android 调试桥),是 Android SDK 中提供的用于管理 Android 模拟器或真机的工具。 adb 是一种功能强大的命令行工具,可让 PC 端与 Android 设备进行通信。adb 命令可执行各种设备操作&#xff0…

银发产业资讯丨蚂蚁集团、金城药业、百联集团、京东健康布局业务

银发经济『新趋势大数据』 AgeNews 每日银发产业大事件速览 2024-10-8 星期二 AgeClub整理 金融监管总局:鼓励险企提供更多养老保障服务 蚂蚁集团等签署合作协议,聚焦智慧医疗领域 金城医药等合作聚焦年长女性健康科技领域 京东健康助力四川发放…

Internet Download Manager6.42免费版下载神器新体验

🚀 开篇就燃!你的下载速度被“TA”承包了 #### 🌟 初识IDM 6.42,下载界的“超跑”驾到 各位追求效率的小伙伴们,今天小红要来揭秘一款让我彻底告别“龟速”下载的神器——Internet Download Manager (简称IDM) 6.42版&…

日语学习零基础生活日语口语柯桥外语学校|股票用日语怎么说?

在日语中,“股票”可以说: • 株(かぶ) 这是最常用的表达方式,直接表示“股票”。 例如: 株を買う - 买股票 株を売る - 卖股票 • 株式(かぶしき) 这个词也是“股票”的意…

学习文档(二)

异常 这是Java 异常类层次结构图概览: Exception 和 Error 有什么区别? 一、概念与本质 Exception(异常):异常是在程序运行过程中出现的可预料的、可恢复的不正常情况。例如,试图打开一个不存在的文件时&#xff0…

【数据结构-栈】【位运算优化】力扣3170. 删除星号以后字典序最小的字符串

给你一个字符串 s 。它可能包含任意数量的 ‘’ 字符。你的任务是删除所有的 ’ 字符。 当字符串还存在至少一个 ‘*’ 字符时,你可以执行以下操作: 删除最左边的 ‘’ 字符,同时删除该星号字符左边一个字典序 最小 的字符。如果有多个字典…

【C++篇】虚境探微:多态的流动诗篇,解锁动态的艺术密码

文章目录 C 多态详解(进阶篇)前言第一章:多态的原理1.1 虚函数表的概念1.1.1 虚函数表的生成过程 1.2 虚表的存储位置 第二章:动态绑定与静态绑定2.1 静态绑定2.1.1 静态绑定的实现机制:2.1.2 示例代码: 2.…

从0到1:小区业主决策投票小程序开发笔记

可研 小区业主决策投票小程序: 便于业主参与社区事务的决策,通过网络投票的形式,大大节省了业委会和业主时间,也提高了投票率。其主要功能:通过身份证、业主证或其他方式确认用户身份;小区管理人员或业委会…

YOLO5的修改

在传统的yolov5网络中并不存在注意力机制,但是源代码中存在相关简略的代码: def __init__(self, c, num_heads):"""Initializes a transformer layer, sans LayerNorm for performance, with multihead attention and linear layers.See …

prometheus client_java实现进程的CPU、内存、IO、流量的可观测

文章目录 1、获取进程信息的方法1.1、通过读取/proc目录获取进程相关信息1.2、通过Linux命令获取进程信息1.2.1、top(CPU/内存)命令1.2.2、iotop(磁盘IO)命令1.2.3、nethogs(流量)命令 2、使用prometheus c…

tableau除了图表好看,在业务中真有用吗?

tableau之前的市值接近150亿美金,被saleforce以157亿美金收购,这个市值和现在的蔚来汽车差不多。 如果tableau仅仅是个show的可视化工具,必然不会有这么高的市值,资本市场的眼睛是雪亮的。 很多人觉得tableau做图表好看&#xff…

分布式常见面试题总结

文章目录 1 什么是 UUID 算法?2 什么是雪花算法?🔥3 说说什么是幂等性?🔥4 怎么保证接口幂等性?🔥5 paxos算法6 Raft 算法7 CAP理论和 BASE 理论7.1 CAP 理论🔥7.2 为什么无法同时保…

Echarts合集更更更之树图

实现效果 写在最后🍒 源码,关注🍥苏苏的bug,🍡苏苏的github,🍪苏苏的码云

DGL库之HGTConv的使用

DGL库之HGTConv的使用 论文地址和异构图构建教程HGTConv语法格式HGTConv的使用 论文地址和异构图构建教程 论文地址:https://arxiv.org/pdf/2003.01332 异构图构建教程:异构图构建 异构图转同构图:异构图转同构图 HGTConv语法格式 dgl.nn.…

极客兔兔Gee-Cache Day7

protobuf配置: 从 Protobuf Releases 下载最先版本的发布包安装。解压后将解压路径下的 bin 目录 加入到环境变量即可。 如果能正常显示版本,则表示安装成功。 $ protoc --version libprotoc 3.11.2在Golang中使用protobuf,还需要protoc-g…