- 禁止白嫖 T > T
- 点点赞呗
JavaEE & UDP简易翻译服务器 & 网络编程示例2 & TCP回显服务器,回显客户端
1. UDP简易翻译服务器
- 这个翻译器主要是在上一章的回显服务器和回显客户端上进行修改
- 修改了计算响应的过程,即process方法
1.1 重写方法
- 重写方法是Java中的一种重要手段
- 指在一个类的子类里,对父类的一个方法进行重新定义!
- 而父类的权限级别要大于等于子类~ 【除了private】
- 向上转型,父类对象调用的是子类重写的方法
- 动态绑定,子类对象调用父类的方法,但是该方法里嵌套调用了重写方法
- 可以理解为super帮助构造父类时,实现动态绑定重写方法~
- 而他的"super"跟子类实例化父类对象别无二致
- 也可以看成向上转型 + 动态绑定
- 而构造子类必然要以子类构造父类,这个过程才是重写方法的本质
子类继承父类,并为帮助父类构造:
Ctrl + O 重写process方法:
- 注意:父类的process权限要足够高才行~
- 注解的作用就是警示你写对代码!
- 不至于写了半天出错了,找不到代码错误的地方~
1.2 设计翻译服务器
- 对于这个简单的翻译器,我只需要将一个个单词和一个个含义对应好,并且保存起来,每次查询的时候就在里面找对应关系~
- 而这也是一些翻译器的基本原理,一个单词字符串对象 + 映射对象占内存也不过1KB,100w个单词 也约等于 10亿字节,也就是1GB
快速记忆小技巧:
- Thousand ==> 1KB
- Million ==> 1MB
- Billion ==> 1GB
而符合这种需求的数据结构就是:哈希表
- 快速查询
- 映射关系 — Map
- 找不到的时候get返回null~
1.3 书写main方法启动服务器测试
public static void main(String[] args) throws IOException {
UDPDictServer udpDictServer = new UDPDictServer(9090);
udpDictServer.start();
}
- 测试正常,如果你要做大这个翻译器,可以多点单词~
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 写一个简单的客户端服务器程序
同样的,分为服务器与客户端:
- 同样也可以做成翻译器~
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文件内有两块缓冲区
- 接受缓冲区
- 发送缓冲区
- 即,只需要知道一方,就可以完成读写~
- 而那一方应该是“对方”
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();
}
}
讲解:
- 抛异常操作自己去抛
- 客户端上线打印日志
- 打开输入输出流
-
字节流转换器
- 通过这两个对象,实现传输过程
- 如何理解输入与输出流?
- 建立长连接
-
获得请求并计算
-
回显计算:
-
public String process(String request) { return request; }
-
这里的flush特别重要,当你flush后,才能算真正输出了~
- 即,对方就能接受你的输出,并且用你的输入流去获得~
- scanner在等待输入呢,flush就相当于踢了它一脚~
-
打印日志~
-
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();
}
}
讲解:
-
获得服务器的输入输出流
- 同样的方式~
- 同样的方式~
-
字节流转换器
-
多次请求响应
- “写”的时候,记得带上“回车空白符”,分割每个响应
- 并打印日志
- “写”的时候,记得带上“回车空白符”,分割每个响应
可能会更加难理解,但是也简化了UDP反复制作“数据报”的过程,并且是有连接的~
2.2.2.3 补充说明
长连接是指一个服务器一段时间内反复服务一个客户端
- 客户端socket这段时间内一直处于打开状态,并不断发送请求得到响应~
并不是一次性发送多条请求,得到多条响应~
- 错误代码:
- 这段代码确实可以完成一次上面的流程
- 但是有不可修复的bug!
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();
}
运行测试(“死锁”版):
运行测试(正常版):
- 对于一次性输入多条请求,获得多个响应也只能这样~
总结图示:
- 下一次控制台输入,又是一次轮回~
2.2.4 修复缺陷
- 运行两个客户端:
你可能已经发现了,这个代码还存在一个缺陷
- 就是这个服务器,在一段时间内,“抢到服务器”的客户端不关闭,服务器就无法服务其他客户端。
- 那怎么办!
其实,很简单
- 线程池 / 循环建立多线程
- 只要让服务器并发的去执行任务就ok了!
但是,客户端达到一定数量会导致系统崩了或者客户端未能“同时”受到服务
- 即,肉眼可见的不并发
代码改进:
- 运行结果:
线程池法:
文章到此结束!谢谢观看
可以叫我 小马,我可能写的不好或者有错误,但是一起加油鸭🦆!文章来源:https://www.toymoban.com/news/detail-415719.html后续网络编程的博客会陆续更新,敬请期待!文章来源地址https://www.toymoban.com/news/detail-415719.html
到了这里,关于JavaEE & UDP简易翻译服务器 & 网络编程示例2 & TCP回显服务器,回显客户端的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!