Java进阶14 TCP日志枚举

news/2025/2/6 15:27:10 标签: java, tcp/ip, 开发语言

Java进阶14 TCP&日志&枚举

一、网络编程TCP

Java对基于TCP协议得网络提供了良好的封装,使用Socket对象来代表两端的通信端口,并通过Socket产生IO流来进行网络通信。

1、TCP协议发数据
1.1 构造方法

方法

说明

Socket(InetAddress address,int port)

创建流套接字并将其连接到指定IP指定端口号

Socket(String host,int port)

创建流套接字并将其连接到指定主机上的指定端口号

1.2 相关方法

方法

说明

InputStream getInputStream()

返回此套接字的输入流

OutputStream getOutputStream()

返回此套接字的输出流

1.3 代码实现
public class Client {
 ? ?public static void main(String[] args) throws IOException {
 ? ? ? ?//创建客户端的Socket对象(Socket)
 ? ? ? ?//Socket(String host, int port) 创建流套接字并将其连接到指定主机上的指定端口号
 ? ? ? ?Socket s = new Socket("127.0.0.1",10000);
?
 ? ? ? ?//获取输出流,写数据
 ? ? ? ?//OutputStream getOutputStream() 返回此套接字的输出流
 ? ? ? ?OutputStream os = s.getOutputStream();
 ? ? ? ?os.write("hello,tcp,我来了".getBytes());
?
 ? ? ? ?//释放资源
 ? ? ? ?os.close();
 ? ? ? ?s.close();
 ?  }
}
2、TCP协议收数据

Java为客户端提供了Socket类,为服务端提供了ServeSocket类

2.1 构造方法

方法

说明

ServerSocket(int port)

创建绑定到指定端口的服务器套接字

2.2 相关方法

方法

说明

Socket accept()

监听要连接到此的套接字并接受它

2.3 代码实现
public class Server {
 ? ?public static void main(String[] args) throws IOException {
 ? ? ? ?//创建服务器端的Socket对象(ServerSocket)
 ? ? ? ?//ServerSocket(int port) 创建绑定到指定端口的服务器套接字
 ? ? ? ?ServerSocket ss = new ServerSocket(10000);
?
 ? ? ? ?//Socket accept() 侦听要连接到此套接字并接受它
 ? ? ? ?Socket s = ss.accept();
?
 ? ? ? ?//获取输入流,读数据,并把数据显示在控制台
 ? ? ? ?InputStream is = s.getInputStream();
 ? ? ? ?byte[] bys = new byte[1024];
 ? ? ? ?int len = is.read(bys);
 ? ? ? ?String data = new String(bys,0,len);
 ? ? ? ?System.out.println("数据是:" + data);
?
 ? ? ? ?//释放资源
 ? ? ? ?s.close();
 ? ? ? ?ss.close();
 ?  }
}

注意事项:

  • accept方法是阻塞的,作用就是等待客户端连接

  • 客户端创建对象并连接服务器,此时是通过三次握手协议,保证跟服务器之间的连接

  • 针对客户端来讲,是往外写的,所以是输出流 针对服务器来讲,是往里读的,所以是输入流

  • read方法也是阻塞的

  • 客户端在关流的时候,还多了一个往服务器写结束标记的动作

  • 最后一步断开连接,通过四次挥手协议保证连接终止

3、三次握手和四次挥手
3.1 三次握手

3.2 四次挥手

4、TCP文件上传案例
  • 案例需求

    客户端:数据来自于本地文件,接收服务器反馈

    服务器:接收到的数据写入本地文件,给出反馈

  • 分析思路

    • 创建客户端对象,创建输入流对象指向文件,每读一次数据就给服务器输出一次数据,输出结束后使用shutdownOutput()方法告知服务端传输结束

    • 创建服务器对象,创建输出流对象指向文件,每接受一次数据就使用输出流输出到文件中,传输结束后,使用输出流给客户端反馈信息

    • 客户端接收服务端的回馈信息

  • 相关方法

    方法

    说明

    void shutdownInput()

    将此套接字的输入流放置在“流的末尾”

    void shutdownOutput()

    禁止用此套接字的输出流

  • 服务端优化思路

    • 服务端可以多次处理

      • 循环包裹while(true)

      • 使用UUID区分了重名文件,防止二次上传文件重名造成覆盖

    • 将服务器改进为多线程版本,满足多个客户端同时通信

    • 改为线程池

  • 代码实现

public class Client {
 ? ?public static void main(String[] args) throws IOException {
 ? ? ? ?//1、创建Socket对象指定ip和端口
 ? ? ? ?Socket socket = new Socket("192.168.11.251",8888);
 ? ? ? ?//2、获取传输数据的流对象(网络流)
 ? ? ? ?InputStream is = socket.getInputStream();
 ? ? ? ?OutputStream os = socket.getOutputStream();
 ? ? ? ?//3、将字节流转换为字符串(读写的内容有中文)
 ? ? ? ?BufferedReader br = new BufferedReader(new InputStreamReader(is));
 ? ? ? ?PrintStream ps = new PrintStream(os);
 ? ? ? ?File file = new File("D:\好哥哥.jpg");
 ? ? ? ?//4、写出文件名
 ? ? ? ?ps.println(file.getName());
 ? ? ? ?//5、读取服务端消息
 ? ? ? ?String state = br.readLine();
 ? ? ? ?if("ok".equals(state)){
 ? ? ? ? ? ?//6、上传文件(字节)
 ? ? ? ? ? ?//创建本地字节输入流关联要上传的文件
 ? ? ? ? ? ?FileInputStream fis = new FileInputStream(file);
 ? ? ? ? ? ?byte[] bys = new byte[1024];
 ? ? ? ? ? ?int len;
 ? ? ? ? ? ?while((len=fis.read(bys))!=-1){
 ? ? ? ? ? ? ? ?os.write(bys,0,len);
 ? ? ? ? ?  }
 ? ? ? ? ? ?//重点:写出结束标记给服务端
 ? ? ? ? ? ?socket.shutdownOutput();
 ? ? ? ? ? ?fis.close();
 ? ? ? ? ? ?//7、读取上传结果
 ? ? ? ? ? ?String result = br.readLine();
 ? ? ? ? ? ?System.out.println(result);
 ? ? ? ? ? ?//8、关流
 ? ? ? ? ? ?socket.close();
 ? ? ?  }
 ?  }
}

public class Server {
 ? ?public static void main(String[] args) throws IOException {
 ? ? ? ?//1、创建ServerSocket对象指定端口
 ? ? ? ?ServerSocket server = new ServerSocket(8888);
 ? ? ? ?System.out.println("服务端开启,等待客户端连接");
?
 ? ? ? ?ThreadPoolExecutor pool = new ThreadPoolExecutor(
 ? ? ? ? ? ? ? ?5,
 ? ? ? ? ? ? ? ?10,
 ? ? ? ? ? ? ? ?60,
 ? ? ? ? ? ? ? ?TimeUnit.SECONDS,
 ? ? ? ? ? ? ? ?new ArrayBlockingQueue<>(20),
 ? ? ? ? ? ? ? ?Executors.defaultThreadFactory(),
 ? ? ? ? ? ? ? ?new ThreadPoolExecutor.AbortPolicy()
 ? ? ?  );
?
 ? ? ? ?while (true) {
 ? ? ? ? ? ?//2、调用accept方法响应客户端的请求
 ? ? ? ? ? ?Socket socket = server.accept();
?
 ? ? ? ? ? ?//new Thread(new SubmitFileTask(socket)).start();
 ? ? ? ? ? ?pool.submit(new FileSubmitTask(socket));
 ? ? ?  }
 ?  }
}

public class FileSubmitTask implements Runnable{
 ? ?//为了拿到另一个类的数据,将其作为参数传进本类,在本类创建带参构造并接收该参数赋值给本类的成员变量,就拿到了
 ? ?private Socket socket;
 ? ?public FileSubmitTask(Socket socket) {
 ? ? ? ?this.socket=socket;
 ?  }
?
 ? ?@Override
 ? ?public void run() {
 ? ? ? ?try {
 ? ? ? ? ? ?//3、获取传输的输入流对象(网络流)
 ? ? ? ? ? ?InputStream is = socket.getInputStream();
 ? ? ? ? ? ?OutputStream os = socket.getOutputStream();
 ? ? ? ? ? ?//4、将字节流转换为字符串(读写的内容有中文)
 ? ? ? ? ? ?BufferedReader br = new BufferedReader(new InputStreamReader(is));
 ? ? ? ? ? ?PrintStream ps = new PrintStream(os);
 ? ? ? ? ? ?//5、读取客户端发送的文件名
 ? ? ? ? ? ?String fileName = br.readLine();
 ? ? ? ? ? ?//关联服务端的存储路径
 ? ? ? ? ? ?File update = new File("D:\itheima\Resource", UUID.randomUUID()+fileName);
 ? ? ? ? ? ?//6、写给客户端消息
 ? ? ? ? ? ?ps.println("ok");
 ? ? ? ? ? ?//7、创建本地字节输出流,关联存储路径
 ? ? ? ? ? ?FileOutputStream fos = new FileOutputStream(update);
 ? ? ? ? ? ?//8、IO读写
 ? ? ? ? ? ?byte[] bys = new byte[1024];
 ? ? ? ? ? ?int len;
 ? ? ? ? ? ?while((len = is.read(bys))!=-1){
 ? ? ? ? ? ? ? ?fos.write(bys,0,len);
 ? ? ? ? ?  }
 ? ? ? ? ? ?fos.close();
 ? ? ? ? ? ?//9、写出上传成功
 ? ? ? ? ? ?ps.println("上传成功!");
 ? ? ? ? ? ?//10、关流
 ? ? ? ? ? ?socket.close();
 ? ? ?  } catch (IOException e) {
 ? ? ? ? ? ?e.printStackTrace();
 ? ? ?  }
 ?  }
}

二、日志

程序中的日志可以用来记录程序运行过程中的信息,并可以进行永久存储。日志和输出语句的比较

输出语句

日志技术

输出位置

只能是控制台

可以将日志信息写入到文件或者数据库中

取消日志

需要修改代码,灵活性比较差

不需要修改代码,灵活性比较好

多线程

性能较差

性能较好

1、日志体系结构

  • 日志规范:一些接口,提供给日志的实现框架设计的标准

  • 日志框架:牛人或者第三方公司已经做好的日志记录实现代码,后来直接可以拿去使用

  • 因为对Commons Logging 的接口不满意,有人就搞了SLF4J;因为对Log4j的性能不满意,有人就搞了Logback

2、Logback快速入门
  • 官网: Logback Home

  • 三个技术模块

    模块名

    介绍

    locback-core

    该模块为其他两个模块提供基础代码,必须有。

    logback-classic

    完整实现了slf4j API的模块。

    logback-access

    logback-access 模块与 Tomcat 和 Jetty 等 Servlet 容器集成,以提供 HTTP 访问日志功能

2.1 操纵步骤
第一步:引入jar包

jar包本质来说就是压缩包,内部存储的都是别人已经写好的代码。在需要导包的项目模块下,和src平级的位置,创建lib目录,将需要的jar包都放进去,然后勾选Add as Library。导jar包只是目前的做法,后面会学maven来管理jar包,不用手动导入

第二步:导入配置文件

将日志的配置信息文件(logback.xml)复制到模块的src

  • 日志级别和配置文件详解

    通过通过logback.xml 中的标签可以设置输出位置和日志信息的详细格式。通常可以设置2个日志输出位置:一个是控制台、一个是系统文件中

第三步:获取日志对象使用
public class LogTest {
 ? ?public static void main(String[] args) {
 ? ? ? ?//获取记录日志对象
 ? ? ? ?Logger logger = LoggerFactory.getLogger("LogTest.class");
 ? ? ? ?//记录日志
 ? ? ? ?logger.info("记录了一条日志");
 ?  }
}

三、枚举

枚举是Java中的一种特殊类型,其作用是为了做信息的标志和信息的分类。枚举可以理解为一种多例设计模式,保证类的对象,在内存中只有固定的几个

1、定义格式

修饰符 enum 枚举类型{
//第一行都是罗列枚举类实例的名称
枚举项1,枚举项2,枚举项3;
}

enum Season{
 ? ?SPRING,SUMMER,AUTUMN,WINTER;
}
2、枚举的特点
  • 所有枚举类都是 Enum 的子类

  • 我们可以通过"枚举类名.枚举项名称"去访问指定的枚举项

  • 每一个枚举项其实就是该枚举的一个对象

  • 枚举也是类, 可以定义成员变量

  • 枚举类的第一行上必须是枚举项,最后一个枚举项后的分号是可以省略的,但是如果枚举类有其他的东西,这个分号就不能省略。建议不要省略

  • 枚举类可以有构造器,但必须是 private 的,它默认的也是 private 的。枚举项的用法比较特殊:枚举(“”);

  • 枚举类也可以有抽象方法,但是枚举项必须重写该方法

3、示例代码
public enum Season {
?
 ? ?SPRING("春"){
?
 ? ? ? ?//如果枚举类中有抽象方法
 ? ? ? ?//那么在枚举项中必须要全部重写
 ? ? ? ?@Override
 ? ? ? ?public void show() {
 ? ? ? ? ? ?System.out.println(this.name);
 ? ? ?  }
?
 ?  },
?
 ? ?SUMMER("夏"){
 ? ? ? ?@Override
 ? ? ? ?public void show() {
 ? ? ? ? ? ?System.out.println(this.name);
 ? ? ?  }
 ?  },
?
 ? ?AUTUMN("秋"){
 ? ? ? ?@Override
 ? ? ? ?public void show() {
 ? ? ? ? ? ?System.out.println(this.name);
 ? ? ?  }
 ?  },
?
 ? ?WINTER("冬"){
 ? ? ? ?@Override
 ? ? ? ?public void show() {
 ? ? ? ? ? ?System.out.println(this.name);
 ? ? ?  }
 ?  };
?
 ? ?public String name;
?
 ? ?//空参构造
 ? ?//private Season(){}
 ?
 ? ?//有参构造
 ? ?private Season(String name){
 ? ? ? ?this.name = name;
 ?  }
 ?
 ? ?//抽象方法
 ? ?public abstract void show();
}
?
public class EnumDemo {
 ? ?public static void main(String[] args) {
 ? ? ? ?//我们可以通过"枚举类名.枚举项名称"去访问指定的枚举项
 ? ? ? ?System.out.println(Season.SPRING);
 ? ? ? ?System.out.println(Season.SUMMER);
 ? ? ? ?System.out.println(Season.AUTUMN);
 ? ? ? ?System.out.println(Season.WINTER);
?
 ? ? ? ?//每一个枚举项其实就是该枚举的一个对象
 ? ? ? ?Season spring = Season.SPRING;
 ?  }
}
4、做信息标志方式(2种)
4.1 常量

虽然可以实现可读性,但是入参不受约束,代码相对不够严谨

4.2 枚举

代码可读性好,入参约束严谨,代码优雅,是最好的信息分类技术!建议使用!


http://www.niftyadmin.cn/n/5843134.html

相关文章

微前端如何实现作用域隔离

微前端是一种架构风格,它将前端应用拆分为多个独立的子应用,使得各个子应用可以独立开发、部署和维护。在微前端架构中,作用域隔离是一个关键问题,确保不同子应用之间的样式、脚本和状态不会冲突。本文将讨论几种实现作用域隔离的方法。 1. CSS 作用域隔离 1.1 CSS Modul…

多用户同时RDP登入Win10

自备以下文件&#xff1a; winsw_frpc.xml展开如下&#xff1a; <service><!-- ID of the service. It should be unique across the Windows system--><id>winsw_frp</id><!-- Display name of the service --><name>winsw_frp</na…

uniapp小程序自定义中间凸起样式底部tabbar

我自己写的自定义的tabbar效果图 废话少说咱们直接上代码&#xff0c;一步一步来 第一步&#xff1a; 找到根目录下的 pages.json 文件&#xff0c;在 tabBar 中把 custom 设置为 true&#xff0c;默认值是 false。list 中设置自定义的相关信息&#xff0c; pagePath&#x…

Windows下从零开始基于Ollama与Open-WebUI本地部署deepseek R1详细指南(包含软件包和模型网盘下载)

0. 概述 最近国产大模型DeepSeek很火&#xff0c;但有时因为访问人数过多导致反应慢甚至宕机。 但好在DeepSeek是开源的&#xff0c;可以本地部署&#xff0c;这样就不用联网也能用了。但本地部署需要考虑硬件需求&#xff0c;比如是否有足够的GPU资源&#xff0c;存储空间&a…

http状态码:请说说 503 Service Unavailable(服务不可用)的原因以及排查问题的思路

503 Service Unavailable&#xff08;服务不可用&#xff09; 是一种HTTP状态码&#xff0c;表示服务器当前无法处理请求&#xff0c;通常是由于临时性原因导致服务中断。以下是它的常见原因和排查思路&#xff1a; 一、503错误的常见原因 1. 服务器过载 场景&#xff1a;服务…

6.【BUUCTF】[SUCTF 2019]CheckIn

打开题目页面如下 看样子是一道有关文件上传的题 上传一句话木马 显示&#xff1a;非法后缀&#xff01; 看来.php后缀被过滤了 上传一张带有木马的照片 在文件地址处输入cmd 输入以下代码执行 copy 1.jpg/b4.php/a 5.jpg 最后一行有一句话木马 上传带有木马的图片 但其实…

掌握Spring MVC异常处理的艺术

在Spring MVC中处理异常&#xff0c;就好比你在家里做饭时遇到了问题&#xff0c;比如切菜切到手了&#xff08;运行时异常&#xff09;&#xff0c;或者发现没盐了&#xff08;预期异常&#xff09;。那么&#xff0c;你该怎么应对这些情况呢&#xff1f;Spring MVC处理异常的…

Python aiortc API

本研究的主要目的是基于Python aiortc api实现抓取本地设备&#xff08;摄像机、麦克风&#xff09;媒体流实现Web端预览。本文章仅仅描述实现思路&#xff0c;索要源码请私信我。 demo-server解耦 原始代码解析 http服务器端 import argparse import asyncio import json…