如何在MacOS上安装Doom Emacs

1. Emacs安装

1.1 通过Homebrew安装

首先我们利用Mac的包管理工具hombrew,安装的是Emacs-plus,传送门在此。 因为当前Doom Emacs不支持29.+, 所以只安装28版本的Emacs(Emacs 27.1+ (28.1 is recommended, or native-comp. 29+ is not supported).

所以,我们用命令安装

1
2
brew tap d12frosted/emacs-plus
brew install emacs-plus@28 --HEAD --with-modern-doom3-icon # 我们想换一个好看的头像,嘻嘻

如下图,doom3的icon,好看!
[Screen Shot 2023-04-11 at 17.18.14](http://blogv1.seanzou.com/upload/2023/04/Screen Shot 2023-04-11 at 17.18.14-d3897770cd794c9ca49df2fbdc9b4f38.png)

1.2 给Emacs创建快捷方式

利用homebrew安装完后Emacs,我们去将Emacs的app连接。我们首先去安装了emacs的根目录。可以从Summary里面找到,e.g., /opt/hombrew/Cellar/emacs-plus@27/HEAD-abedf3a。然后使用命令cp进行快捷方式的链接。

1
2
cd /opt/hombrew/Cellar/emacs-plus@27/HEAD-abedf3a
cp -r Emacs.app /Applications

这个时候我们就会发现我们有一个可爱的图标的Emacs了。

2. Doom Emacs配置覆盖

2.1 安装依赖

1
2
brew install git ripgrep coreutils fd
xcode-select --install

2.2 覆盖Emacs的配置

这个时候Emacs的配置很重要,DoomEmacs Github给的地方是~/.config/emacs,但是我的配置完全不是这个,所以导致我最开始即使安装成功了Doom 和 Emacs,但是打开的仍旧是原版的Emacs,所以对于我来说(MacOS)用户来说命令应该如下,正确位置上~/.emacs.d,而不是~/.config/emacs

1
2
3
4
5
git clone https://github.com/doomemacs/doomemacs ~/.emacs.d
cd ~/.emacs.d
bin/doom install # 安装过程中有y 点y
bin/doom doctor # 检查一下有没有问题
bin/doom sync # 同步一下,我没有运行这行命令甚至无法打开Emacs

至此我们的Doom Emacs已经安装完成了,接下来为了方便起见,可以将Doom加入环境变量。

[关于Emcas配置] 来自Dason大佬的建议:删掉.emacs.d,就会自动读取.config里面的配置。

2.3 将Doom命令加入

使用vim ~/.bashrc或者vim ~/.bash_profile,然后加入我们通过命令pwd找到我们当前Doom的目录,加入进去就可以啦。嘿嘿。

总结

完成了,昨天在火车上思考了一路,最后得出结论,既然Doom和Emacs都安装成功了,但是打开还是原版的Emacs,很明显就是Doom的配置文件没有覆盖成功,于是今天重新试了一遍,找了一个MacOS版本的Youtube视频,结果成功啦。参考视频链接在此。

l

解决 Parallels Desktop 17 无法连接网络问题

前言

不少小伙伴在 macOS Big Sur 或 Monterey 中安装 Parallels Desktop 16/17 之后,都遇到了初始化网络失败,无法连接网络的问题。

正文

我们只要修改两个文件的配置即可:

  • /Library/Preferences/Parallels/dispatcher.desktop.xml
  • /Library/Preferences/Parallels/network.desktop.xml

可以通过 Finder 的前往文件夹功能直达:

  1. 打开 dispatcher.desktop.xml 文件,找到 <Usb>0</Usb>,修改为 <Usb>1</Usb> 并保存。

另外,有些小白朋友可能按截图中的行号来找,这是不对的。可通过 ⌘ + F 键,然后输入关键词,来快速定位。

![3.webp.jpg](https://cdn.jsdelivr.net/gh/swimminghao/picture@main/img/2024/09/13/CleanShot 2024-09-13 at 10.23.36@2x.png)

  1. 打开 network.desktop.xml 文件,找到 <UseKextless>1</UseKextless><UseKextless>-1</UseKextless>,修改为 <UseKextless>0</UseKextless> 并保存。

![2.webp.jpg](https://cdn.jsdelivr.net/gh/swimminghao/picture@main/img/2024/09/13/CleanShot 2024-09-13 at 10.24.17@2x.png)

如果找不到 <UseKextless>1</UseKextless><UseKextless>-1</UseKextless>,那么需要新增一行。

1
2
3
4
<ParallelsNetworkConfig schemaVersion="1.0" dyn_lists="VirtualNetworks 1">
<!-- 在第一行新增即可 -->
<UseKextless>0</UseKextless>
</ParallelsNetworkConfig>
  1. 完全退出 Parallels Desktop,重新打开,就能正常连接网络了。
l

holer-server项目解读

[1/40]程序文件概述: holer-server/src/main/java/org/holer/server/HolerApp.java

该文件是holer-server项目的主要入口文件。主要作用是启动Holer服务器,并且设置服务器的启动参数和端口。文件中的关键部分包括:

  • 使用了@SpringBootApplication注解来指定该类是Spring Boot应用的入口。
  • 使用了@EnableScheduling注解来启用定时任务的支持。
  • main方法是应用程序的入口点,通过SpringApplication.run(HolerApp.class, args)来启动Spring Boot应用程序。
  • 通过ServerUtil.property(ServerConst.SERVER_PORT)获取服务器端口。
  • 通过ServerContainer.getContainer().start()启动ServerContainer实例。
  • 最后通过日志记录服务器启动的端口信息。

该文件主要负责启动Holer服务器并初始化相关配置,然后启动ServerContainer来处理请求。

[2/40]程序文件概述: holer-server/src/main/java/org/holer/server/handler/ExceptHandler.java

该程序文件是一个Java类文件,位于holer-server/src/main/java/org/holer/server/handler/ExceptHandler.java。该文件定义了一个异常处理器类ExceptHandler,用于处理不同类型的异常。

该类使用@RestControllerAdvice注解标记为一个全局异常处理类,可以处理控制器中抛出的异常。

在该类中,定义了三个异常处理方法:

  1. handle(Exception e)方法用于处理通用的Exception异常,打印异常信息并返回一个HolerResult对象,该对象包含一个错误代码和错误信息。
  2. handle(MethodArgumentNotValidException e)方法用于处理参数校验异常,获取校验失败的字段错误信息并拼接为一个错误信息字符串,然后返回一个HolerResult对象,该对象包含一个错误代码和错误信息。
  3. handle(HolerException e)方法用于处理自定义的HolerException异常,直接返回一个HolerResult对象,该对象包含自定义异常中的错误代码。

通过这些异常处理方法,程序可以在发生异常时进行捕获、处理和返回错误信息,提高系统的可靠性和可维护性。

[3/40]程序文件概述: holer-server/src/main/java/org/holer/server/handler/ExtraClientHandler.java

该文件是holer项目中的一个Java源代码文件,路径为holer-server/src/main/java/org/holer/server/handler/ExtraClientHandler.java。它是一个Netty的事件处理器类,继承自SimpleChannelInboundHandler。它包含了处理客户端连接和数据传输的方法,包括exceptionCaught、channelRead0、channelActive、channelInactive和channelWritabilityChanged等方法。这些方法分别用于处理出现异常、接收数据、客户端连接建立、客户端连接断开和可写性变化等事件。

[4/40]程序文件概述: holer-server/src/main/java/org/holer/server/handler/DataHandler.java

这个程序文件是DataHandler.java,它位于holer-server/src/main/java/org/holer/server/handler路径下。

该文件是一个Java类,它是一个Netty的ChannelDuplexHandler的子类。它实现了channelReadwritechannelActivechannelInactive方法。

channelRead方法在读取数据后会更新DataCollector对象中的统计信息,并将消息传递给下一个处理器。
write方法在写入数据后会更新DataCollector对象中的统计信息,并继续执行后续的写操作。
channelActive方法在连接激活时会增加DataCollector对象中的连接数。
channelInactive方法在连接失效时会减少DataCollector对象中的连接数。

该类的主要功能是通过DataCollector收集和统计连接的读写数据量,并跟踪连接数。

[5/40]程序文件概述: holer-server/src/main/java/org/holer/server/handler/ServerHandler.java

该文件是holer-server项目中的一个处理程序类,用于处理服务器收到的消息。主要包括以下几个方法:

  1. exceptionCaught方法:捕获holer客户端的异常,并打印日志。
  2. channelRead0方法:处理接收到的消息,根据消息类型不同采取不同的处理方式。
  3. channelWritabilityChanged方法:当可写状态发生变化时,将该状态同步到关联的通道。
  4. channelInactive方法:当通道不再活动时,进行一些清理工作,如移除通道的引用及关闭相关通道。
  5. handleHeartbeatMsg方法:处理心跳消息,通知客户端已接收到该消息。
  6. handleAuthMsg方法:处理客户端认证消息,进行认证操作。
  7. handleConnectMsg方法:处理连接消息,建立与目标服务器的连接。
  8. handleDisconnectMsg方法:处理断开连接消息,关闭与目标服务器的连接。
  9. handleTransferMsg方法:处理数据传输消息,将数据传输到目标服务器。

该类主要功能是根据接收到的消息类型执行相应的操作,如认证、连接、断开连接和数据传输等。

[6/40]程序文件概述: holer-server/src/main/java/org/holer/server/init/ServerInitializer.java

该文件是一个Java类文件,位于holer-server/src/main/java/org/holer/server/init/目录下。它是一个netty的服务器初始化类,继承了ChannelInitializer类。在initChannel方法中,根据参数sslEnabled的值来判断是否开启SSL加密,并根据需要配置SSL引擎,然后添加一系列的管道处理器,包括消息解码器、消息编码器、空闲检测器和服务器处理器。

[7/40]程序文件概述: holer-server/src/main/java/org/holer/server/init/ExtraClientInitializer.java

这是一个名为ExtraClientInitializer.java的文件,位于holer-server/src/main/java/org/holer/server/init/目录下。这个文件是一个Netty的ChannelInitializer子类,用来初始化SocketChannel的管道。

在initChannel方法中,会依次向管道添加一个DataHandler和一个ExtraClientHandler,用于处理数据和额外的客户端请求。

[8/40]程序文件概述: holer-server/src/main/java/org/holer/server/h2/H2Function.java

这是一个名为H2Function.java的Java程序文件,位于holer-server/src/main/java/org/holer/server/h2目录下。它是一个H2数据库函数类,包含了一个名为unixTimeStamp的静态方法,参数为一个Timestamp对象,返回一个整数类型结果。该方法将给定的Timestamp对象转换为Unix时间戳。

[9/40]程序文件概述: holer-server/src/main/java/org/holer/server/util/DataCollector.java

这是一个名为DataCollector的Java类,它位于org.holer.server.util包中。该类用于收集和管理数据,并提供方法来访问和操作收集到的数据。

该类包含以下成员变量:

  • collectors:一个ConcurrentHashMap,用于存储不同端口的DataCollector实例。
  • port:表示当前DataCollector实例所监听的端口。
  • readBytes:一个AtomicLong类型的对象,用于记录读取的字节数。
  • wroteBytes:一个AtomicLong类型的对象,用于记录写入的字节数。
  • readMsgs:一个AtomicLong类型的对象,用于记录读取的消息数量。
  • wroteMsgs:一个AtomicLong类型的对象,用于记录写入的消息数量。
  • channels:一个AtomicInteger类型的对象,用于记录当前连接的通道数量。

该类包含以下方法:

  • getCollector(Integer port):根据端口获取对应的DataCollector实例。
  • getInitAllData():获取所有DataCollector实例的初始数据。
  • getAllData():获取所有DataCollector实例的当前数据。
  • getInitData():获取当前DataCollector实例的初始数据。
  • getData():获取当前DataCollector实例的当前数据。
  • incrementReadBytes(long bytes):增加读取的字节数。
  • incrementWroteBytes(long bytes):增加写入的字节数。
  • incrementReadMsgs(long msgs):增加读取消息的数量。
  • incrementWroteMsgs(long msgs):增加写入消息的数量。
  • getChannels():获取当前连接的通道数量。
  • getPort():获取当前DataCollector实例监听的端口。
  • setPort(Integer port):设置当前DataCollector实例监听的端口。

总体而言,该类用于收集和统计与端口相关的数据,并提供了访问和操作这些数据的方法。

[10/40]程序文件概述: holer-server/src/main/java/org/holer/server/util/ServerUtil.java

这个程序文件是一个名为ServerUtil的工具类。它包含了一些静态方法和实例方法,用来提供服务器相关的实用功能。这个类使用了一些第三方库,如Jackson、Gson和OkHttp,还依赖了一些其他的类和接口。它还被声明为一个Spring的组件(Component),可以被自动装配到其他类中使用。整个文件包括了一些公共方法,如初始化方法、获取服务方法、验证方法、写方法等。这些方法用来处理各种服务器相关的功能,如用户验证、生成随机ID、验证许可证、获取总端口数量等。

[11/40]程序文件概述: holer-server/src/main/java/org/holer/server/util/ServerMgr.java

该文件是一个名为ServerMgr的Java类,主要包含了一些静态变量和静态方法。其中静态变量包括bindChannels、holerChannels、trialClients、extraClientId等Map类型的变量,以及webServerPort、serverDomain、serverHost、serverPort、proxyContent等一些基本类型的变量。静态方法包括isSslServerEnable、getSslServerHost、getSslServerPort等获取静态变量值的方法,以及initCfg、initHoler、saveClient、savePort等一些用于初始化配置和保存数据的方法。此外,还有一些其他的辅助方法,如bind、unbind、deleteProxy等。整体来说,该类是一个服务器管理工具类,用于管理服务器的状态、配置和通讯等。

[12/40]程序文件概述: holer-server/src/main/java/org/holer/server/config/SchedulerConfig.java

这是一个名为SchedulerConfig的Java类文件,位于holer-server/src/main/java/org/holer/server/config/路径下。该类使用了Spring框架的注解@Configuration,用于标识为配置类。实现了SchedulingConfigurer接口,用于自定义任务调度器的配置。

configureTasks方法中,创建了一个ThreadPoolTaskScheduler对象,并进行了一些配置,如设置线程池大小为5,线程名前缀为”Holer-Task-“。然后调用initialize方法进行初始化。最后通过registrar.setTaskScheduler(taskScheduler)方法将配置好的任务调度器设置到ScheduledTaskRegistrar对象中。

该配置类的主要作用是创建和配置一个自定义的任务调度器,并将其应用于任务注册器中,以便在Spring应用程序中实现定时任务调度。

[13/40]程序文件概述: holer-server/src/main/java/org/holer/server/config/HolerWebConfig.java

这是一个名为HolerWebConfig.java的配置文件,位于org.holer.server.config包中。它实现了WebMvcConfigurer接口,并覆盖了addInterceptors方法。该方法通过向注册表添加拦截器来配置拦截器。文件中还有两个注入的拦截器实例:apiInterceptor和viewInterceptor。addInterceptors方法使用这两个拦截器,并为它们指定了拦截路径。apiInterceptor拦截/api/**路径,viewInterceptor拦截/view/**路径。

[14/40]程序文件概述: holer-server/src/main/java/org/holer/server/config/CorsConfig.java

这个文件是”Holer Server”项目中的一个配置文件,它用于配置跨域资源共享(CORS)功能。该文件定义了一个 CorsConfig 类,被注解为@Configuration,表示这是一个Spring应用程序的配置类。在这个类中,有一个@Bean方法,它创建了一个CorsFilter对象,并返回它。CorsFilter是Spring框架中的一个过滤器,用于处理跨域请求。在这个方法中,我们创建了一个CorsConfiguration对象,并设置了一些允许访问的来源、头部和方法。然后,创建了一个UrlBasedCorsConfigurationSource对象,将CorsConfiguration配置应用到所有的URL路径上。最后,将UrlBasedCorsConfigurationSource对象传递给CorsFilter构造函数,创建CorsFilter对象并返回。这样,当请求到达服务器时,CorsFilter将会根据CorsConfiguration的设置来处理跨域请求。

[15/40]程序文件概述: holer-server/src/main/java/org/holer/server/timer/HolerWorker.java

该程序文件名为HolerWorker.java,位于org.holer.server.timer包下。这个文件是一个定时任务类,包含了三个定时任务方法cleanExpiredData()、closeHoler()和setDomain()。cleanExpiredData()方法用于清除过期的数据;closeHoler()方法用于关闭Holer;setDomain()方法用于设置域名。这个类使用了Spring的Scheduled注解来指定定时执行的时间间隔。文件中还引入了一些其他的类和工具类,并且使用了日志输出。

[16/40]程序文件概述: holer-server/src/main/java/org/holer/server/container/ServerContainer.java

该程序文件是Holer服务器的主要容器类,用于启动和停止服务器。以下是该文件的关键要点:

  1. 该类位于org.holer.server.container包中。
  2. 使用了Netty库来构建服务器。
  3. 该类是单例模式实现的,通过getContainer()方法获取唯一实例。
  4. 拥有两个NioEventLoopGroup实例,一个用于处理网络请求的工作线程组,一个用于监听新连接的Boss线程组。
  5. ServerContainer类的构造函数调用了init()方法来初始化工作线程组和Boss线程组。
  6. 使用ServerBootstrap实例来配置服务器的基本参数,如工作线程组、通道类型和处理器。
  7. 通过listenPort()方法绑定一个指定的端口号。
  8. 通过listenPorts()方法监听所有配置的端口号。
  9. 有一个newServer()方法用于创建一个新的ServerBootstrap实例。
  10. 通过start()方法启动服务器,在指定的主机和端口上监听新连接。
  11. 通过stop()方法停止服务器,优雅地关闭工作线程组和Boss线程组。

总结:ServerContainer类是Holer服务器的核心容器类,负责处理服务器的启动和停止。它使用Netty库提供的API实现了一个基本的服务器框架,并通过单例模式确保全局唯一性。

[17/40]程序文件概述: holer-server/src/main/java/org/holer/server/constant/HolerType.java

该程序文件是一个Java枚举类,命名为HolerType。该枚举类定义了一些常见的网络协议类型,如HTTP、HTTPS、SSH等。每个协议类型都有一个与之对应的字符串类型(type属性),并提供了一个value方法用于获取该字符串类型。此外,该枚举类还提供了一个isValid方法,用于检查给定的字符串是否为有效的协议类型。

[18/40]程序文件概述: holer-server/src/main/java/org/holer/server/constant/ServerConst.java

该文件是一个Java类文件,位于org.holer.server.constant包下。该类中定义了一系列用于服务器的常量字段。

其中一些常量的含义如下:

  • EXTRA_CLIENTS:用于存储额外客户端的Netty Channel对象的AttributeKey。
  • OS_TYPE:操作系统类型,通过System.getProperty(“os.name”)获取。
  • SSL:字符串常量,表示SSL。
  • HOLER:字符串常量,表示Holer。
  • DOMAIN:表示域名。
  • PORT:表示端口号。
  • PROTOCOL:表示协议。
  • LISTEN_PORT:监听端口。
  • PROXY_CONF:代理配置文件路径。
  • HOLER_CONF:Holer配置文件路径。
  • NGINX_CONF:Nginx配置文件路径。
  • HOLER_SSL_JKS:Holer SSL证书密钥库路径。
  • CONF:配置文件路径。
  • NGINX_SSL:Nginx SSL。
  • HTTP:表示HTTP协议。
  • HTTPS:表示HTTPS协议。
  • HTTPS_PORT:HTTPS端口号。
  • HTTP_PORT:HTTP端口号。
  • SSL_CRT:SSL证书。
  • DOMAIN_RULE:域名的正则表达式规则。
  • KEY_RULE:密钥的正则表达式规则。
  • SERVER_RULE:服务器地址的正则表达式规则。
  • EMAIL_RULE:邮箱的正则表达式规则。
  • SERVER_MSG:服务器消息配置文件路径。
  • TOKEN:身份验证令牌。
  • VIEW_LOGIN:登录页面路径。
  • MAX_EXTRA_CLIENTS:最大额外客户端数。
  • MAX_PORT:最大端口号。
  • MIN_PORT:最小端口号。
  • MAX_DAY:最大天数。
  • DEFAULT_VALID_DAY:默认有效天数。
  • DEFAULT_DOMAIN:默认域名。
  • WISDOM_DOMAIN:智能域名。
  • ONLINE:在线状态。
  • OFFLINE:离线状态。
  • ONE_KB:1KB。
  • DEFAULT_HTTP_PORT:默认HTTP端口号。
  • API_PREFIX:API前缀。
  • LICENSE:许可证。
  • KEY:密钥。
  • NGINX_RELOAD:Nginx重新加载命令。
  • INCLUDE_CONF:Nginx配置文件中的include语句。
  • WEB_SERVER_PORT:Web服务器端口。
  • SERVER_DOMAIN:服务器域名。
  • SERVER_HOST:服务器主机。
  • SERVER_PORT:服务器端口。
  • SSLSERVER_ENABLE:SSL服务器是否启用。
  • SSLSERVER_HOST:SSL服务器主机。
  • SSLSERVER_PORT:SSL服务器端口。
  • HOLER_DOMAIN_NAME:Holer域名。
  • HOLER_SERIAL_NO:Holer许可证序列号。
  • HOLER_NGINX_BIN:Holer中Nginx可执行文件的路径。
  • HOLER_NGINX_CONF:Holer中Nginx配置文件的路径。
  • HOLER_NGINX_HOME:Holer中Nginx的安装目录。

[19/40]程序文件概述: holer-server/src/main/java/org/holer/server/constant/HolerCode.java

这是一个名为HolerCode.java的文件,位于src/main/java/org/holer/server/constant/路径下。这个文件定义了一个枚举类型HolerCode,包含了许多常量成员。每个常量成员都有一个对应的整数值,并通过构造函数进行初始化。HolerCode还提供了两个方法:value()用于获取常量成员的整数值,message()用于获取常量成员对应的消息文本。

[20/40]程序文件概述: holer-server/src/main/java/org/holer/server/model/HolerLicense.java

这个程序文件名为HolerLicense.java,位于org.holer.server.model包下的src/main/java目录中。它是一个Java类文件,用于定义HolerLicense对象的模型。

这个类使用了lombok库的@Data注解,自动生成了getter和setter方法。它实现了Serializable接口,表示可以被序列化。

HolerLicense类有以下成员变量:

  • licenseId:Long类型,表示许可证ID
  • userName:String类型,表示用户名
  • serialNum:String类型,表示序列号
  • validDay:Long类型,表示有效期天数
  • expireAt:String类型,表示过期时间
  • createAt:Long类型,表示创建时间
  • portNum:Long类型,表示端口号

这个类的作用是表示一个Holer许可证对象,并提供相关的属性和方法。这个类可用于在Holer服务器中存储和处理许可证信息。

[21/40]程序文件概述: holer-server/src/main/java/org/holer/server/model/HolerPort.java

这个文件是一个Java类文件,文件名为HolerPort.java。该类位于org.holer.server.model包。它是一个实体类,用于映射数据库表holer_port。该类定义了一些属性和方法,用于描述Holer服务器的端口信息,包括访问密钥(accessKey)、端口号(portNum)、服务器地址(server)、域名(domain)、Holer类型(type)等。该类还提供了一些辅助方法,用于计算有效天数(validDay)、过期时间(expireAt)、创建时间(createAt)和获取IP地址(inetAddr)。

[22/40]程序文件概述: holer-server/src/main/java/org/holer/server/model/HolerStatus.java

该文件是一个Java类文件,位于项目的holer-server模块中的org.holer.server.model包下。该类是一个数据模型类,用于表示Holer的状态。

该类使用了lombok库的@Data注解,自动生成了属性的getter、setter方法、equals()、hashCode()、toString()等方法。

HolerStatus类有以下属性:

  • code:一个整数,用于表示状态码。该属性被标注为不序列化和不反序列化。
  • msg:一个字符串,用于表示状态信息。该属性被标注为不序列化和不反序列化。
  • msgZhCN:一个字符串,用于表示中文状态信息。该属性会被序列化和反序列化,并使用SerializedName注解指定了序列化后的名称。
  • msgEnUS:一个字符串,用于表示英文状态信息。该属性会被序列化和反序列化,并使用SerializedName注解指定了序列化后的名称。

[23/40]程序文件概述: holer-server/src/main/java/org/holer/server/model/HolerClient.java

这个程序文件是holer-server项目的一部分。它定义了一个HolerClient类,在数据库表holer_client中映射了多个属性。该类实现了Serializable接口,并使用lombok库的@Data注解自动生成了getter和setter方法。HoldeClient类具有以下属性:clientId、name、accessKey、enabled、status、onlineAt、channel、ports。其中,clientId是自动生成的唯一标识符,name是一个非空且符合邮箱格式的字符串,accessKey是一个字符串,enabled是一个布尔值,status是一个整数。onlineAt和channel属性被标记为@Transient和@JsonIgnore,并不会在数据库中存储,而是用于临时存储数据。ports属性是一个HolerPort对象的列表。此外,类还包括一些方法,如publicPorts方法返回一个整数列表,并遍历ports列表以获取端口号。

[24/40]程序文件概述: holer-server/src/main/java/org/holer/server/model/HolerUser.java

该程序文件是一个Java类文件,名为HolerUser.java。该类位于org.holer.server.model包下。该类使用了Lombok库的@Data注解,以自动生成getter和setter方法。该类是一个实体类,使用了javax.persistence注解进行标注,以与数据库表holer_user进行映射。该类实现了Serializable接口,以支持序列化。类中包含了字段userId、name、password和token,分别表示用户id、用户名、密码和令牌。其中name字段使用了javax.validation.constraints注解进行验证,要求值不能为空且长度在3到128个字符之间;password字段也使用了javax.validation.constraints注解进行验证,要求值不能为空且长度在6到128个字符之间。

[25/40]程序文件概述: holer-server/src/main/java/org/holer/server/model/HolerData.java

这个程序文件是holer-server项目中的一个Java类文件,文件名是HolerData.java。这个类是一个POJO类,用于表示Holer服务器中的数据信息。它实现了java.io.Serializable接口,以便在网络传输和持久化存储过程中进行序列化和反序列化。

这个类有以下属性:

  • port (int类型): 表示服务器端口号
  • readBytes (long类型): 表示从客户端读取的字节数
  • wroteBytes (long类型): 表示向客户端写入的字节数
  • readMsgs (long类型): 表示已读取消息数
  • wroteMsgs (long类型): 表示已写入消息数
  • channels (int类型): 表示当前连接的通道数
  • timestamp (long类型): 表示时间戳

这个类使用了Lombok库中的@Data注解,自动生成了属性的getter和setter方法、toString方法等。

[26/40]程序文件概述: holer-server/src/main/java/org/holer/server/model/HolerResult.java

该源代码文件是一个名为HolerResult的Java类,位于org.holer.server.model包中。它具有以下属性和方法:

属性:

  • code:整数类型,表示返回结果的代码。
  • msg:字符串类型,表示返回结果的信息。
  • data:泛型T,表示返回结果的数据。
  • total:长整型,表示返回结果的总数。

构造方法:

  • HolerResult(Integer code):根据给定代码初始化结果对象,使用ServerUtil类获取代码对应的状态信息。
  • HolerResult(Integer code, String msg):使用给定的代码和信息初始化结果对象。
  • HolerResult(HolerCode code):根据给定的HolerCode枚举值初始化结果对象,使用ServerUtil类获取代码对应的状态信息。
  • HolerResult(Page<?> page, HolerCode code):根据给定的Page对象和HolerCode枚举值初始化结果对象,将Page对象的内容设置为结果对象的数据,并使用ServerUtil类获取代码对应的状态信息。
  • HolerResult(T data, HolerCode code):根据给定的数据和HolerCode枚举值初始化结果对象,将数据设置为结果对象的数据,并使用ServerUtil类获取代码对应的状态信息。

重要方法:

  • 无。

使用注解:

  • @Data:使用Lombok库生成getter、setter、hashCode、equals等方法。

[27/40]程序文件概述: holer-server/src/main/java/org/holer/server/model/HolerException.java

这个程序文件是holer-server项目中的一个Java类文件,文件名为HolerException.java。该类继承了RuntimeException类。它定义了一个HolerException异常,主要用于包装HolerCode和HolerStatus,提供了一些方法来获取异常的状态信息。该文件主要用于处理holer-server项目中的异常情况。

[28/40]程序文件概述: holer-server/src/main/java/org/holer/server/model/HolerReport.java

这个程序文件是holer-server项目中的一个Java类文件,文件名为HolerReport.java。它位于holer-server/src/main/java/org/holer/server/model/目录下。

该类使用了Lombok的@Data注解,自动生成了getter和setter方法。它实现了Serializable接口,并包含以下属性:

  • onlineClient: 在线客户端数量
  • offlineClient: 离线客户端数量
  • enabledClient: 启用的客户端数量
  • disabledClient: 禁用的客户端数量
  • expiredPort: 过期的端口数量
  • unexpiredPort: 未过期的端口数量
  • activePort: 活跃的端口数量
  • inactivePort: 不活跃的端口数量
  • upPort: 上行端口数量
  • downPort: 下行端口数量
  • appType: 使用Holer的应用类型及其数量的映射
  • connection: 连接数及其数量的映射
  • traffic: HolerData对象列表,表示流量数据

这个类用于表示Holer服务器的报告数据。

[29/40]程序文件概述: holer-server/src/main/java/org/holer/server/model/HolerApi.java

这是一个Java源代码文件,文件名为HolerApi.java。该文件包含了一个名为HolerApi的类,该类实现了Serializable接口,并使用了Lombok的@Data注解。该类具有以下属性:uri(String类型)、method(String类型)、free(boolean类型)。这些属性被自动生成了getter和setter方法。此外,该类还定义了一个名为serialVersionUID的静态长整型常量。

[30/40]程序文件概述: holer-server/src/main/java/org/holer/server/model/HolerChannel.java

这个程序文件是holler-server项目中的一个Java类文件,位于路径org.holler.server.model中。它实现了Serializable接口并使用了Lombok库中的@Data注解。该类具有以下成员变量:client,类型为HolerClient;ports,类型为Map<Integer, HolerPort>。这个类用于表示Holler服务器中的通道。

[31/40]程序文件概述: holer-server/src/main/java/org/holer/server/db/DBUserService.java

这个文件是 DBUserService.java,它位于 holer-server/src/main/java/org/holer/server/db 目录下。这是一个接口文件,定义了对数据库用户表进行操作的方法。它继承了 JpaRepository 接口,泛型参数为 HolerUserLong。这个接口定义了以下两个方法:

  • findByNameAndPassword 方法,根据用户名和密码查找用户。
  • findByToken 方法,根据令牌查找用户。

[32/40]程序文件概述: holer-server/src/main/java/org/holer/server/db/DBPortService.java

这是一个名为DBPortService.java的Java源代码文件,属于holer-server/src/main/java/org/holer/server/db目录。该文件定义了一个接口DBPortService,继承自JpaRepository<HolerPort, Long>。接口中定义了一些方法用于对HolerPort对象进行数据库操作,如根据accessKey、portNum、domain进行查询,根据accessKey进行删除,统计满足条件的记录数等。还有两个使用原生查询语句的方法,分别用于统计已过期的端口数量和活跃的端口数量。

[33/40]程序文件概述: holer-server/src/main/java/org/holer/server/db/DBClientService.java

这是一个名为DBClientService.java的Java文件,位于holer-server/src/main/java/org/holer/server/db目录中。该文件是一个接口文件,定义了一个名为DBClientService的接口。该接口继承了JpaRepository接口,并指定了泛型参数为HolerClient和Long。

DBClientService接口中定义了一些方法:

  • findByAccessKey:通过访问密钥查找HolerClient对象
  • findByName:通过名称查找HolerClient对象列表
  • countAllByStatus:计算所有状态为给定参数的HolerClient对象数量
  • countAllByEnabled:计算所有启用状态为给定参数的HolerClient对象数量

[34/40]程序文件概述: holer-server/src/main/java/org/holer/server/interceptor/ApiInterceptor.java

这个程序文件是一个名为ApiInterceptor.java的拦截器类,用于处理HTTP请求之前的拦截操作。它实现了Spring框架的HandlerInterceptor接口。在preHandle方法中,它会先检查请求中的令牌是否有效,如果令牌无效,则会返回一个包含错误代码的HolreResult对象,并返回false表示请求已被拦截。如果令牌有效,则返回true表示继续处理该请求。该拦截器被标记为@Component,表示它是一个由Spring管理的组件。

[35/40]程序文件概述: holer-server/src/main/java/org/holer/server/interceptor/ViewInterceptor.java

这个程序文件是一个名为ViewInterceptor的类,实现了HandlerInterceptor接口。它位于org.holer.server.interceptor包中,用于拦截请求并进行处理。

该类包含一个方法preHandle,用于处理请求之前的操作。在该方法中,它首先获取当前请求的HttpSession对象,并检查是否为null。如果为null,则通过HttpServletResponse对象将请求重定向到/login.html页面,并返回false表示请求不被继续处理。

然后,它从session中获取名为”HOLER-AUTH-TOKEN”的属性,并检查是否为null。如果为null,则通过HttpServletResponse对象将请求重定向到/login.html页面,并返回false表示请求不被继续处理。

最后,如果以上条件都不满足,它返回true,表示请求可以继续处理。

该类还使用了@Component注解,表示它是一个Spring组件,可以被Spring容器进行管理和注入。

[36/40]程序文件概述: holer-server/src/main/java/org/holer/server/rest/RESTClientService.java

这是一个名为RESTClientService.java的Java文件。它位于holer-server/src/main/java/org/holer/server/rest目录下。

这个文件定义了一个名为RESTClientService的类,该类是一个RestController,用于处理关于Holer客户端的REST API请求。它包含了一些常用的注解,如@Validated、@CrossOrigin、@RestController和@RequestMapping。

这个类依赖于DBClientService和DBPortService这两个数据库服务,并通过@Autowired注解进行自动注入。

它包含了一些处理REST API请求的方法,包括findAll、findByAccessKey、getReport、addClient、updateClient和deleteById。

这些方法使用了@GetMapping、@PostMapping、@PutMapping和@DeleteMapping注解,分别处理对应的HTTP请求方法。这些方法主要负责查询数据库的内容,并根据请求返回相应的结果。

整体而言,这个文件实现了一个RESTful API,用于处理关于Holer客户端的请求,并与数据库进行交互。

[37/40]程序文件概述: holer-server/src/main/java/org/holer/server/rest/RESTUserService.java

这个文件是一个名为RESTUserService的Java类,位于holer-server/src/main/java/org/holer/server/rest/目录下。该类提供了处理用户登录和退出功能的RESTful接口。其中,login方法处理用户登录请求,logout方法处理用户退出请求。该类依赖于DBUserService类实现数据库访问和操作。该文件还包含了一些注解用于配置接口路由和跨域访问。

[38/40]程序文件概述: holer-server/src/main/java/org/holer/server/rest/RESTPortService.java

该程序文件为一个RESTful风格的端口服务类,用于处理和管理端口的增删改查操作。

该类包含以下主要功能:

  1. 对于GET请求”/api/port/{clientId}”,根据客户端ID查询该客户端对应的端口列表。
  2. 对于POST请求”/api/port/{accessKey}”,新增一个端口,并关联到指定的访问密钥(accessKey)的客户端。
  3. 对于PUT请求”/api/port”,更新一个已存在的端口信息。
  4. 对于DELETE请求”/api/port/{portId}”,根据端口ID删除指定的端口。

该类依赖于其他类与服务:

  1. 使用@Autowired注解注入了DBClientService和DBPortService服务,用于与数据库进行交互。
  2. 使用了ServerUtil和ServerMgr工具类,提供了一些操作数据库和管理服务端口的方法。

该类还使用了一些常量和模型类,例如HolerCode、HolerType、HolerClient和HolerPort,用于表示不同的状态码、端口类型和客户端/端口模型。

整体来说,该程序文件是一个处理端口管理的RESTful服务类,通过对GET、POST、PUT和DELETE请求的处理,实现了对端口的增删改查功能。

[39/40]程序文件概述: holer-server/pom.xml

这个文件是一个 Maven 的 POM(Project Object Model)文件,用于构建 holser-server 项目。它定义了项目的基本信息,依赖项和构建配置。项目使用 Spring Boot 框架,主要依赖包括 Spring Boot Starter Web、Spring Boot Starter Data JPA、MySQL 连接器、Lombok、Commons Lang、Commons Collections、Commons BeanUtils、Commons Codec、JavaMail、Netty、OkHttp、H2 数据库和 Spring Boot Starter Actuator。构建配置包括 Maven 编译器插件和 Spring Boot Maven 插件。

[40/40]程序文件概述: holer-server/assembly.xml

这个程序文件是一个XML配置文件,用于指定Holer Server项目的打包和组装方式。

它包含以下内容:

  • <includeBaseDirectory>:指定在生成的tar.gz压缩包中是否包含与项目名相同的根目录。
  • <dependencySets>:定义依赖项集合,其中包括将本项目添加到依赖文件夹下的设置。
  • <outputDirectory>:指定将来自依赖项集合的运行时依赖包放在哪个目录下。
  • <fileSets>:定义文件集合,其中包括将src/main/bin目录下的文件复制到根目录下的设置。

简而言之,这个文件描述了如何组装和打包Holer Server项目,包括将项目本身和运行时依赖项一起打包,并将特定文件复制到特定目录。

用一张Markdown表格简要描述以下文件的功能:

文件路径 文件功能
holer-server/src/main/java/org/holer/server/
HolerApp.java
Holer服务器的主要入口文件,用于启动Holer服务器。
holer-server/src/main/java/org/holer/server/
handler/ExceptHandler.java
异常处理器类,处理控制器中抛出的异常。
holer-server/src/main/java/org/holer/server/
handler/ExtraClientHandler.java
处理客户端连接和数据传输的Netty事件处理器类。
holer-server/src/main/java/org/holer/server/
handler/DataHandler.java
数据处理器类,处理接收到的消息。
holer-server/src/main/java/org/holer/server/
handler/ServerHandler.java
服务器处理器类,处理服务器接收到的消息。
holer-server/src/main/java/org/holer/server/
init/ServerInitializer.java
服务器初始化类,用于初始化服务器管道。
holer-server/src/main/java/org/holer/server/
init/ExtraClientInitializer.java
额外的客户端初始化类,用于初始化额外的客户端管道。
holer-server/src/main/java/org/holer/server/
h2/H2Function.java
H2数据库函数类,包含了Unix时间戳转换的方法。
holer-server/src/main/java/org/holer/server/
util/DataCollector.java
数据收集器类,用于收集和管理数据。
holer-server/src/main/java/org/holer/server/
util/ServerUtil.java
服务器相关的实用工具类,提供一些公共方法和功能。
holer-server/src/main/java/org/holer/server/
util/ServerMgr.java
服务器管理工具类,提供管理服务器相关的静态方法和变量。
holer-server/src/main/java/org/holer/server/
config/SchedulerConfig.java
任务调度器的配置类,用于自定义任务调度器的配置。
holer-server/src/main/java/org/holer/server/
config/HolerWebConfig.java
Web配置类,用于配置拦截器和其他Web相关配置。
holer-server/src/main/java/org/holer/server/
config/CorsConfig.java
跨域资源共享(CORS)配置类,用于配置跨域请求处理。
holer-server/src/main/java/org/holer/server/
timer/HolerWorker.java
定时任务类,包含定时清除数据和关闭Holer的方法。
holer-server/src/main/java/org/holer/server/
container/ServerContainer.java
服务器容器类,用于启动和停止服务器。

整体而言,该组程序文件实现了一个Holer服务器,用于处理客户端连接、数据传输、异常处理、数据收集与管理、定时任务调度等功能。

概括这些文件的整体功能:这些文件的整体功能是实现一个Holer服务器,包括启动服务器、处理客户端连接和数据传输、处理异常、初始化服务器管道、使用H2数据库函数、收集和管理数据、提供服务器相关的实用工具和管理工具、配置任务调度器、配置Web和CORS、执行定时任务,以及启动和停止服务器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
flowchart LR
%% <gpt_academic_hide_mermaid_code> 一个特殊标记,用于在生成mermaid图表时隐藏代码块
classDef Comment stroke-dasharray: 5 5
subgraph 项目示意图
R0000000000["🗎HolerApp.java"] -.-x CR0000000000["`该文件是holer-
server项目的主
要入口文件。主要作用
是启动Holer服务
器,并且设置服务器的...`"]:::Comment
R000000000[["📁server"]] --> R0000000000["🗎HolerApp.java"]
R00000000010["🗎ExceptHandler.java"] -.-x CR00000000010["`该程序文件是一个Ja
va类文件,位于ho
ler-server
.zip.extra
ct/holer-s...`"]:::Comment
R0000000001[["📁handler"]] --> R00000000010["🗎ExceptHandler.java"]
R00000000011["🗎ExtraClientHandler.java"] -.-x CR00000000011["`该文件是holer项
目中的一个Java源
代码文件,路径为ho
ler-server
/src/main/...`"]:::Comment
R0000000001[["📁handler"]] --> R00000000011["🗎ExtraClientHandler.java"]
R00000000012["🗎DataHandler.java"] -.-x CR00000000012["`这个程序文件是Dat
aHandler.j
ava,它位于hol
er-server.
zip.ext...`"]:::Comment
R0000000001[["📁handler"]] --> R00000000012["🗎DataHandler.java"]
R00000000013["🗎ServerHandler.java"] -.-x CR00000000013["`该文件是holer-
server项目中的
一个处理程序类,用于
处理服务器收到的消息
。主要包括以下几个方...`"]:::Comment
R0000000001[["📁handler"]] --> R00000000013["🗎ServerHandler.java"]
R000000000[["📁server"]] --> R0000000001[["📁handler"]]
R00000000020["🗎ServerInitializer.java"] -.-x CR00000000020["`该文件是一个Java
类文件,位于hole
r-server.z
ip.extract
/holer-ser...`"]:::Comment
R0000000002[["📁init"]] --> R00000000020["🗎ServerInitializer.java"]
R00000000021["🗎ExtraClientInitializer.java"] -.-x CR00000000021["`这是一个名为Extr
aClientIni
tializer.j
ava的文件,位于h
oler-serve...`"]:::Comment
R0000000002[["📁init"]] --> R00000000021["🗎ExtraClientInitializer.java"]
R000000000[["📁server"]] --> R0000000002[["📁init"]]
R00000000030["🗎H2Function.java"] -.-x CR00000000030["`这是一个名为H2Fu
nction.jav
a的Java程序文件
,位于holer-s
erver.zip....`"]:::Comment
R0000000003[["📁h2"]] --> R00000000030["🗎H2Function.java"]
R000000000[["📁server"]] --> R0000000003[["📁h2"]]
R00000000040["🗎DataCollector.java"] -.-x CR00000000040["`这是一个名为Data
Collector的
Java类,它位于o
rg.holer.s
erver.util...`"]:::Comment
R0000000004[["📁util"]] --> R00000000040["🗎DataCollector.java"]
R00000000041["🗎ServerUtil.java"] -.-x CR00000000041["`这个程序文件是一个名
为ServerUti
l的工具类。它包含了
一些静态方法和实例方
法,用来提供服务器相...`"]:::Comment
R0000000004[["📁util"]] --> R00000000041["🗎ServerUtil.java"]
R00000000042["🗎ServerMgr.java"] -.-x CR00000000042["`该文件是一个名为Se
rverMgr的Ja
va类,主要包含了一
些静态变量和静态方法
。其中静态变量包括b...`"]:::Comment
R0000000004[["📁util"]] --> R00000000042["🗎ServerMgr.java"]
R000000000[["📁server"]] --> R0000000004[["📁util"]]
R00000000050["🗎SchedulerConfig.java"] -.-x CR00000000050["`这是一个名为Sche
dulerConfi
g的Java类文件,
位于holer-se
rver.zip....`"]:::Comment
R0000000005[["📁config"]] --> R00000000050["🗎SchedulerConfig.java"]
R00000000051["🗎HolerWebConfig.java"] -.-x CR00000000051["`这是一个名为Hole
rWebConfig
.java的配置文件
,位于org.hol
er.server....`"]:::Comment
R0000000005[["📁config"]] --> R00000000051["🗎HolerWebConfig.java"]
R00000000052["🗎CorsConfig.java"] -.-x CR00000000052["`这个文件是Holer
Server项目中
的一个配置文件,它用
于配置跨域资源共享(
CORS)功能。...`"]:::Comment
R0000000005[["📁config"]] --> R00000000052["🗎CorsConfig.java"]
R000000000[["📁server"]] --> R0000000005[["📁config"]]
R00000000060["🗎HolerWorker.java"] -.-x CR00000000060["`该程序文件名为Hol
erWorker.j
ava,位于org.
holer.serv
er.timer包下...`"]:::Comment
R0000000006[["📁timer"]] --> R00000000060["🗎HolerWorker.java"]
R000000000[["📁server"]] --> R0000000006[["📁timer"]]
R00000000070["🗎ServerContainer.java"] -.-x CR00000000070["`该程序文件是Hole
r服务器的主要容器类
,用于启动和停止服务
器。以下是该文件的关
键要点:1. 该...`"]:::Comment
R0000000007[["📁container"]] --> R00000000070["🗎ServerContainer.java"]
R000000000[["📁server"]] --> R0000000007[["📁container"]]
R00000000[["📁holer"]] --> R000000000[["📁server"]]
R0000000[["📁org"]] --> R00000000[["📁holer"]]
R000000[["📁java"]] --> R0000000[["📁org"]]
R00000[["📁main"]] --> R000000[["📁java"]]
R0000[["📁src"]] --> R00000[["📁main"]]
R000[["📁holer-server"]] --> R0000[["📁src"]]
R00[["📁holer-server.zip.extract"]] --> R000[["📁holer-server"]]
R0[["📁root"]] --> R00[["📁holer-server.zip.extract"]]
end

用一张Markdown表格简要描述以下文件的功能:

文件名 功能
HolerType.java 定义了Holer服务器支持的网络协议类型
ServerConst.java 定义了服务器相关的常量字段
HolerCode.java 定义了Holer服务器的状态码和消息文本
HolerLicense.java 定义了Holer服务器的许可证信息模型
HolerPort.java 定义了Holer服务器的端口信息模型
HolerStatus.java 定义了Holer服务器的状态信息模型
HolerClient.java 定义了Holer服务器的客户端信息模型
HolerUser.java 定义了Holer服务器的用户信息模型
HolerData.java 定义了Holer服务器的数据信息模型
HolerResult.java 定义了Holer服务器的通用结果封装模型
HolerException.java 定义了Holer服务器的异常类
HolerReport.java 定义了Holer服务器的报告信息模型
HolerApi.java 定义了Holer服务器的API接口信息模型
HolerChannel.java 定义了Holer服务器的通道信息模型
DBUserService.java 定义了对用户表进行数据库操作的接口
DBPortService.java 定义了对端口表进行数据库操作的接口

以上这些文件属于Holer服务器项目的不同模块,功能涵盖了启动服务器、连接和数据传输、异常处理、数据管理、结果封装、API接口定义和数据库操作等。综合来说,该程序的整体功能是实现一个Holer服务器,用于将本地服务映射到公网,实现内网穿透功能。

概括这些文件的整体功能:这些文件的整体功能是实现一个Holer服务器,包括定义服务器常量字段、状态码和消息文本、许可证信息、端口信息、状态信息、客户端信息、用户信息、数据信息、结果封装、异常处理、报告信息、API接口信息和通道信息模型,以及对用户表和端口表进行数据库操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
flowchart LR
%% <gpt_academic_hide_mermaid_code> 一个特殊标记,用于在生成mermaid图表时隐藏代码块
classDef Comment stroke-dasharray: 5 5
subgraph 项目示意图
R00000000000["🗎HolerType.java"] -.-x CR00000000000["`该程序文件是一个Ja
va枚举类,命名为H
olerType。该
枚举类定义了一些常见
的网络协议类型,如H...`"]:::Comment
R0000000000[["📁constant"]] --> R00000000000["🗎HolerType.java"]
R00000000001["🗎ServerConst.java"] -.-x CR00000000001["`该文件是一个Java
类文件,位于org.
holer.serv
er.constan
t包下。该类中定义了...`"]:::Comment
R0000000000[["📁constant"]] --> R00000000001["🗎ServerConst.java"]
R00000000002["🗎HolerCode.java"] -.-x CR00000000002["`这是一个名为Hole
rCode.java
的文件,位于src/
main/java/
org/holer/...`"]:::Comment
R0000000000[["📁constant"]] --> R00000000002["🗎HolerCode.java"]
R000000000[["📁server"]] --> R0000000000[["📁constant"]]
R00000000010["🗎HolerLicense.java"] -.-x CR00000000010["`这个程序文件名为Ho
lerLicense
.java,位于or
g.holer.se
rver.model...`"]:::Comment
R0000000001[["📁model"]] --> R00000000010["🗎HolerLicense.java"]
R00000000011["🗎HolerPort.java"] -.-x CR00000000011["`这个文件是一个Jav
a类文件,文件名为H
olerPort.j
ava。该类位于or
g.holer.se...`"]:::Comment
R0000000001[["📁model"]] --> R00000000011["🗎HolerPort.java"]
R00000000012["🗎HolerStatus.java"] -.-x CR00000000012["`该文件是一个Java
类文件,位于项目的h
oler-serve
r模块中的org.h
oler.serve...`"]:::Comment
R0000000001[["📁model"]] --> R00000000012["🗎HolerStatus.java"]
R00000000013["🗎HolerClient.java"] -.-x CR00000000013["`这个程序文件是hol
er-server项
目的一部分。它定义了
一个HolerCli
ent类,在数据库表...`"]:::Comment
R0000000001[["📁model"]] --> R00000000013["🗎HolerClient.java"]
R00000000014["🗎HolerUser.java"] -.-x CR00000000014["`该程序文件是一个Ja
va类文件,名为Ho
lerUser.ja
va。该类位于org
.holer.ser...`"]:::Comment
R0000000001[["📁model"]] --> R00000000014["🗎HolerUser.java"]
R00000000015["🗎HolerData.java"] -.-x CR00000000015["`这个程序文件是hol
er-server项
目中的一个Java类
文件,文件名是Hol
erData.jav...`"]:::Comment
R0000000001[["📁model"]] --> R00000000015["🗎HolerData.java"]
R00000000016["🗎HolerResult.java"] -.-x CR00000000016["`该源代码文件是一个名
为HolerResu
lt的Java类,位
于org.holer
.server.mo...`"]:::Comment
R0000000001[["📁model"]] --> R00000000016["🗎HolerResult.java"]
R00000000017["🗎HolerException.java"] -.-x CR00000000017["`这个程序文件是hol
er-server项
目中的一个Java类
文件,文件名为Hol
erExceptio...`"]:::Comment
R0000000001[["📁model"]] --> R00000000017["🗎HolerException.java"]
R00000000018["🗎HolerReport.java"] -.-x CR00000000018["`这个程序文件是hol
er-server项
目中的一个Java类
文件,文件名为Hol
erReport.j...`"]:::Comment
R0000000001[["📁model"]] --> R00000000018["🗎HolerReport.java"]
R00000000019["🗎HolerApi.java"] -.-x CR00000000019["`这是一个Java源代
码文件,文件名为Ho
lerApi.jav
a。该文件包含了一个
名为HolerApi...`"]:::Comment
R0000000001[["📁model"]] --> R00000000019["🗎HolerApi.java"]
R000000000110["🗎HolerChannel.java"] -.-x CR000000000110["`这个程序文件是hol
ler-server
项目中的一个Java
类文件,位于路径or
g.holler.s...`"]:::Comment
R0000000001[["📁model"]] --> R000000000110["🗎HolerChannel.java"]
R000000000[["📁server"]] --> R0000000001[["📁model"]]
R00000000020["🗎DBUserService.java"] -.-x CR00000000020["`这个文件是 DBUs
erService.
java,它位于 h
oler-serve
r.zip.e...`"]:::Comment
R0000000002[["📁db"]] --> R00000000020["🗎DBUserService.java"]
R00000000021["🗎DBPortService.java"] -.-x CR00000000021["`这是一个名为DBPo
rtService.
java的Java源
代码文件,属于hol
er-server....`"]:::Comment
R0000000002[["📁db"]] --> R00000000021["🗎DBPortService.java"]
R000000000[["📁server"]] --> R0000000002[["📁db"]]
R00000000[["📁holer"]] --> R000000000[["📁server"]]
R0000000[["📁org"]] --> R00000000[["📁holer"]]
R000000[["📁java"]] --> R0000000[["📁org"]]
R00000[["📁main"]] --> R000000[["📁java"]]
R0000[["📁src"]] --> R00000[["📁main"]]
R000[["📁holer-server"]] --> R0000[["📁src"]]
R00[["📁holer-server.zip.extract"]] --> R000[["📁holer-server"]]
R0[["📁root"]] --> R00[["📁holer-server.zip.extract"]]
end

用一张Markdown表格简要描述以下文件的功能:根据以上分析,用一句话概括程序的整体功能。

文件路径 文件功能描述
holer-server/src/main/java/org/holer/server/
db/DBClientService.java
定义数据库客户端服务接口,提供对Holer客户端的基本操作
holer-server/src/main/java/org/holer/server/
interceptor/ApiInterceptor.java
处理HTTP请求前的拦截操作,检查令牌是否有效
holer-server/src/main/java/org/holer/server/
interceptor/ViewInterceptor.java
处理请求前的拦截操作,检查会话和令牌是否有效
holer-server/src/main/java/org/holer/server/
rest/RESTClientService.java
提供Holer客户端的RESTful API接口,包括查询、新增、更新和删除
holer-server/src/main/java/org/holer/server/
rest/RESTUserService.java
提供用户登录和退出的RESTful API接口
holer-server/src/main/java/org/holer/server/
rest/RESTPortService.java
提供端口管理的RESTful API接口,包括查询、新增、更新和删除
holer-server/pom.xml Maven项目配置文件,定义项目的依赖和构建配置
holer-server/assembly.xml 组装和打包Holer Server项目的配置文件

总体来说,程序的整体功能是实现Holer服务器,包括数据库服务、拦截器、RESTful API接口和打包部署配置。

概括这些文件的整体功能:这些文件的整体功能是实现Holer服务器,包括定义数据库操作接口、拦截器类、RESTful API接口和项目构建、打包、部署配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
flowchart LR
%% <gpt_academic_hide_mermaid_code> 一个特殊标记,用于在生成mermaid图表时隐藏代码块
classDef Comment stroke-dasharray: 5 5
subgraph 项目示意图
R00000000000["🗎DBClientService.java"] -.-x CR00000000000["`这是一个名为DBCl
ientServic
e.java的Jav
a文件,位于hole
r-server.z...`"]:::Comment
R0000000000[["📁db"]] --> R00000000000["🗎DBClientService.java"]
R000000000[["📁server"]] --> R0000000000[["📁db"]]
R00000000010["🗎ApiInterceptor.java"] -.-x CR00000000010["`这个程序文件是一个名
为ApiInterc
eptor.java
的拦截器类,用于处理
HTTP请求之前的拦...`"]:::Comment
R0000000001[["📁interceptor"]] --> R00000000010["🗎ApiInterceptor.java"]
R00000000011["🗎ViewInterceptor.java"] -.-x CR00000000011["`这个程序文件是一个名
为ViewInter
ceptor的类,实
现了HandlerI
nterceptor...`"]:::Comment
R0000000001[["📁interceptor"]] --> R00000000011["🗎ViewInterceptor.java"]
R000000000[["📁server"]] --> R0000000001[["📁interceptor"]]
R00000000020["🗎RESTClientService.java"] -.-x CR00000000020["`这是一个名为REST
ClientServ
ice.java的J
ava文件。它位于h
oler-serve...`"]:::Comment
R0000000002[["📁rest"]] --> R00000000020["🗎RESTClientService.java"]
R00000000021["🗎RESTUserService.java"] -.-x CR00000000021["`这个文件是一个名为R
ESTUserSer
vice的Java类
,位于holer-s
erver.zip....`"]:::Comment
R0000000002[["📁rest"]] --> R00000000021["🗎RESTUserService.java"]
R00000000022["🗎RESTPortService.java"] -.-x CR00000000022["`该程序文件为一个RE
STful风格的端口
服务类,用于处理和管
理端口的增删改查操作
。该类包含以下主...`"]:::Comment
R0000000002[["📁rest"]] --> R00000000022["🗎RESTPortService.java"]
R000000000[["📁server"]] --> R0000000002[["📁rest"]]
R00000000[["📁holer"]] --> R000000000[["📁server"]]
R0000000[["📁org"]] --> R00000000[["📁holer"]]
R000000[["📁java"]] --> R0000000[["📁org"]]
R00000[["📁main"]] --> R000000[["📁java"]]
R0000[["📁src"]] --> R00000[["📁main"]]
R000[["📁holer-server"]] --> R0000[["📁src"]]
R0001["🗎pom.xml"] -.-x CR0001["`这个文件是一个 Ma
ven 的 POM(
Project Ob
ject Model
)文件,用于构建 h...`"]:::Comment
R000[["📁holer-server"]] --> R0001["🗎pom.xml"]
R0002["🗎assembly.xml"] -.-x CR0002["`这个程序文件是一个X
ML配置文件,用于指
定Holer Ser
ver项目的打包和组
装方式。它包含...`"]:::Comment
R000[["📁holer-server"]] --> R0002["🗎assembly.xml"]
R00[["📁holer-server.zip.extract"]] --> R000[["📁holer-server"]]
R0[["📁root"]] --> R00[["📁holer-server.zip.extract"]]
end
l

做任何事都非常厉害的诀窍,这3点你记好

记得高中时特喜欢看《名侦探柯南》,剧情对逻辑能力有一定考验,看起来还是比较烧脑的。

所以那时堂主就有意识不断提升自己的逻辑思维能力,也发现了自己因为该项能力不足而产生的各种问题。

每天那么多事情,还是不知道从哪里做起,总是手忙脚乱……

公开讲话或展示报告,总表达不出重点,心里特着急……

看书写文也是随心情,真正下笔时,不知道从何下手……

所以当看到这个同学的留言,真的很有共鸣:

堂主,我有一个疑问想求解答。像《金字塔原理》等这类书籍,看完后感觉想要真正融入实践去运用好难,不知道这是认知问题还是思维习惯的培养或者其他原因呢?

这本书堂主也看了几遍,最后发现,逻辑思维不好,既是思维固化的原因,也是认知以及方法论的问题。

所以,今天给大家分享的这篇文章,能够一定意义上帮助大家解决留言类似问题。

相信我,如果你借鉴文章中的一些方法,逻辑思维会有巨大提升!

01.

沟通框架法

日常沟通中,没有逻辑框架的表达差别,是很明显的。

比如你通知同事开会:

逻辑不清者:

下午3点开会,记得提前10分钟过来开空调到25°,在桌子上摆上景田,总监爱喝;

他下午要来总结月度目标,顺便帮我通知下其他人,在110会议室~

很可能到时候同事忘记通知其他人,晚到了半个小时,你也喝不上怡宝,被总监请去喝茶了……

有逻辑者:

今天下午3点,总监要来110会议室开月会,辛苦你通知下其他人;

再麻烦提前10分钟过来开好25°的空调,摆上总监爱喝的怡宝。

先说总体事项,再说细节,最后搭上同事个人收益。

下面堂主分享3个框架模型,可以作为形成你个人方法论的参考。

1、 工作沟通:STAR模型

这个模型能帮你轻松通过面试、工作汇报。

我们最大的问题,就是不懂如何有逻辑地向领导或面试官,展示自己的优势,以及工作的成果。

明明打好了满肚子的腹稿,一出口就变成了:“额……额……”

这种情况面试官内心独白估计是赶紧打发回去吧。

掌握好STAR模型的工作沟通方法,让你能够非常清楚自己需要表达什么。

S——情境(situation),事情是在什么情况发生的?

T——目标(target),你是如何明确自己的任务?

A——**行动(action)**,根据目标采取什么行动?

R——**结果(result)**,最后结果如何,个人有什么收获?

不需太啰嗦,每个点说1-2句即可。

举个面试例子,一个想去新媒体公司的大学生,自我介绍时可以这么说:

在校期间我是学校官方微信号的负责人(s);

我的主要任务是官方校园动态、和学生有趣槽点的推送,以及指导新社员(T)

在2年内我参考了近100个高校官微的运营模式,同时业余参加新媒体课程、请教老师(A)

最后总结了一套自己的写作模式和运营模式,经过验证,官微阅读量从6k上升到1.5w,自己拥有了5k粉丝量的个人账号。(R)

不到一分钟的时间,有条理地表达自己的工作成果,充分展现自己的个人能力。

2、 情感沟通:FOSSA模型

很多争吵都是因为情绪表达不到位,加剧了矛盾火力,越吵越凶。之后即便你有情绪,那么不妨在沟通之前,想想下面几个问题。

图片

另外在我们的人生道路上,永远不要发生无谓的冲突,你要清楚自己是一块宝石,犯不着和石头硬碰硬。

如果碰到烂人尽量大事化小,小事化了,实在触及到底线,再适当予以反击。

3、 阅读拆解:SQ3R模型

有逻辑地进行阅读,能大大提高你的读书吸收效率。

大多人都是拿本书就看,看完一头雾水,讨论起书中内容开始蒙了。

用SQ3R阅读模型框架,能轻松帮你理清思路,用最短的时间得到更多的知识点。

图片

同时阅读笔记很重要,绝对不只是单纯的“ctrl+v”、“ctrl+c”****,没经过思考的笔记,就算记得又臭又长也毫无用处,因为你根本不会去看。

02.

思维清单法

这是逆转你思考方式的方法,对生活工作都特别有帮助。

逻辑性强的人,善于解构任务,化繁为简,剔除无用信息, 能用更短的时间解决更多的事情。

这就是锻炼逻辑思维的好处和目的——替自己和别人省出更多时间,而时间就是金钱。

刚刚毕业时候做公司报告,我很认真写了30-50来张ppt。

结果当天被领导点名批评:废话连篇,乱七八糟,抓不住重点。

最后参考了一个思考顺序清单,通过大量练习,之后每次总结都基本能够得到领导的认可。

这个思维清单中和了「演绎推理法」「归纳整理法」****,能让你从时间、空间、事情重要程度等方面,进行全方位思考。

你遇到的每个难题,只要按照以下清单顺序考虑,都能迎刃而解,效果真不是吹的,谁用谁知道!

第一步:结论先行

第二步:分析情况

第三步:解决方法

第四步:时间规划

第五步:开始行动

举个应用例子,方便大家理解具体的操作方法:

你是新媒体公司的实习生, 现在要进行转正答辩,怎么有逻辑地表达自己3个月的工作成果?

第一步:结论先行

先把3个月的工作成果展示出来,让领导看到完成值。

这是特别重要的一点!不管报告还是沟通,先说结论能节省所有人的时间。

第二步:分析情况

列出影响数据的分析原因、工作亮点与不足、工作收获等……

这部分要遵循总分总原则,由上到下层层递进,带着“为什么会这样、如何改善”的思维,去剖析出每个问题。

第三步:确定方法

针对所有问题,用归纳法整理出“时间、空间”所有解决的方法、再用演绎法写出,每个能具体实施的方案。

比如:家离公司太远,通勤时间过长,学习时间过少。

时间上:每天提前半小时起床、或在上班途中学习、增大工作密度。

空间上:搬家,缩短空间距离。

第四步:时间规划

这一步,要根据自己的解决方法,和事情的重要程度,列成一个工作规划表:

先做什么、再做什么、之后做什么、最后做什么?

第五步:开始行动

如果不行动,上面所有的逻辑推理都是在纸上谈兵,只会让我们的思维认知停留在原地,毫无长进,所以,行动才是关键啊!

03.

持续积累法

接下来这句话,可能会让你恍然大悟!

其实很多时候,不是因为我们逻辑不好,而是我们的知识存量是有限!了解的事情太少,导致逻辑联系不起来。

想升级自己的逻辑思维,最根本的方法,就是扩大自己的知识储备。

接下来堂主就分享3种提升思维的认知渠道,就算只坚持10天半个月,也有很大的成效!

1. 尝试演讲,形成应激反应

能够参加演讲、辩论类的人,逻辑思维都会比一般人好很多,所以模仿优秀的人,也是很好的提升方法。

长期坚持下来,你就会遇事不慌,面对一切新挑战、繁琐工作,都能迅速上手~

图片

同时,生活中也要抓住一切机会,锻炼自己的表达能力,这里分享2个小细节:

1) 线上工作沟通时,需回复较长信息,可以刻意练习这个回复结构,来表达自己的观点:

第一、第二、第三……

2) 与人沟通时,也同样刻意练习:我有三个方面要说,123……

咳咳,这里我也有三句话要说, 大家注意啦!

第一,能坚持看到这里的同学好优秀!文章快结束了,再坚持坚持哦~

第二,如果喜欢这篇文章的话,记得保存下来,方便以后查看哦~

第三,答应我, 看完去输出个思维导图大纲,这是你提高逻辑思维第一步~

2.看思辨类节目,代入正确角色

这时有人要问了:堂主,我也没少看节目啊,我还是没长进啊。

为什么会这样?

因为你自动代入了观众角色啊,本来正方立场,结果反方一发言,你就觉得:啊好对好对,我怎么没想到!这时正方又把你拽回来:是啊是啊,就是这样!老铁懂我!

一直被别人牵着鼻子走,要是你在现场,估计投票键都会被你摁烂了。

代入选手角色, 选正方,就坚定做正方,选反方,就坚定做反方。

对方一发言,不是想着对对对,而是:不对,他有漏洞,忽略了客观角度,巴拉巴拉。队友发言,也不急着赞同,同样分析他的逻辑表达方式。

吃透这边的论证后,再换个立场训练,你会发现一期节目你得看3456遍,你才能彻底了解辩题的所有角度,客观地表达最正确的想法。

3. 读思辨类书籍,繁殖知识量

这个重要性,就不用我再多说啦,只有看更专业的书籍,才能更全面了解思维模型,废话不多说,直接上推荐书籍。

1)入门书籍,引起你纠正思维的兴趣:

图片

小学生也可以读的启蒙思维书籍,说一个道理搭配几个生活事例, 特别简单粗暴。

很喜欢这句话:人是生而自由的,却无往不在枷锁之中。

图片

完美不枯燥的一本书,书不厚但很耐读,干货特别多,故事很有趣。

从5个方面来帮助你形成自己的方法论:定义问题-分析问题-由谁解决问题-问题来自哪里-如何做一个问题解决者。

2)进阶书籍,系统学习深度思考

图片

前身是《学会提问》,我们最缺的就是批判性思维,这本是入门最佳之选,算是理性“杠精”指南,让你学会理智独立思考,就算说不过别人,也别被别人骗。

图片

读完可以立马用的干货书,书评有句话令人深思:“只要你有批判性思维你就能批判自己的思维”。

最后,送大家两句话,一起共勉:

1、 无论一个问题多么复杂,如果能以正确的方式去看待,它都会变得简单起来。

2、 花半秒钟就看透事物本质的人,和花一辈子都看不清事物本质的人,注定是截然不同的命运。

愿你能养成善于思考的习惯,生活中增加思考频次,慢慢掌握洞察事情本事的能力,点个「在看」,一起成为逻辑大神吧~

l

DBeaver Ultimate Edition 免费破解使用

背景

免费版本不支持导出excel格式,所以得想办法使用ue版本。

系统环境

  • 系统: macos 14.2.1/macos 10.13.6
  • SOC: m1 pro/intel

安装DBeaver UE

官方安装包下载地址 https://downloads.dbeaver.net/ultimate/23.3.0/dbeaver-ue-23.3.0-macos-x86_64.dmg

下载agent

链接: https://pan.baidu.com/s/1xWo75x9HiWDyQajGY9TUKw?pwd=a16r 提取码: a16r,下载并解压,放到一个专门的目录,下面会用到

修改 DBeaver UE

在应用程序里,右键显示包内容,找到dbeaver.ini (/Applications/DBeaverUltimate.app/Contents/Eclipse/dbeaver.ini)

找到 -vm,替换原始java路径,修改如下

1
2
3
4
-vm

# 你的java路径,如果本地没java环境,需要安装java环境。
/Library/Java/JavaVirtualMachines/zulu-20.jdk/Contents/Home/bin/java

然后在文件末尾添加如下两行

1
2
3
4
-Dlm.debug.mode=true

# 你下载的agent解压后的dbeaver-agent.jar的路径
-javaagent:/Users/xxx/Downloads/dbeaver-agent/dbeaver-agent.jar

修改Hosts

1
2
# dbeaver start
127.0.0.1 dbeaver.com

打开DBeaver UE

打开安装好的DBeaver UE,如果闪退或提示已损坏,请自行搜索解决办法。打开后,会提示让你输入注册码,输入下面的注册码即可

1
2
3
4
5
aYhAFjjtp3uQZmeLzF3S4H6eTbOgmru0jxYErPCvgmkhkn0D8N2yY6ULK8oT3fnpoEu7GPny7csN
sXL1g+D+8xR++/L8ePsVLUj4du5AMZORr2xGaGKG2rXa3NEoIiEAHSp4a6cQgMMbIspeOy7dYWX6
99Fhtpnu1YBoTmoJPaHBuwHDiOQQk5nXCPflrhA7lldA8TZ3dSUsj4Sr8CqBQeS+2E32xwSniymK
7fKcVX75qnuxhn7vUY7YL2UY7EKeN/AZ+1NIB6umKUODyOAFIc8q6zZT8b9aXqXVzwLJZxHbEgcO
8lsQfyvqUgqD6clzvFry9+JwuQsXN0wW26KDQA==

如无意外,目前应该已经破解成功了。

破解成功

l

为何大多数程序员做不了独立开发者?

知乎上有人提问:做个很小众的应用就可以月入数万,为什么多数程序员都不做个人开发?

图片

有个匿名的用户回答的挺好的,详细讲述了自己独立开发软件转起的经历,以下是正文内容:


我要匿名了,因为要说真话了。

我写的其中一个软件(后续以“电脑工具软件”称呼),电脑端的,月入在2.5~3万,规模还在扩大。

先说一下过程吧,提到的各种编程技术对于我后期做成这个小众应用都很重要。

12年毕业,在上海工作两年期间主要工作语言是C语言、RedHat服务器、Oracle数据库、Delphi7、C#的Winform技术,利用加班时间,我简单学过QT技术。

14年7月起,在郑州工作过一年,主要是C语言以及各种网络协议数据抓取、分析审计。

15年清明节,来深圳创业,直到18年7月份因团队变故离开,在此期间我担任公司CTO,学会了Java 、Mysql、Redis、CentOS、微信支付宝支付流程等。

18年到19年清明节前,我去河北,在此期间我学会了android应用开发(原生开发),但是没挣到钱。

19年初,春节过后,闲的,花了10天吧,完成了我要说的这个电脑工具软件软件的第一个版本,尽管很简陋,bug很多。

由于在河北没挣到钱,我又于19年清明节那天,回到了深圳,又加入了原来的那个团队。公司被他 们搞的一团遭,都破产了,我回来后,我们又接了个项目从头开始。

19年特别忙,我也没空再维护我那个软件。对于公司项目,我又学会了开发微信小程序,公众号,uniapp等技术。

20年,做了一个智能软件项目,我又学会了iOS开发(用的是object-c 和 uniapp 混合技术)

到此,根据我的熟练程度。

编程语言我掌握了:Java、JavaScript、C#、Python、Nodejs、go、Html、CSS、c、delphi数据库:mysql、Oracle、MangoDB、Redis

客户端:桌面网页端、Androdi端、windows电脑桌面客户端、iOS应用、微信小程序、公众号

服务器端:宝塔、Java的Springboot系列开发

总的来看,除过Mac上的软件,其它我都开发过,想想,我他妈真是好学。

再仔细想来,我11年就开发过android软件,我应该是中国第一批开发android软件的人。

之所以列举上面这些,是因为这些东西,都对我后来做成这个软件有重要影响。

接着20年继续说,20年后半后没那么忙了,我在周末抽空又把那个 电脑工具软件 翻出来,把bug修复了一下,界面再优化了一下,并加入了 根据电脑设备id号(就是将 cpu、主板、硬盘的序列号组后然后用md5生成的64位编号)校验功能,并在软件上留下了我的微信号,于20年9月份,我将软件发布到小众软件这个网站上了,有好些人夸赞我这个软件很实用,还提到了软件存在的问题。然后我有空,就修复一下,接着发新版本。

然后,有人付款,5块的,10块的,20块钱的,我生成一个证书文件(里面就是一串字母,包含了软件什么时候到期等信息),记得第10月就收到400多元,有一次一个哥们,一开心,直接给我转了300元。真的感谢这个哥们,那时候我穷。

11月份卖了800多元,12月份1600元,好开心,够房租了。此时,我意识到,这个软件能挣大钱。我想把软件上传到360软件管家、腾讯电脑管家的时候,都要一个东西:软著。所以,我就开始写了软著材料,开始申请了。

一个软著从申请到下来,如果不出任何差错,最快也得一个半月。如果出错了,打回来,再提交,又得1个半月。再等给你把纸质的软著寄回来,那还得再等2个月。我前前后后弄了半年才把软著给整下来,软著拿到手已经是21年四五月份了。

21年,由于公司业务遇到瓶颈,公司内部各种矛盾,哎,伤心。

21年,记得是有一次去宝安沙井,我给我伙伴说(公司就3个人),咱把我这个软件好好推推吧,我感觉能挣到不少钱。不过,他们没放到眼里。

然后21年2月份就到2000元,2月份到了3000元,4月月份到了5000元了,5月份6000,到10月已经有1万多了。(这些数据不是真实数据,但量级是一样的,只是为说明每月都增加不少收入,我记得有一个月比前一个月翻倍了)

到了10月底,公司解散了,哎,操蛋。

在21年里,由于忙,我一直都是一边忙公司的事情,周末有空了就维护一下软件的问题,主要是各种闪退,菜单弹不出来,显示出错等,但是功能还是那么简单,UI还是那么的简陋。一边了就在知乎发发帖子,推广我的软件。

11月份,我就搬家了,换了一个稍微大点的房子,本想去找工作的,但想了想,快到年底了,加上 好多公司裁员,工作估计不好找,况且我这个软件有收入,我想投入时间好好再完善一下,然后再去上班。

在此后,我的重点放在以下方面:

  1. 收集用户反馈的问题
  2. 收集用户的新需求
  3. 我自己深度琢磨用户的使用场景,不断做出更多更好用的功能点
  4. 研究如何将软件推广出去

以上4点缺一不可,不同阶段,重点不一样而已。

21年的11月、12月到22年的2月,这四项都在做,工作重要内容有:

  1. 修改用户反馈的问题
  2. 软件新增加了不少用户提的新功能
  3. 软件加上我自己琢磨的功能
  4. 在知乎上发了更多的推广
  5. 开发了服务器端程序,把软件改造为在线验证会员日期(原来是简单的激活码验证,因激活码与机器码绑定,大量机器码重复,很不靠谱)
  6. 给软件升级了新的 安装包功能(因为有些老系统,没有 包含一些 库文件,之前都是一个 压缩包直接发给用户的)

这三个多月很寂寞,是在家一个人孤独寂寞地在做,我都瘦了好多,因为天天吃挂面和凉拌黄瓜。

22年春节过后,3月份,我和另外一个朋友合租了一个办公室。对,我也没去找工作,此时,我一个月能赚到1.5万了。

从21年的4月份,到22年3月份,我尝试着将价格提高,并分月、季、半年、年、终身等套餐,直到探索到一个 不能再高的价格为止,价格套餐此后再没变过。

到22年3月份,搬到合租的办公室上班。接着以下问题困扰着我:

  1. 用户都是加我微信,给我赚钱,所以微信好友加多了,如果服务不到位,有人举报我,腾讯就把我微信号禁止加好友几天
  2. 赚钱转给我多了,腾讯老是给用户提醒 资金 安全
  3. 每天好多用户加我,尤其大中午的,搞的我好久没午休好了,状态极期低迷
  4. 以设备ID号来判断电脑,容易重复,重复率那是相当高。

所以,我就用我朋友的公司,花了半个月,弄了个微信、支付宝支付,再弄个了微信扫码登录功能,于五一前,终于上线了,我整个人都轻松了。

不过,要把钱提出来也是个问题,因为微信支付宝的钱,得先提到 业对公账户,对公账户的钱只能以工资或者其他手段弄出来,那么就得缴纳企业所得税、个税等。

到22年5月份,软件的功能基本上已经全了,bug很少很少了。此时,一个很重要的问题是,如何扩大规模,也就是推广。

推广才是最最重要的、最难的。

我尝试过。

  1. 知乎发帖子,但是你一个个人账号,帖子发多了,容易被当作广告,被平台删除。弄很多知乎账号,一是不现实,二是效果不好,账号权重太低,三帖子不能发太多。
  2. 百度贴吧、豆瓣、微博发帖子,有点效果,效果不是很突出,也存在着同样的被删帖封号的风险
  3. 抖音等视频平台发视频,效果不行,主要原因是我这是一个电脑软件,不是手机软件,效果不明显
  4. 做官网,官网改了一版又一版
  5. 百度搜索上打竞价广告,试过了,收益盖不住成本,但凡能持平,我也会使劲打广告的
  6. 在软著到手后,我迅速上架了360和腾讯软件管家,有效果,每天加起来能带来100多个下载,能转换成300多收益
  7. 我尝试,做各种活动(活动内容和方案不能在这里明说,我怕被用户和我的竞争对手知道这篇文章,事实上我的竞争对手在抄袭我的软件UI和推广手段,我主要是怕他们知道这玩意确实能赚钱,做的更带劲了),充分发动用户传播积极性,这招很管用。

以上6点,只有第5条、第6条、第7条的效果是长远而且行之有效的。

到了22年6月之后,软件终于不用我怎么管了,自行运行,自动收钱,然后躺平了。用户每天在增加,收益变得起来起多。

截止今天,23年6月18号,我都做了八九款电脑端软件了(名字不能在这里说)。

22年初过年开始,花了3个月,做的一个软件,从2022-05-21 15:00:11第一笔收入,到今天,8977个用户,挣了7113元。没推广过,感觉没啥钱途。

22年10月份,做的一个软件,从2022-11-12 11:03:08第一笔收入到现在,348个用户,挣了1738元。这个软件感觉有钱途,打算好好推广一波。

其它好几款软件,也没推广过,软著还没下来,一直放着。估计感觉没没有钱途不好说,真的懒的推广。

乱七八遭的,总结一下吧:

  1. 能做到现在这个程度,运气,运气,运气占很大成分。一是因为从做这个软件的第一版本,到我意识到能赚大钱的时候,经历了将近2年长时间;二是因为我做的其它软件,也卖的不好(或许是其它软件我也没用心推广过,都是自然流量);三是环节太多了,每个环节要探索,都要花好长时间验证,但凡一个环节不成功,就会失败。
  2. 你要掌握很多技术,不要指望别人和你一起开发,陌生人你信不过,朋友那你也得有即是做软件开发、也愿意和你投入时间的朋友,大家都很忙的,所以好多事情得你自己搞定。(比如官网、服务器端程序就是我自己做的)
  3. 你真的得有大把时间,一个软件你要改好,真的得花很多时间,有时候需要连续的很长一段时间,比如连续一个月两个月
  4. 推广营销才是最重要,见过很从客户,对功能产品蜜汁自信,一腔热血,但是做出来,让他们卖的时候,就蔫了。中国人很多,再小众的软件,也有人用,就看你能不能让他们找到你这个软件。那怕是功能相同的软件,你比他们的营销牛逼,你也能赚到钱。
  5. 脑袋瓜子确实要聪慧,能真正抓住什么是真需求、什么是伪需求,即不能不听别人的,也不能全听别人的,要会真正思考问题
  6. 我还得再接再厉,如题主的朋友那样,做到年百万收益。

我这个过程,我感觉都是不可复制的,各种尝试后的经验告诉我,如果你开发了一个软件:

  1. 想靠口碑传播起来,那是很慢的,你熬不住的。
  2. 迅速将软件做到一个差不多的版本,就猛打广告。如果收益能大于广告费,那么恭喜你,你要赚大钱了。如果收益和广告费持平,那么恭喜你,你可能要赚大钱了。如果广告费大于收益,你就好好分析原因。如果打了广告,还没收益,滚犊子,赶紧去上班吧。
  3. 时间才是最宝贵的,是最大的成本。现在时间是19:28,偌大的房子里,没开灯,唯有4k的显示器亮瞎了眼,望一望窗外,天黑了,又一天过去了

一把年纪了,想去找工作,估计也找不到了。我打算 做外贸和其它软件,就这样一个人这样搞下去!


于2023年7月13日 21:40:00 内容补充

浪迹知乎多年,属实不敢相信这种题材的贴子能火,但它就象彩票中大奖的新闻中报道的一样,我第一次随手倍投了十几条经验,它就中了榜一。

1. 为啥文中不提软件名字?

能看这个帖子的,绝大多是程序员,肯定有人会攻击我的服务器,破解我的软件,网上盗版漫天飞。

2. 为啥匿名?

我的其它知乎帖子中,有我的软件介绍,会带来“问题1”的麻烦。

3. 辛苦吗?

这是文中的错觉。在21年10月份,公司解散的时候,我的软件每月就有不少收入了,生活过得去。公司解散后,反而没有那么压力大了,因为没有任务计划逼着我赶进度了。每天都是想把软件做大做强的动力,驱使着我兴致勃勃地干活,相比以前,起得更早了,睡得更晚了,精神头也更好了。在干活时,我也不是一直盯着ide全神心在干活,事实是我一边在刷剧,一边在干活。脑中贯注于代码,大脑易疲惫,电影电视剧是大脑的兴奋催化剂。一年能看大约500多小时的剧,好些剧反复看。

周星驰系列,金庸系列,成龙系列,李保田的《神医喜来乐》《宰相刘罗锅》,张译的《光荣时代》,祁厅长的《人民的名义》,李幼斌的《亮剑》,《大秦帝国》三步曲(第四步不感兴趣)《三国演义》《西游记》《铁齿铜牙纪晓岚》《大明风华》,动物世界相关,动画片《超能勇士》,韩剧《搞笑一家人》

有好剧的,推荐一下,最好是喜剧。

4. 关于吃挂面和凉拌黄瓜

这一段,本没想渲染生活很惨,可意外的是效果如此。原因在于,主食我只会煮挂面和泡面,炒菜只想炒大白菜、小白菜、包菜(清洗方便,切起来顺手,炒时熟的快),凉菜偏好黄瓜(叉板切片,撒盐,倒醋,三步搞定),讲究的是 简单、速度快、省事。

5. 为啥发这个贴子

没火之前,刷了那么多贴子,楞是没嫖到多少有用的经验,或者说分享的内容不太干,看了没多少收获。所以,我想抛砖引玉,如我当天的预测,这个贴子没啥人用。想不到20天后,也就前天(7月11号)晚上有人回贴了,我也用心回了,直到昨天中午我还在认真回贴中。昨天晚上,突然发现点赞、收藏、评论猛增,有点诧异。直到习惯性地刷新了一下热榜,才意识到这贴子上热榜了。

这下,我可真是慌了。本着无私分享,以心换心,换别人经验的态度,贴子和评论的回复中,有些敏感的不谐内容。评论中我就挖啊挖,删啊删。贴子不想删除,因为评论中也有一些有用的信息。读了好几遍贴子,改了好多次。晚上都没睡好。

6. 关于如何联系我

我只是一个很普通的程序员,联系我也没啥用,我只想匿名交流经验。我的网易“易信”app号 “ biexiabibi ”。

7. 是正经软件吗?

文中早早就说了,有软著,在360、腾讯软件管家上有上传,绝对是合法合规的软件。

8. 看知友,觉得很强?

这也是错觉。

我一直都感觉在小打小闹,见识如井底之蛙,好在有自知之明。因为这些经验都是我自己琢磨出来的,始终认为外面有高人,别人做得风生水起,我得多找别人交流。

关于编程,那纯粹是好学,和时间一年一年积累出来的,是螺丝钉的深度,是扳手的技能,造不了航母。

9. 关于UI?

能“致敬”就致敬,能拿来就拿来,当然我也会画UI草图,也会PS。

10. 关于技术框架和服务器负载流量等?

客户端就不说了,用你顺手的做出来就行。服务器很便宜,服务器端都是云,至于配置,你要是感觉客户端卡的时候,你自己分析问题在哪,然后升级配置。对于小众的软件来讲,基本就是验证用户登录会员等信息的,你买最底配置1核1G内存1M带宽就够了,一个月30元吧。

11. 如何判断这个软件是否有前途?

我可以提供一些判断这个软件是否有前途的小建议:

(1) 去各种搜索指数的地方看看相关关键词搜索量,微信搜索指数 抖音搜索指数 微博搜索指数 百度 360 搜狗搜索指数

(2) 去抖音 快手 小红书 微信搜索 百度360搜狗 知乎 微博 豆瓣 等去搜一下相关内容,各种关键词,反复试探搜索

(3) qq群,看看有没有相关群

(4) 看看同行的产品,加他们的qq群,打探敌情;去应用商店看评论,看看用户的评价。

(5) 发抖音,发朋友圈调研,看看大家的评论

(6) 发抖音,发朋友圈,假装你已经开发好了,需要的私信,看看大家的咨询购买意愿。花点钱,推一推。

(7) 一个软件要做成的环节很多,别人没做成功不代表你不可以做。有的人可能技术不行,有的人做出来的功能不全,或者没做到用户最重要的点上,有的人压根就没推广。我意思是,别人做过的,你也可以做。

(8) 有时候也可以蹭风口,比如现在流行的chatgpt,整一堆账号,搭建个代理,然后使劲在抖音打广告。赚一波就走。

(9) 做完以上,就到了你自己 做决定的时候了(至于怎么做,我也有点模糊),你凭感觉吧,哈哈。

至于怎么做决定,大的讲,就三点:你能做出来吗?你能营销卖出去吗?投入成本和获得的收益值得去做吗?

12. 做成免费软件然后用广告收费靠谱吗?

能收费就收费,否则就上广告,广告和收费你也可以一块上。至于怎么弄,这得综合考虑。因素有:竞争对手有没有,竞争对手的产品如何,竞争对手推广的好不好,目标用户的消费能力如何,目标用户对这个产品使用习惯,以及你的运营成本。

(1) 如果没竞争对手,或者别人都找不到竞争对手的产品,那就就收费,可劲提高收费,因为你相当于垄断。至于定价多少,小学六年级我们就学过餐厅菜定价问题。经观察,价格和顾客数量有一个线性关系,求定价多少,才能使利润最大化。

(2) 如果你有竞争对手,对手很牛,营销也很好,那么对手收费的,那你就比他便宜,或者免费。

总之,你一定要比别人有至少一个点的优势,如价格优势,或者 某个特有功能优势。
13. 脑袋空空的,没啥好创意,找不到感觉?

(1)去 小众应用 网站,360 腾讯软件管家,国外下载站,mac apple android 等应用网站多看看
(2)多用百度 微信 抖音 等搜索指数 看看一些关键词的搜索量
(3)多看广告,尤其抖音 百度 上的人家持续推广的软件相关的广告(重点)
(4)去看看一些任务外包平台,别人的小需求,可能蕴藏着大商机(重点)
(5)多看看别人在运营的软件,多琢磨它的盈利点,以及运营手段
(6)别人做过的,你也可以做,重点是 运营(重点)
多看多琢磨,积累素材,慢慢就有感觉了,能感觉哪些可以做,哪些不可以做。如果你不看不琢磨,脑袋空空,一点素材都没有,大脑如何联想、如何想象,如何迸发灵感,脑袋怎么可能有感觉了!≠

l

如何查看 Linux 服务器性能参数指标?

一个基于 Linux 操作系统的服务器运行的同时,也会表征出各种各样参数信息。通常来说运维人员、系统管理员会对这些数据会极为敏感,但是这些参数对于开发者来说也十分重要,尤其当你的程序非正常工作的时候,这些蛛丝马迹往往会帮助快速定位跟踪问题。这里只是一些简单的工具查看系统的相关参数,当然很多工具也是通过分析加工 /proc、/sys 下的数据来工作的,而那些更加细致、专业的性能监测和调优,可能还需要更加专业的工具(perf、systemtap 等)和技术才能完成哦。毕竟来说,系统性能监控本身就是个大学问。

img

一、CPU和内存类

1.1 top

➜ ~ top

img

第一行后面的三个值是系统Ç Ç 在之前 1、5、15 的平均负载,也可以看出系统负载是上升、平稳、下降的趋势,当这个值超过 CPU 可执行单元的数目,则表示 CPU 的性能已经饱和成为瓶颈了。

第二行统计了系统的任务状态信息。running 很自然不必多说,包括正在 CPU 上运行的和将要被调度运行的;sleeping 通常是等待事件(比如 IO 操作)完成的任务,细分可以包括 interruptible 和 uninterruptible 的类型;stopped 是一些被暂停的任务,通常发送 SIGSTOP 或者对一个前台任务操作 Ctrl-Z 可以将其暂停;zombie 僵尸任务,虽然进程终止资源会被自动回收,但是含有退出任务的 task descriptor 需要父进程访问后才能释放,这种进程显示为 defunct 状态,无论是因为父进程提前退出还是未 wait 调用,出现这种进程都应该格外注意程序是否设计有误。

第三行 CPU 占用率根据类型有以下几种情况:

√ (us) user:CPU 在低 nice 值(高优先级)用户态所占用的时间(nice<=0)。正常情况下只要服务器不是很闲,那么大部分的 CPU 时间应该都在此执行这类程序

√ (sy) system:CPU 处于内核态所占用的时间,操作系统通过系统调用(system call)从用户态陷入内核态,以执行特定的服务;通常情况下该值会比较小,但是当服务器执行的 IO 比较密集的时候,该值会比较大

√ (ni) nice:CPU 在高 nice 值(低优先级)用户态以低优先级运行占用的时间(nice>0)。默认新启动的进程 nice=0,是不会计入这里的,除非手动通过 renice 或者 setpriority() 的方式修改程序的nice值

√ (id) idle:CPU 在空闲状态(执行 kernel idle handler )所占用的时间

√ (wa) iowait:等待 IO 完成做占用的时间

√ (hi) irq:系统处理硬件中断所消耗的时间

√ (si) softirq:系统处理软中断所消耗的时间,记住软中断分为 softirqs、tasklets (其实是前者的特例)、work queues,不知道这里是统计的是哪些的时间,毕竟 work queues 的执行已经不是中断上下文了

√ (st) steal:在虚拟机情况下才有意义,因为虚拟机下 CPU 也是共享物理 CPU 的,所以这段时间表明虚拟机等待 hypervisor 调度 CPU 的时间,也意味着这段时间 hypervisor 将 CPU 调度给别的 CPU 执行,这个时段的 CPU 资源被“stolen”了。这个值在我 KVM 的 VPS 机器上是不为 0 的,但也只有 0.1 这个数量级,是不是可以用来判断 VPS 超售的情况?

CPU 占用率高很多情况下意味着一些东西,这也给服务器 CPU 使用率过高情况下指明了相应地排查思路:

√ 当 user 占用率过高的时候,通常是某些个别的进程占用了大量的 CPU,这时候很容易通过 top 找到该程序;此时如果怀疑程序异常,可以通过 perf 等思路找出热点调用函数来进一步排查;

√ 当 system 占用率过高的时候,如果 IO 操作(包括终端 IO)比较多,可能会造成这部分的 CPU 占用率高,比如在 file server、database server 等类型的服务器上,否则(比如>20%)很可能有些部分的内核、驱动模块有问题;

√ 当 nice 占用率过高的时候,通常是有意行为,当进程的发起者知道某些进程占用较高的 CPU,会设置其 nice 值确保不会淹没其他进程对 CPU 的使用请求;

√ 当 iowait 占用率过高的时候,通常意味着某些程序的 IO 操作效率很低,或者 IO 对应设备的性能很低以至于读写操作需要很长的时间来完成;

√ 当 irq/softirq 占用率过高的时候,很可能某些外设出现问题,导致产生大量的irq请求,这时候通过检查 /proc/interrupts 文件来深究问题所在;

√ 当 steal 占用率过高的时候,黑心厂商虚拟机超售了吧!

第四行和第五行是物理内存和虚拟内存(交换分区)的信息:

total = free + used + buff/cache,现在buffers和cached Mem信息总和到一起了,但是buffers和cached Mem 的关系很多地方都没说清楚。其实通过对比数据,这两个值就是 /proc/meminfo 中的 Buffers 和 Cached 字段:Buffers 是针对 raw disk 的块缓存,主要是以 raw block 的方式缓存文件系统的元数据(比如超级块信息等),这个值一般比较小(20M左右);而 Cached 是针对于某些具体的文件进行读缓存,以增加文件的访问效率而使用的,可以说是用于文件系统中文件缓存使用。

而 avail Mem 是一个新的参数值,用于指示在不进行交换的情况下,可以给新开启的程序多少内存空间,大致和 free + buff/cached 相当,而这也印证了上面的说法,free + buffers + cached Mem才是真正可用的物理内存。并且,使用交换分区不见得是坏事情,所以交换分区使用率不是什么严重的参数,但是频繁的 swap in/out 就不是好事情了,这种情况需要注意,通常表示物理内存紧缺的情况。

最后是每个程序的资源占用列表,其中 CPU 的使用率是所有 CPU core 占用率的总和。通常执行 top 的时候,本身该程序会大量的读取 /proc 操作,所以基本该 top 程序本身也会是名列前茅的。

top 虽然非常强大,但是通常用于控制台实时监测系统信息,不适合长时间(几天、几个月)监测系统的负载信息,同时对于短命的进程也会遗漏无法给出统计信息。

1.2 vmstat

vmstat 是除 top 之外另一个常用的系统检测工具,下面截图是我用-j4编译boost的系统负载。

img

r 表示可运行进程数目,数据大致相符;而b表示的是 uninterruptible 睡眠的进程数目;swpd 表示使用到的虚拟内存数量,跟 top-Swap-used 的数值是一个含义,而如手册所说,通常情况下 buffers 数目要比 cached Mem 小的多,buffers 一般20M这么个数量级;io 域的 bi、bo 表明每秒钟向磁盘接收和发送的块数目(blocks/s);system 域的 in 表明每秒钟的系统中断数(包括时钟中断),cs表明因为进程切换导致上下文切换的数目。

说到这里,想到以前很多人纠结编译 linux kernel 的时候 -j 参数究竟是 CPU Core 还是 CPU Core+1?通过上面修改 -j 参数值编译 boost 和 linux kernel 的同时开启 vmstat 监控,发现两种情况下 context switch 基本没有变化,且也只有显著增加 -j 值后 context switch 才会有显著的增加,看来不必过于纠结这个参数了,虽然具体编译时间长度我还没有测试。资料说如果不是在系统启动或者 benchmark 的状态,参数 context switch>100000 程序肯定有问题。

1.3 pidstat

如果想对某个进程进行全面具体的追踪,没有什么比 pidstat 更合适的了——栈空间、缺页情况、主被动切换等信息尽收眼底。这个命令最有用的参数是-t,可以将进程中各个线程的详细信息罗列出来。

-r:显示缺页错误和内存使用状况,缺页错误是程序需要访问映射在虚拟内存空间中但是还尚未被加载到物理内存中的一个分页,缺页错误两个主要类型是

√ minflt/s 指的 minor faults,当需要访问的物理页面因为某些原因(比如共享页面、缓存机制等)已经存在于物理内存中了,只是在当前进程的页表中没有引用,MMU 只需要设置对应的 entry 就可以了,这个代价是相当小的

√ majflt/s 指的 major faults,MMU 需要在当前可用物理内存中申请一块空闲的物理页面(如果没有可用的空闲页面,则需要将别的物理页面切换到交换空间去以释放得到空闲物理页面),然后从外部加载数据到该物理页面中,并设置好对应的 entry,这个代价是相当高的,和前者有几个数据级的差异

-s:栈使用状况,包括 StkSize 为线程保留的栈空间,以及 StkRef 实际使用的栈空间。使用ulimit -s发现CentOS 6.x上面默认栈空间是10240K,而 CentOS 7.x、Ubuntu系列默认栈空间大小为8196K

img

-u:CPU使用率情况,参数同前面类似

-w:线程上下文切换的数目,还细分为cswch/s因为等待资源等因素导致的主动切换,以及nvcswch/s线程CPU时间导致的被动切换的统计

如果每次都先ps得到程序的pid后再操作pidstat会显得很麻烦,所以这个杀手锏的-C可以指定某个字符串,然后Command中如果包含这个字符串,那么该程序的信息就会被打印统计出来,-l可以显示完整的程序名和参数

➜ ~ pidstat -w -t -C “ailaw” -l

这么看来,如果查看单个尤其是多线程的任务时候,pidstat比常用的ps更好使!

1.4 其他

当需要单独监测单个 CPU 情况的时候,除了 htop 还可以使用 mpstat,查看在 SMP 处理器上各个 Core 的工作量是否负载均衡,是否有某些热点线程占用 Core。

➜ ~ mpstat -P ALL 1

如果想直接监测某个进程占用的资源,既可以使用top -u taozj的方式过滤掉其他用户无关进程,也可以采用下面的方式进行选择,ps命令可以自定义需要打印的条目信息:

while :; do ps -eo user,pid,ni,pri,pcpu,psr,comm | grep ‘ailawd’; sleep 1; done

如想理清继承关系,下面一个常用的参数可以用于显示进程树结构,显示效果比pstree详细美观的多

➜ ~ ps axjf

二、磁盘IO类

iotop 可以直观的显示各个进程、线程的磁盘读取实时速率;lsof 不仅可以显示普通文件的打开信息(使用者),还可以操作 /dev/sda1 这类设备文件的打开信息,那么比如当分区无法 umount 的时候,就可以通过 lsof 找出磁盘该分区的使用状态了,而且添加 +fg 参数还可以额外显示文件打开 flag 标记。

2.1 iostat

➜ ~ iostat -xz 1

其实无论使用 iostat -xz 1 还是使用 sar -d 1,对于磁盘重要的参数是:

√ avgqu-s:发送给设备 I/O 请求的等待队列平均长度,对于单个磁盘如果值>1表明设备饱和,对于多个磁盘阵列的逻辑磁盘情况除外

√ await(r_await、w_await):平均每次设备 I/O 请求操作的等待时间(ms),包含请求排列在队列中和被服务的时间之和;

√ svctm:发送给设备 I/O 请求的平均服务时间(ms),如果 svctm 与 await 很接近,表示几乎没有 I/O 等待,磁盘性能很好,否则磁盘队列等待时间较长,磁盘响应较差;

√ %util:设备的使用率,表明每秒中用于 I/O 工作时间的占比,单个磁盘当 %util>60% 的时候性能就会下降(体现在 await 也会增加),当接近100%时候就设备饱和了,但对于有多个磁盘阵列的逻辑磁盘情况除外;

还有,虽然监测到的磁盘性能比较差,但是不一定会对应用程序的响应造成影响,内核通常使用 I/O asynchronously 技术,使用读写缓存技术来改善性能,不过这又跟上面的物理内存的限制相制约了。

上面的这些参数,对网络文件系统也是受用的。

三、网络类

网络性能对于服务器的重要性不言而喻,工具 iptraf 可以直观的现实网卡的收发速度信息,比较的简洁方便通过 sar -n DEV 1 也可以得到类似的吞吐量信息,而网卡都标配了最大速率信息,比如百兆网卡千兆网卡,很容易查看设备的利用率。

通常,网卡的传输速率并不是网络开发中最为关切的,而是针对特定的 UDP、TCP 连接的丢包率、重传率,以及网络延时等信息。

3.1 netstat

➜ ~ netstat -s

显示自从系统启动以来,各个协议的总体数据信息。虽然参数信息比较丰富有用,但是累计值,除非两次运行做差才能得出当前系统的网络状态信息,亦或者使用 watch 眼睛直观其数值变化趋势。所以netstat通常用来检测端口和连接信息的:

netstat –all(a) –numeric(n) –tcp(t) –udp(u) –timers(o) –listening(l) –program(p)

–timers可以取消域名反向查询,加快显示速度;比较常用的有

➜ ~ netstat -antp #列出所有TCP的连接
➜ ~ netstat -nltp #列出本地所有TCP侦听套接字,不要加-a参数

3.2 sar

sar 这个工具太强大了,什么 CPU、磁盘、页面交换啥都管,这里使用 -n 主要用来分析网络活动,虽然网络中它还给细分了 NFS、IP、ICMP、SOCK 等各种层次各种协议的数据信息,我们只关心 TCP 和 UDP。下面的命令除了显示常规情况下段、数据报的收发情况,还包括

TCP

➜ ~ sudo sar -n TCP,ETCP 1

img

√ active/s:本地发起的 TCP 连接,比如通过 connect(),TCP 的状态从CLOSED -> SYN-SENT

√ passive/s:由远程发起的 TCP 连接,比如通过 accept(),TCP 的状态从LISTEN -> SYN-RCVD

√ retrans/s(tcpRetransSegs):每秒钟 TCP 重传数目,通常在网络质量差,或者服务器过载后丢包的情况下,根据 TCP 的确认重传机制会发生重传操作

√ isegerr/s(tcpInErrs):每秒钟接收到出错的数据包(比如 checksum 失败)

UDP
➜ ~ sudo sar -n UDP 1

√ noport/s(udpNoPorts):每秒钟接收到的但是却没有应用程序在指定目的端口的数据报个数

√ idgmerr/s(udpInErrors):除了上面原因之外的本机接收到但却无法派发的数据报个数

当然,这些数据一定程度上可以说明网络可靠性,但也只有同具体的业务需求场景结合起来才具有意义。

3.3 tcpdump

tcpdump 不得不说是个好东西。大家都知道本地调试的时候喜欢使用 wireshark,但是线上服务端出现问题怎么弄呢?

附录的参考文献给出了思路:复原环境,使用 tcpdump 进行抓包,当问题复现(比如日志显示或者某个状态显现)的时候,就可以结束抓包了,而且 tcpdump 本身带有 -C/-W 参数,可以限制抓取包存储文件的大小,当达到这个这个限制的时候保存的包数据自动 rotate,所以抓包数量总体还是可控的。此后将数据包拿下线来,用 wireshark 想怎么看就怎么看,岂不乐哉!tcpdump 虽然没有 GUI 界面,但是抓包的功能丝毫不弱,可以指定网卡、主机、端口、协议等各项过滤参数,抓下来的包完整又带有时间戳,所以线上程序的数据包分析也可以这么简单。

下面就是一个小的测试,可见 Chrome 启动时候自动向 Webserver 发起建立了三条连接,由于这里限制了 dst port 参数,所以服务端的应答包被过滤掉了,拿下来用 wireshark 打开,SYNC、ACK 建立连接的过程还是很明显的!在使用 tcpdump 的时候,需要尽可能的配置抓取的过滤条件,一方面便于接下来的分析,二则 tcpdump 开启后对网卡和系统的性能会有影响,进而会影响到在线业务的性能。

img

欢迎大家一起学习交流

l

ZFile Docker 镜像构建过程

前言

下文提供 ZFile 镜像构建过程,供大家参考。

Dockerfile

1
2
3
4
5
6
7
8
9
10
11
12
13
FROM ibm-semeru-runtimes:open-8-jre

WORKDIR /root

RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo 'Asia/Shanghai' >/etc/timezone

RUN curl -o app.jar https://c.jun6.net/ZFILE/zfile-release.jar

EXPOSE 8080

ENTRYPOINT java $JAVA_OPTS -Xshareclasses -Xquickstart -jar /root/app.jar

  • FROM ibm-semeru-runtimes:open-8-jre 表示使用的基础镜像,这里选中的这个是 ibmopenj9 jdk8 版本的 jre,这个版本的 jdk 具有内存占用小,启动速度快等优势,且针对 docker环境做过特殊优化。
  • WORKDIR /root 表示工作目录在 /root,下方所有命令将在这个目录下执行
  • RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtimeRUN echo 'Asia/Shanghai' >/etc/timezone 表示设置时区为上海时间,这两个设置的区别参考:https://unix.stackexchange.com/questions/384971/whats-the-difference-between-localtime-and-timezone-files
  • RUN curl -o app.jar https://c.jun6.net/ZFILE/zfile-release.jar 表示下载 zfile 最新版 jar 包,并命名为 app.jar,因为上方工作目录为 /root,所以实际下载到了 /root/app.jar
  • EXPOSE 8080 表示容器可能会使用这个端口,这个只是声明或备注式的,不会实际影响端口情况。
  • ENTRYPOINT java $JAVA_OPTS -Xshareclasses -Xquickstart -jar /root/app.jar 表示启动 /root/app.jar,其中 -Xshareclasses -Xquickstartibmopenj9 jvm 的参数,用来优化内存占用。

build

由于需要同时支持 arm64 架构和 amd64 架构,所以使用的 docker多平台构建,即同时 build 多个架构的镜像。

  1. 由于 Docker 默认的 builder 实例不支持同时指定多个 --platform,我们必须首先创建一个新的 builder 实例。
1
2
docker buildx create --name zfile-builder --driver docker-container

  1. 使用新创建好的 builder 实例
1
2
docker buildx use zfile-builder

  1. 查看已有的 builder 支持构建的架构类型
1
2
docker buildx ls

  1. 安装模拟器(用于模拟其他平台的构建)
1
2
docker run --privileged --rm tonistiigi/binfmt --install all

  1. Dockerfile 所在目录执行构建命令并 pushdocker hub (需提前 docker login 账号)
1
2
docker buildx build --platform linux/arm64,linux/amd64 -t zhaojun1998/zfile:latest --push .

结语

然后在 docker hub 就可以看到推送的镜像了。

[docker-hub_images

后续还会更新如何使用 CI 工具自动化构建镜像的方式。

l

mac catalina 手动安装openssl@3

mac catalina 通过homebrew 安装 openssl 失败,被嫌弃系统太老,make test 测试不通过

I manually installed openssl@3 with the following commands

  1. Download the latest version from https://www.openssl.org/source/openssl-3.1.1.tar.gz
  2. Uncompress the file with double click and open the terminal. Find the created folder and cd openssl-3.1.1
  3. Continue with
    perl ./Configure --prefix=/usr/local --openssldir=/usr/local/openssl no-ssl3 no-ssl3-method no-zlib darwin64-x86_64-cc enable-ec_nistp_64_gcc_128
  4. make
  5. make test (optional) I passed all tests
  6. sudo make install MANDIR=/usr/local/Cellar/openssl@3/3.1.1_1/share/man MANSUFFIX=ssl
  7. openssl version (optional - verification). It should report OpenSSL 3.1.1 30 May 2023 (Library: OpenSSL 3.1.1 30 May 2023)
  8. which -a openssl (optional).
  9. brew link openssl@3
  10. brew list (optional) you should see the openssl@3 inside installed packages.
l

关闭 OneDrive 内部的自动更新机制

我有一台用了十年的 mac mini,这台电脑的质量还是不错的。虽然也升级了内存和硬盘。 这个没怎么清过灰的家伙也一直没坏。稳定地发挥一个 HTPC 的作用。 不过苹果是已经放弃了它,最终它停留在 catalina。 不过最近我遇到了点麻烦:onedrive 打不开了。

目录

本文使用到了 homebrew,如果你没有或不能使用 brew,请参考另一篇:

更新

目前看来,这是微软推送了一个未在 catalina 上验证过的更新,目前问题已修复, 可以直接安装到最新版,如果您已经使用了本文的方法关闭了自动更新, 那么删掉现有 OneDrive 程序重新安装即可。下次微软再犯相同错误,可以如法炮制。

问题

某天,OneDrive 突然提示我它已经损坏了,重启也没什么反应。 我的第一反应是 mini 用的这块 ssd 大限到了, 不过后来看看其他程序和文件似乎也都正常,感觉又不太像是 ssd 的寿命问题。

如果不是 ssd 的寿命问题,之前 OneDrive 也是好好的,那么估计就是更新出问题了, 我的 OneDrive 是在 app store 安装的,打开商店看了一下,最近 OneDrive 果然有更新。

第一回合我们自然是先重装试试看能不能修复,顺带一提, OneDrive 内部有一个重置的命令,可以把 OneDrive 重置到出厂状态, 右键点击 OneDrive 应用,点击「显示包内容」:

img

接下来就可以在 Contents/Resources 下找到 ResetOneDriveApp.command:

img

双击运行就好,不过写在这里你应该可以猜到,这个和重装都没能解决问题。

解决

首先我们要安装旧版本的应用,很显然 app store 是没办法更新到指定版本的, 不过 brew 可以,只是需要一些小手段。

使用 HomeBrew 安装旧版应用

首先我们在 Homebrew Formulae 中找到 onedrive 的页面, 从这个页面我们可以找到 OneDrive 的 Cask code, 点击 history:

img

这时我们就可以看到近期的更新,我打算更新到 2 月 23 日的版本, 我们点击 #141750 右边「查看当时的代码

img

接下来 raw 按钮给出的就是 当时的 cask code 了,我们可以下载下来,使用以下命令安装:

1
brew install --cask onedrive.rb

安装好以后,千万不要立即执行 OneDrive!因为 OneDrive 自身也内嵌了更新机制, 一旦启动了 OneDrive,它就会自作聪明地自作主张, 把我们好不容易装上去的旧版更新为无法启动的最新版。

关闭自动更新

一个 OneDrive,三个更新进程,我们索性把它们全关掉:

1
2
3
launchctl remove com.microsoft.OneDriveStandaloneUpdater
sudo launchctl remove com.microsoft.OneDriveStandaloneUpdaterDaemon
sudo launchctl remove com.microsoft.OneDriveUpdaterDaemon

一不做二不休,配置文件也删了好了:

1
2
3
sudo rm /Library/LaunchAgents/com.microsoft.OneDriveStandaloneUpdater.plist
sudo rm /Library/LaunchDaemons/com.microsoft.OneDriveStandaloneUpdaterDaemon.plist
sudo rm /Library/LaunchDaemons/com.microsoft.OneDriveUpdaterDaemon.plist

这时我们再启动 OneDrive,整个世界清净了。

总结

如果你还在使用 catalina,并且也在使用 OneDrive 时,那么大概率会遇到这个问题, 其实我理解微软的做法,淘汰某个古老系统是正常的,更新也是按正常逻辑运行的, 但是两个加在一起,老系统就不正常了,这不能作为让用户承担问题的理由, 起码应该下发一个版本,停止旧版本的自动更新,再接下来向新系统下发更新。 不过我的牢骚微软应该是听不到的,如果你也有这个问题,那么请按以下步骤尝试:

  1. 重装旧版本应用,重装后不要立即启动
  2. 停用所有更新相关服务
l