【JavaEE】UDP简易翻译服务器-网络编程示例2-TCP回显服务器,回显客户端

简介: JavaEE & UDP简易翻译服务器 & 网络编程示例2 & TCP回显服务器,回显客户端

JavaEE & UDP简易翻译服务器 & 网络编程示例2 & TCP回显服务器,回显客户端

1. UDP简易翻译服务器

这个翻译器主要是在上一章的回显服务器和回显客户端上进行修改

修改了计算响应的过程,即process方法

d20a2da3352a482cb926adc85f5506a5.png


1.1 重写方法

重写方法是Java中的一种重要手段

指在一个类的子类里,对父类的一个方法进行重新定义!

而父类的权限级别要大于等于子类~ 【除了private】

向上转型,父类对象调用的是子类重写的方法

动态绑定,子类对象调用父类的方法,但是该方法里嵌套调用了重写方法

可以理解为super帮助构造父类时,实现动态绑定重写方法~

而他的"super"跟子类实例化父类对象别无二致

也可以看成向上转型 + 动态绑定

而构造子类必然要以子类构造父类,这个过程才是重写方法的本质

子类继承父类,并为帮助父类构造:

443a5b27a53a4693b693c36681f401c4.png


Ctrl + O 重写process方法:


注意:父类的process权限要足够高才行~

3f9b67a9baee4abc8bca938be40d979f.png


注解的作用就是警示你写对代码!

不至于写了半天出错了,找不到代码错误的地方~

1.2 设计翻译服务器

对于这个简单的翻译器,我只需要将一个个单词和一个个含义对应好,并且保存起来,每次查询的时候就在里面找对应关系~

而这也是一些翻译器的基本原理,一个单词字符串对象 + 映射对象占内存也不过1KB,100w个单词 也约等于 10亿字节,也就是1GB

快速记忆小技巧:


Thousand ==> 1KB

Million ==> 1MB

Billion ==> 1GB

而符合这种需求的数据结构就是:哈希表


快速查询

映射关系 — Map

2fd8d05c95874c0fad1fa864c51064e7.png


找不到的时候get返回null~

033a01198fb94ee9a8b0392cf9b7fc95.png


1.3 书写main方法启动服务器测试

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

d0ecd2f113a34035aa354dcd1f891173.png



测试正常,如果你要做大这个翻译器,可以多点单词~

2. TCP网络编程示例

这个示例跟UDP的作用是一模一样的~

只不过这次用到的协议是TCP

如果没有学UDP建议先学UDP!


传送门:JavaEE & 网络编程示例1 & UDP套接字数据报编程 == 一发一收


2.1 ServerSocket 与 Socket

ServerSocket : 服务器使用的socket对象

Socket : 既会给客户端使用,也会给服务器使用的socket对象

2.1.1 ServerSocket的构造方法

方法名 方法说明

ServerSocket(int port) 服务器socket对象构造方法【指定端口号】

服务器一定要绑定具体的端口号~

2.1.2 ServerSocket的核心方法

方法名 方法说明

Socket accept() 建立连接

void close() 关闭socket【文件】对象

socket对象如果周期很长,一般是不需要关闭的,因为关闭时一般意味着程序终结,资源自动回收


accept方法是跟客户端建立连接的方法,后面写代码时重点说明


TCP有连接的特点就在这~

连接一旦建立,发送与接受都是能确定是否成功的~

返回的Socket对象,即可以代表服务器与客户端的连接,也可以代表客户端与服务器的连接~


2.1.3 Socket的构造方法

方法名 方法说明

Socket(String host, int port) 指定IP与端口号

2.1.4 Socket的核心方法

方法名 方法说明

InetAddress getInetAddress() 返回Socket对象的IP地址

InputStreamgetInputStream() 返回控制这个socket文件的输入流

OutputStreamgetOutputStream() 返回控制这个socket文件的输出流

输入输出流特别重要

作用于他们就相当于作用于网卡

有了他们,我们就可以进行数据的沟通了!

而他们对应的是字节流 ==> TCP面向字节流


2.1.5 长连接与短连接

服务器收到一个请求,就返回一个响应,然后断开连接

这就是短连接


服务器收到一个客户端的多条请求,再一起返回响应,然后断开连接

这就是长连接


而长短连接都是可能出现的!

对于接下来的代码,考虑到多条请求,我做出如下规定:


多条请求之间以空白符分割~

每一个请求都是字符串

对于后面的代码设计,是按长连接来设计的!


2.2 基于TCP 的 Socket 写一个简单的客户端服务器程序

同样的,分为服务器与客户端:


dd94f01d8a6246f3a816cbb35f5ffd75.png


同样也可以做成翻译器~

2.2.1 TCP回显服务器

可能在前面会很懵,但是后面的图解会串联起来,可能会让你理解起来更加容易!

2.2.1.1 ServerScoket对象与构造方法

这个对象是专门给服务器用的,通过这个对象来获得客户端【发来请求的机器】的【socket管理员】

即连接

而这个socket并不是用于操纵socket文件~

public class TCPEchoServer {
    private ServerSocket serverSocket = null;
    public TCPEchoServer(int port) throws IOException {
        this.serverSocket = new ServerSocket(port);
    }
}


2.2.1.2 start启动方法

Socket对象被动构造

accept的话,则是接受客户端的输出

public void start() throws IOException {
    System.out.println("服务器启动!");
    while(true) {
        Socket clientSocket = serverSocket.accept();//建立连接
        processConnect(clientSocket); // 连接成功后进行一些操作~
   }
}


你可能有一个疑惑:


发送信息要用到客户端socket对象这没问题

但是,接受到的信息为什么也用到客户端的socket对象?

服务器收到的信息可能来自很多地方,并且都是字节流,不像数据报一块一块的

服务器的输出流数据来源来自客户端的输入流

输入:我输入给别人

输出:别人输出给我

如以下关系:


socket文件内有两块缓冲区

接受缓冲区

发送缓冲区

59572272c3e1417399f862581f85f337.png


即,只需要知道一方,就可以完成读写~

而那一方应该是“对方”

2.2.1.3 processConnect细节

public void processConnect(Socket clientSocket) throws IOException {
    System.out.printf("[%s:%d] 客户端上线\n", clientSocket.getInetAddress().toString(),
            clientSocket.getPort());
    try(InputStream inputStream = clientSocket.getInputStream();
        OutputStream outputStream = clientSocket.getOutputStream()) {
        Scanner scanner = new Scanner(inputStream);
        //这个对象将自动读取【字节流/其他流】为【字符流】
        PrintWriter printWriter = new PrintWriter(outputStream);
        //这个对象将自动写入【字符流】化为【字节流/其他流】
        while(scanner.hasNext()) {//死循环了,除非客户端关闭~
            String request = scanner.next();//nextLine有坑很烦
            String response = process(request);
            printWriter.println(response);//换行记得加~
            printWriter.flush();
            System.out.printf("[%s : %d] 发来请求:%s, 将对其返回响应:%s\n", clientSocket.getInetAddress().toString(),
                    clientSocket.getPort(), request, response);
        }
        System.out.printf("[%s:%d] 客户端下线\n", clientSocket.getInetAddress().toString(),
                clientSocket.getPort());
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        clientSocket.close();
    }
}


讲解:


抛异常操作自己去抛

客户端上线打印日志



打开输入输出流

cc55e1be39b14feaa9507b65ffb683ca.png


字节流转换器

通过这两个对象,实现传输过程

0fbb79cd8a8341b6a98bd1936f05451e.png


如何理解输入与输出流?

cb7c9ccaf79343bbaa29d5ef6a6cdf6a.png


建立长连接


e623cfedef75452bab2734a54663b3a8.png

获得请求并计算


回显计算:


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

这里的flush特别重要,当你flush后,才能算真正输出了~


即,对方就能接受你的输出,并且用你的输入流去获得~

scanner在等待输入呢,flush就相当于踢了它一脚~

打印日志~


4c4d9d2ae15c4d03b570205d4127ebe3.png


2.2.2 TCP回显客户端

2.2.2.1 指定服务器Socket对象与构造方法

会用这个对象就行了,至于这么通过端口获得对应的输入输出流的不得而知~

public class TCPEchoClient {
    Socket socket = null;//此socket对象代表了服务器的socket文件~
    public TCPEchoClient(String host, int port) throws IOException {
        this.socket = new Socket(host, port);
        //这个过程客户端主动连接了服务器,这样就可以被服务器的accept接受~
        //而服务器的accept返回的对象,默认填上了客户端的IP与端口号
    }
}




2.2.2.2 start启动方法

public void start() {
    Scanner scanner = new Scanner(System.in);
    try (InputStream inputStream = socket.getInputStream();
         OutputStream outputStream = socket.getOutputStream()){
        PrintWriter printWriter = new PrintWriter(outputStream);
        Scanner scannerFromServer = new Scanner(inputStream);
        while(true) {
            System.out.print("-> ");
            String request = scanner.nextLine();
            printWriter.println(request);
            printWriter.flush();
            String response = scannerFromServer.next();//如果为空,则需要等待对方flush
            System.out.printf("[%s : %d] 收到请求:%s, 返回响应:%s\n", socket.getInetAddress().toString(),
                    socket.getPort(), request, response);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}



讲解:


获得服务器的输入输出流


同样的方式~

d17c1dd4f6b240cf8fb2aa3b0716de12.png

字节流转换器



多次请求响应


“写”的时候,记得带上“回车空白符”,分割每个响应

并打印日志

2933b21de71e43c7b13b19b92c36584e.png


可能会更加难理解,但是也简化了UDP反复制作“数据报”的过程,并且是有连接的~


2.2.2.3 补充说明

长连接是指一个服务器一段时间内反复服务一个客户端


客户端socket这段时间内一直处于打开状态,并不断发送请求得到响应~

并不是一次性发送多条请求,得到多条响应~


错误代码:

这段代码确实可以完成一次上面的流程

但是有不可修复的bug!


1f165b849627453e8cf2073c22ef2b9d.png

2.2.3 测试与总结

服务器进程:

端口号随便写的(空余的)

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


客户端进程:

IP自己去查~

public static void main(String[] args) throws IOException {
    TCPEchoClient tcpEchoClient = new TCPEchoClient("10.61.10.239", 9090);
    tcpEchoClient.start();
}


运行测试(“死锁”版):

ec0b639ee4284620adf5e903e1676009.gif



运行测试(正常版):


对于一次性输入多条请求,获得多个响应也只能这样~


01db98a66dec42daaaf6654a44524d39.gif

总结图示:


b9a276f4fe1f4ca795c6dc958816b765.png一次控制台输入,又是一次轮回~



2.2.4 修复缺陷

6ca1eb739df4477c98dfd133581bdb7e.png


运行两个客户端:

33d444c6c12741fbb8b02cdd5916c659.gif


你可能已经发现了,这个代码还存在一个缺陷


就是这个服务器,在一段时间内,“抢到服务器”的客户端不关闭,服务器就无法服务其他客户端。

那怎么办!

其实,很简单


线程池 / 循环建立多线程

只要让服务器并发的去执行任务就ok了!

但是,客户端达到一定数量会导致系统崩了或者客户端未能“同时”受到服务


即,肉眼可见的不并发

代码改进:


de683c258ec44e438eca7629a963e90e.png


运行结果:

43a4b7d510da462f8eef483373ebc238.gif


线程池法:


8ddec022f7b842cab1e59a83cc31cfed.png

目录
相关文章
|
7天前
|
存储 消息中间件 弹性计算
阿里云服务器ECS计算型c7和通用算力型u1在适用场景、计算性能、网络与存储性能等方面的对比
阿里云ECS服务器u1和c7实例在适用场景、性能、处理器特性等方面存在显著差异。u1为通用算力型,性价比高,适合中小企业及对性能要求不高的场景;c7为企业级计算型,采用最新Intel处理器,性能稳定且强大,适用于高性能计算需求。u1支持多种CPU内存配比,但性能一致性可能受底层平台影响;c7固定调度模式,确保高性能与稳定性。选择时可根据预算与性能需求决定。
55 23
|
13天前
|
SQL 数据采集 人工智能
“服务器老被黑?那是你没上AI哨兵!”——聊聊基于AI的网络攻击检测那些事儿
“服务器老被黑?那是你没上AI哨兵!”——聊聊基于AI的网络攻击检测那些事儿
68 12
|
1月前
|
安全 网络安全 定位技术
网络通讯技术:HTTP POST协议用于发送本地压缩数据到服务器的方案。
总的来说,无论你是一名网络开发者,还是普通的IT工作人员,理解并掌握POST方法的运用是非常有价值的。它就像一艘快速,稳定,安全的大船,始终为我们在网络海洋中的冒险提供了可靠的支持。
78 22
|
2月前
|
Ubuntu Linux
Linux系统管理:服务器时间与网络时间同步技巧。
以上就是在Linux服务器上设置时间同步的方式。然而,要正确运用这些知识,需要理解其背后的工作原理:服务器根据网络中的其他机器的时间进行校对,逐步地精确自己的系统时间,就像一只犹豫不决的啮齿动物,通过观察其他啮齿动物的行为,逐渐确定自己的行为逻辑,既简单,又有趣。最后希望这个过程既能给你带来乐趣,也能提高你作为系统管理员的专业素养。
132 20
|
21天前
|
存储 缓存 弹性计算
阿里云经济型e实例云服务器评测:企业官网搭建的性价比之选
阿里云服务器经济型e实例可以用来搭建企业网站吗?云服务器作为搭建企业官网的基础设施,其性能、稳定性、成本等因素直接影响着官网的运营效果。阿里云经济型e实例云服务器作为一款性价比较高的产品,备受用户关注。许多企业在选择云服务器搭建官网时,都会将其纳入考虑范围。本文将详细探讨阿里云经济型e实例云服务器的特点、性能表现、稳定性与可靠性,以及成本考量,最终解答是否适合用它来搭建企业官网。
|
2月前
|
存储 缓存 网络协议
阿里云特惠云服务器99元与199元配置与性能和适用场景解析:高性价比之选
2025年,阿里云长效特惠活动继续推出两款极具吸引力的特惠云服务器套餐:99元1年的经济型e实例2核2G云服务器和199元1年的通用算力型u1实例2核4G云服务器。这两款云服务器不仅价格亲民,而且性能稳定可靠,为入门级用户和普通企业级用户提供了理想的选择。本文将对这两款云服务器进行深度剖析,包括配置介绍、实例规格、使用场景、性能表现以及购买策略等方面,帮助用户更好地了解这两款云服务器,以供参考和选择。
|
2月前
|
域名解析 人工智能 弹性计算
DeepSeek服务器繁忙解决方法:使用阿里云一键部署DeepSeek个人网站!
通过阿里云一键部署DeepSeek个人网站,解决服务器繁忙问题。学生用户可领取300元代金券实现0成本部署,普通用户则可用99元/年的服务器。教程涵盖从选择套餐、设置密码到获取百炼API-KEY的全流程,助您快速搭建专属大模型主页,体验DeepSeek、Qwen-max、Llama等多款模型,无需代码,最快5分钟完成部署。支持绑定个人域名,共享亲友使用,日均成本仅约1元。
178 10
|
22天前
|
弹性计算 关系型数据库 Apache
阿里云实验基于ECS搭建云上博客
实验网址https://developer.aliyun.com/adc/scenario/fdecd528be6145dcbe747f0206e361f3?spm=a2c6h.13858375.devcloud-scene-list.4.d1a04090jMEG9j
88 26
|
27天前
|
安全 Linux
阿里云linux服务器使用脚本通过安全组屏蔽异常海外访问ip
公网网站可能会遭受黑客攻击导致访问异常,使用此脚本可以屏蔽掉异常IP 恢复访问。也可自行设置定时任务定期检测屏蔽。
143 28
|
19天前
|
存储 机器学习/深度学习 算法
阿里云X86/ARM/GPU/裸金属/超算等五大服务器架构技术特点、场景适配与选型策略
在我们选购阿里云服务器的时候,云服务器架构有X86计算、ARM计算、GPU/FPGA/ASIC、弹性裸金属服务器、高性能计算可选,有的用户并不清楚他们之间有何区别。本文将深入解析这些架构的特点、优势及适用场景,帮助用户更好地根据实际需求做出选择。