• [技术干货] RPM包安装
    RPM包安装1、如何安装rpm软件包rmp软件包的安装可以使用程序rpm来完成。执行下面的命令rpm -i your-package.rpm其中your-package.rpm是你要安装的rpm包的文件名,一般置于当前目录下。安装过程中可能出现下面的警告或者提示:... conflict with ... 可能是要安装的包里有一些文件可能会覆盖现有的文件,缺省时这样的情况下是无法正确安装的可以用rpm --force -i 强制安装即可... is needed by ...... is not installed ... 此包需要的一些软件你没有安装可以用rpm --nodeps -i 来忽略此信息也就是说,rpm -i --force --nodeps 可以忽略所有依赖关系和文件问题,什么包都能安装上,但这种强制安装的软件包不能保证完全发挥功能2、如何安装.src.rpm软件包有些软件包是以.src.rpm结尾的,这类软件包是包含了源代码的rpm包,在安装时需要进行编译。这类软件包有两种安装方法,方法一:执行rpm -i your-package.src.rpmcd /usr/src/redhat/SPECSrpmbuild -bp your-package.specs 一个和你的软件包同名的specs文件cd /usr/src/redhat/BUILD/your-package/ 一个和你的软件包同名的目录./configure 这一步和编译普通的源码软件一样,可以加上参数makemake install方法二:执行rpm -i you-package.src.rpmcd /usr/src/redhat/SPECS 前两步和方法一相同rpmbuild -bb your-package.specs 一个和你的软件包同名的specs文件这时,在/usr/src/redhat/RPM/i386/ (根据具体包的不同,也可能是i686,noarch等等)目录下,有一个新的rpm包,这个是编译好的二进制文件,执行rpm -i new-package.rpm即可安装完成。3、如何卸载rpm软件包使用命令 rpm -e 包名,包名可以包含版本号等信息,但是不可以有后缀.rpm。比如,卸载软件包proftpd-1.2.8-1,可以使用下列格式:rpm -e proftpd-1.2.8-1 rpm -e proftpd-1.2.8 rpm -e proftpd- rpm -e proftpd不可以是下列格式:rpm -e proftpd-1.2.8-1.i386.rpm rpm -e proftpd-1.2.8-1.i386 rpm -e proftpd-1.2 rpm -e proftpd-1有时会出现一些错误或者警告:... is needed by ... 这说明这个软件被其他软件需要,不能随便卸载可以用rpm -e --nodeps强制卸载4、如何不安装但是获取rpm包中的文件使用工具rpm2cpio和cpiorpm2cpio xxx.rpm | cpio -vi rpm2cpio xxx.rpm | cpio -idmv rpm2cpio xxx.rpm | cpio --extract --make-directories参数i和extract相同,表示提取文件。v表示指示执行进程d和make-directory相同,表示根据包中文件原来的路径建立目录m表示保持文件的更新时间。5、如何查看与rpm包相关的文件和其他信息下面所有的例子都假设使用软件包mysql-3.23.54a-11我的系统中安装了那些rpm软件包rpm -qa 列出所有安装过的包如果要查找所有安装过的包含某个字符串sql的软件包rpm -qa |grep sql如何获得某个软件包的文件全名rpm -q mysql可以获得系统中安装的mysql软件包全名,从中可以获得当前软件包的版本等信息。这个例子中可以得到信息mysql-3.23.54a-11。一个rpm包中的文件安装到那里去了?rpm -ql 包名注意:这里的包名是不包括.rpm后缀的软件包的名称,也就是说只能用mysql或者mysql-3.23.54a-11而不是mysql-3.23.54a-11.rpm,如果只是想知道可执行程序放到那里去了,也可以用which,比如which mysql一个rpm包中包含那些文件一个没有安装过的软件包,使用:rpm -qlp ****.rpm一个已经安装过的软件包,还可以使用:rpm -ql ****.rpm如何获取关于一个软件包的版本,用途等相关信息?一个没有安装过的软件包,使用rpm -qip ****.rpm。一个已经安装过的软件包,还可以使用rpm -qi ****.rpm。某个程序是哪个软件包安装的,或者哪个软件包包含这个程序rpm -qf `which 程序名` 返回软件包的全名 rpm -qif `which 程序名` 返回软件包的有关信息 rpm -qlf `which 程序名` 返回软件包的文件列表注意,这里不是引号,而是`,就是键盘左上角的那个键,也可以使用rpm -qilf,同时输出软件包信息和文件列表。某个文件是哪个软件包安装的,或者哪个软件包包含这个文件注意,前一个问题中的方法,只适用与可执行的程序,而下面的方法,不仅可以用于可执行程序,也可以用于普通的任何文件,前提是知道这个文件名,首先获得这个程序的完整路径,可以用whereis或者which,然后使用rpm -qf例如:# whereis ftptop ftptop: /usr/bin/ftptop /usr/share/man/man1/ftptop.1.gz # rpm -qf /usr/bin/ftptop proftpd-1.2.8-1 # rpm -qf /usr/share/doc/proftpd-1.2.8/rfc/rfc0959.txt proftpd-1.2.8-1获得软件包相关的信息用rpm -q,q表示查询query,后面可以跟其他选项,比如i 表示info,获得软件包的信息; l 表示list,获得文件列表; a 表示all,在所有包中执行查询; f 表示file,根据文件进行相关的查询; p 表示package,根据软件包进行查询需要的查询条件可以使用grep产生,或者从""中的命令行产生原文链接: https://www.kancloud.cn/linux-tech/linux_learning/661736
  • [技术干货] 如何升级openssl
    在计算机网络上,OpenSSL是一个开放源代码的软件库包,应用程序可以使用这个包来进行安全通信,避免窃听,同时确认另一端连接者的身份。这个包广泛被应用在互联网的网页服务器上。SSL是Secure Sockets Layer(安全套接层协议)的缩写,可以在Internet上提供秘密性传输。Netscape公司在推出第一个Web浏览器的同时,提出了SSL协议标准。其目标是保证两个应用间通信的保密性和可靠性,可在服务器端和用户端同时实现支持。已经成为Internet上保密通讯的工业标准。 SSL能使用户/服务器应用之间的通信不被攻击者窃听,并且始终对服务器进行认证,还可选择对用户进行认证。SSL协议要求建立在可靠的传输层协议(TCP)之上。SSL协议的优势在于它是与应用层协议独立无关的,高层的应用层协议(例如:HTTP,FTP,TELNET等)能透明地建立于SSL协议之上。SSL协议在应用层协议通信之前就已经完成加密算法、通信密钥的协商及服务器认证工作。在此之后应用层协议所传送的数据都会被加密,从而保证通信的私密性。很多加密算法用到了openssl这个组件,低版本的存在很多漏洞和风险需要升级到新版本。基本功能 OpenSSL整个软件包大概可以分成三个主要的功能部分:SSL协议库、应用程序以及密码算法库。OpenSSL的目录结构自然也是围绕这三个功能部分进行规划的。 作为一个基于密码学的安全开发包,OpenSSL提供的功能相当强大和全面,囊括了主要的密码算法、常用的密钥和证书封装管理功能以及SSL协议,并提供了丰富的应用程序供测试或其它目的使用。 辅助功能 BIO机制是OpenSSL提供的一种高层IO接口,该接口封装了几乎所有类型的IO接口,如内存访问、文件访问以及Socket等。这使得代码的重用性大幅度提高,OpenSSL提供API的复杂性也降低了很多。 OpenSSL对于随机数的生成和管理也提供了一整套的解决方法和支持API函数。随机数的好坏是决定一个密钥是否安全的重要前提。 OpenSSL还提供了其它的一些辅助功能,如从口令生成密钥的API,证书签发和管理中的配置文件机制等等。如果你有足够的耐心,将会在深入使用OpenSSL的过程慢慢发现很多这样的小功能,让你不断有新的惊喜。工具/原料opensslcentos6.5_x64方法/步骤两种方法查看当前openssl版本源码编译之前要先安装zlib下载最新的源码包openssl-1.1.0c.tar.gztar zxvf openssl-1.1.0c.tar.gzcd openssl-1.1.0c./config shared zlib  --prefix=/usr/local/openssl && make && make install移除老版本的openssl,创建新的软连接mv /usr/bin/openssl /usr/bin/openssl.oldmv /usr/include/openssl /usr/include/openssl.oldln -s /usr/local/openssl/bin/openssl /usr/bin/opensslln -s /usr/local/openssl/include/openssl /usr/include/opensslln -sf /usr/local/openssl/lib/libcrypto.so.1.0.0 /lib/libcrypto.so.6echo "/usr/local/openssl/lib" >>/etc/ld.so.conf ldconfig -v6.至此openssl升级完成原文链接:https://jingyan.baidu.com/article/bea41d4386a9f2b4c51be6aa.html
  • [技术干货] Liunx系统下,内网升级OpenSSL
    1、下载相关的安装包zlib-1.2.11.tar.gzopenssl-1.0.2t.tar.gzopenssh-8.1p1.tar.gz依赖包zlib下载地址:http://www.zlib.net/依赖包openssl下载地址:https://www.openssl.org/source/最新的Openssh下载地址:https://mirrors.sonic.net/pub/OpenBSD/OpenSSH/portable/(后面执行报错需要安装此依赖)下载PAM模块地址 http://www.linux-pam.org/library/2、查看当前版本和服务状态2.1、查看openssh版本ssh -V2.2、查看openssl版本openssl version2.3、查看zlib版本find /usr/ -name zlib.pc # 找出zlib.pc的文件路径cat /path/zlib.pc # 查看里面内容,有zlib版本显示2.4、确认telnet服务正常开启(防止ssh升级失败,无法连接终端)telnet 192.168.226.1232.5、查看端口22情况netstat -ntulp |grep 222.6、sshd服务情况ps -ef | grep sshd2.7、查看sshd文件位置(后面重启时候可能会用到,需要执行该脚本文件重启sshd)locate sshd3、安装步骤在安装之前要确认当前版本,如果依赖包zlib和openssl版本是当前最新,则不需要重新安装依赖包3.1、zlib安装1、解压tar -zxvf zlib-1.2.11.tar.gz2、进入zlib解压目录cd zlib-1.2.113、执行脚本(perfix参数是指定安装路径)./configure --prefix=/usr/local/zlib4、编译make5、安装sudo make install6、进入临时root操作界面sudo -i7、共享库注册echo '/usr/local/zlib/lib' >> /etc/ld.so.conf.d/zlib.conf8、更新缓存,使新添加的lib 被系统找到ldconfig 3.2、openssl安装1、备份原先的openssl的文件sudo mv /usr/bin/openssl /usr/bin/openssl.old2、解压tar -zxvf openssl-1.0.2t.tar.gz3、进入zlib解压目录cd openssl-1.0.2t4、执行脚本./config --prefix=/usr/local/ssl --shared zlib5、编译make---------------------------执行make这步,可能会出现下面错误----------------------------------报错内容:c_zlib.c:25:19: fatal error: zlib.h: No such file or directory Makefile:287: recipe for target 'build_crypto' failed make: *** [build_crypto] Error 1解决方式:1、复制软件包到指定目录 sudo cp zlib-1.2.11 /usr/local/src/zlib-1.2.11 -r 2、构建静态库 sudo -i ./configure make test make install 3、构建共享库 make clean ./configure --shared make test make install cp zutil.h /usr/local/include cp zutil.c /usr/local/include -------------------------------------------------------------------------------------------6、测试(测试通过之后,后面执行ssh升级,可以找到ssl,否则后面ssh会安装失败)make test7、安装sudo make install8、进入临时root操作界面sudo -i9、建立软连接(由于安装时候默认安装目录为 /usr/local/ssl/)ln -s /usr/local/ssl/bin/openssl /usr/bin/opensslln -s /usr/local/ssl/include/openssl /usr/include/openssl10、将openssl 的lib 库添加到系统echo "/usr/local/ssl/lib" > /etc/ld.so.conf.d/openssl.conf11、使新添加的lib 被系统找到ldconfig3.3、Openssh安装1、备份原先的openssh的文件sudo mv /etc/init.d/ssh /etc/init.d/ssh.oldsudo mv /etc/ssh /etc/ssh.old2、解压tar -zxvf openssh-8.1p1.tar.gz3、进入openssh解压目录cd openssh-8.1p14、卸载原openssh- 如果是原ssh以apt安装的卸载方式:sudo apt-get remove openssh-server openssh-client- 如果是源码安装的:sudo make uninstall5、执行脚本./configure --prefix=/usr --sysconfdir=/etc/ssh --with-ssl-dir=/usr/local/ssl --with-zlib=/usr/local/zlib --with-md5-passwords--------------------------------执行这步之后,可能会出现下面错误---------------------------报错内容:configure: error: PAM headers not found解决方式:1、下载pam模块 2、 进入下载的目录下,依次执行下面命令 3、 ./configure 4、 make 5、 sudo make install-------------------------------------------------------------------------------------------6、编译make7、安装sudo make install8、修改默认配置文件根据之前配置修改,保证配置相同- 8.1、 vi /etc/ssh/sshd_config- 8.2、打开sshd_config文件, 复制下面一句话 (因为更新ssh,sftp-server文件文件位置也可能会更新的) ''' Subsystem sftp /usr/libexec/sftp-server '''- 8.3、sudo cp /etc/init.d/ssh.old /etc/init.d/ssh- 8.4、sudo cp /etc/ssh.old/sshd_config /etc/ssh/- 8.5、sudo vi /etc/ssh/sshd_config- 8.6、将8.2步骤复制那句话,替换上去9、重启服务systemctl restart ssh----------------------------重启服务可能会出现下面错误--------------------------------------报错内容: Failed to restart ssh.service: Unit ssh.service is masked解决方式: /usr/sbin/sshd 或 /etc/init.d/sshd--------------------------------------------------------------------------------------------4、升级后的问题4.1 ssh升级后,可能会遇到以前经常连接服务器的客户端发出服务器的密钥已经被更改,执行下面命令rm -rf ~/.ssh/known_hosts4.2 服务端会出现输不了中文,以中文命名的文件会乱码解决方式:sudo vi /etc/profile将下面几行写在最低行export LC_NAME=zh_CN.UTF-8export LC_TELEPHONE=zh_CN.UTF-8export LC_IDENTIFICATION=zh_CN.UTF-8export LC_MEASUREMENT=zh_CN.UTF-8export LANG=en_US.UTF-8export LC_TIME=zh_CN.UTF-8export LC_NAME=zh_CN.UTF-8使文件生效source /etc/profile作者:洛奇lodge链接:https://www.jianshu.com/p/d61ad1512d22
  • [技术干货] OpenSSL 最新版 快速安装 v3.0.2 v1.1.1n Windows系统
    OpenSSL是一个开放源代码的软件库包,应用程序可以使用这个包来进行安全通信,避免窃听,同时确认另一端连接者的身份。这个包广泛被应用在互联网的网页服务器上。  默认的Windows系统是不带openssl功能的,因此当需要生成密钥或证书时需要先安装openssl库。  openssl : 无法将“openssl”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次。 所在位置 行:1 字符: 1 + openssl version + ~~~~~~~     + CategoryInfo          : ObjectNotFound: (openssl:String) [], CommandNotFoundException + FullyQualifiedErrorId : CommandNotFoundException安装方法 由于openssl是开源的,因此可以直接下载源码,自己编译,但这一过程非常复杂,需要先安装perl、vs等软件,然后才能编译openssl。  /source/index.html https://www.openssl.org/source/ 另一种方式是利用其他人已经做好的便捷版安装包,直接运行即可,采用这种方式更加迅速,且不易出现问题。  步骤一 前往网站下载:Win32/Win64 OpenSSL Installer for Windows - Shining Light Productions 列表中提供了v3.0.2 v1.1.1两个版本,OpenSSL 3.0是OpenSSL的最新主要版本,服务支持直到2026年9月7日,是一个长期支持(LTS)版本。此前的LTS版本(1.1.1系列)将支持至9月11日2023年。  对于每个版本需要根据自己的电脑架构进行选择:  电脑或者要安装的版本是64位,还是32位,通常基本都是64位; 电脑架构是否是arm,取决于CPU,一般不是;  此外,表格中也提供了轻量级版本,选择Light即可。  Win64 OpenSSL v3.0.2:  http://slproweb.com/download/Win64OpenSSL-3_0_2.msi  Win64 OpenSSL v3.0.2 Light:  http://slproweb.com/download/Win64OpenSSL_Light-3_0_2.msi  下载后直接运行,点击下一步,完成安装,需要记住安装位置。  步骤二 安装完毕后需要设置环境变量才可以使用, 默认安装位置为:C:\Program Files\OpenSSL-Win64 列表中提供了v3.0.2 v1.1.1两个版本,OpenSSL 3.0是OpenSSL的最新主要版本,服务支持直到2026年9月7日,是一个长期支持(LTS)版本。此前的LTS版本(1.1.1系列)将支持至9月11日2023年。  对于每个版本需要根据自己的电脑架构进行选择:  电脑或者要安装的版本是64位,还是32位,通常基本都是64位; 电脑架构是否是arm,取决于CPU,一般不是;  此外,表格中也提供了轻量级版本,选择Light即可。  Win64 OpenSSL v3.0.2:  http://slproweb.com/download/Win64OpenSSL-3_0_2.msi  Win64 OpenSSL v3.0.2 Light:  http://slproweb.com/download/Win64OpenSSL_Light-3_0_2.msi  下载后直接运行,点击下一步,完成安装,需要记住安装位置。  步骤二 安装完毕后需要设置环境变量才可以使用, 默认安装位置为:C:\Program Files\OpenSSL-Win64 # 环境变量名 OPENSSL_HOME # 环境变量值 C:\Program Files\OpenSSL-Win64\bin然后还需要在 path 变量中添加该环境变量。添加引用  %OPENSSL_HOME%点击确定后关闭,在命令行中输入 openssl version 查看是否可用。添加引用  %OPENSSL_HOME%点击确定后关闭,在命令行中输入 openssl version 查看是否可用。原文链接:https://blog.csdn.net/Ximerr/article/details/123529838
  • [技术干货] guava的使用方法和示例代码
    Guava是Google开源的一款Java工具库,提供了许多实用的功能,如集合操作、缓存、函数式编程等。本文将介绍Guava的基本使用方法和一些示例代码。一、Guava的引入在项目的pom.xml文件中添加以下依赖:<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>30.1-jre</version> </dependency>二、Guava的功能模块集合操作Guava提供了许多高效的集合操作方法,如Sets.newHashSet()、Lists.newArrayList()等。以下是一个简单的示例:import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; import java.util.Set; public class GuavaSetExample { public static void main(String[] args) { Set<String> set = Sets.newHashSet("a", "b", "c"); System.out.println(set); // 输出:[a, b, c] } }缓存Guava提供了强大的缓存功能,可以自动缓存计算结果,提高性能。以下是一个简单的示例:import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import java.util.concurrent.TimeUnit; public class GuavaCacheExample { public static void main(String[] args) { Cache<String, String> cache = CacheBuilder.newBuilder() .maximumSize(100) // 设置最大缓存数量 .expireAfterWrite(10, TimeUnit.MINUTES) // 设置写入后10分钟过期 .build(); cache.put("key", "value"); // 存入缓存 String value = cache.getIfPresent("key"); // 从缓存中获取值,如果不存在则返回null System.out.println(value); // 输出:value } }函数式编程Guava支持函数式编程,可以将方法作为参数传递,提高代码的可读性和灵活性。以下是一个简单的示例:import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.collect.Collections2; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import java.util.*; import java.util.function.*; import java.util.stream.*; public class GuavaFunctionalProgrammingExample { public static void main(String[] args) { List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); // 使用filter筛选出偶数,然后使用map将每个数字乘以2,最后收集到一个新的列表中 List<Integer> evenNumbersDoubled = numbers.stream() .filter(Predicate.isEven()) // 筛选出偶数 .map(i -> i * 2) // 将每个数字乘以2 .collect(Collectors.toList()); // 收集到一个新的列表中 System.out.println(evenNumbersDoubled); // 输出:[4, 8] } }以下是Guava的一些常用方法:Optional:用于解决空指针异常问题,可以表示一个值存在或不存在。Lists:提供了一些高效的List操作,如去重、排序、过滤等。Sets:提供了一些高效的Set操作,如去重、交集、并集等。Maps:提供了一些高效的Map操作,如去重、合并、排序等。Predicates:提供了一些常用的函数式接口,如Predicate、Predicate等。Functions:提供了一些常用的函数式接口,如Function、Function<T, R>等。Multimaps:提供了一些高效的多值Map操作,如将一个键映射到多个值。Bimaps:提供了一些高效的双值Map操作,如将一个键映射到两个值。三、总结本文介绍了Guava的基本使用方法和一些简单的示例代码,包括集合操作、缓存和函数式编程。Guava作为一款功能强大的Java工具库,可以帮助我们简化代码,提高开发效率。
  • [技术干货] Java中CompletableFuture的场景
    Java中的CompletableFuture是一个实现了Future接口的类,它提供了一种异步编程的方式,可以让你在不阻塞主线程的情况下执行耗时操作。CompletableFuture主要用于处理异步任务的结果,支持链式调用和组合多个异步任务。作用场景:异步执行耗时操作,如文件读写、网络请求等。对多个异步任务进行组合处理,如并行执行、串行执行等。处理异步任务的结果,支持链式调用。示例代码:import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; public class CompletableFutureExample { public static void main(String[] args) { // 创建一个异步任务,模拟耗时操作 Supplier<String> supplier = () -> { try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } return "Hello, CompletableFuture!"; }; // 使用CompletableFuture.supplyAsync()方法创建异步任务 CompletableFuture<String> future = CompletableFuture.supplyAsync(supplier); // 当异步任务完成时,处理结果 future.thenAccept(result -> { System.out.println("异步任务结果:" + result); }); // 阻塞主线程,等待异步任务完成 future.join(); } }在这个示例中,我们创建了一个异步任务,模拟了耗时操作(例如文件读写、网络请求等)。然后,我们使用CompletableFuture.supplyAsync()方法创建了一个异步任务,并通过thenAccept()方法处理任务完成后的结果。最后,我们使用future.join()方法阻塞主线程,等待异步任务完成。
  • [分享交流] 如何优雅地处理Java多线程编程中的共享资源问题?
    如何优雅地处理Java多线程编程中的共享资源问题,以确保线程安全和高性能?
  • [技术干货] ReentrantReadWriteLock介绍
    ReentrantReadWriteLock是一种Java并发工具类,它提供了一种灵活的读写锁机制。与synchronized关键字不同,ReentrantReadWriteLock允许多个线程同时读取共享资源,但在写入时只允许一个线程进行操作,从而提高了并发性能。ReentrantReadWriteLock的主要特点如下:可重入性:同一个线程可以多次获取读锁或写锁,但每次只能持有一个锁。公平性:当多个线程同时请求锁时,按照等待时间的长短进行排队,而不是随机分配。读写分离:读锁和写锁是分开的,提高了并发性能。下面是一个使用ReentrantReadWriteLock的示例代码:import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; public class ReentrantReadWriteLockDemo { private ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); private int value; // 读操作 public int read() { readWriteLock.readLock().lock(); // 获取读锁 try { return value; } finally { readWriteLock.readLock().unlock(); // 释放读锁 } } // 写操作 public void write(int value) { readWriteLock.writeLock().lock(); // 获取写锁 try { this.value = value; } finally { readWriteLock.writeLock().unlock(); // 释放写锁 } } }在这个示例中,我们使用了一个ReentrantReadWriteLock对象来实现读写分离。当需要读取value时,我们获取读锁并返回当前值;当需要修改value时,我们获取写锁并更新值。这样可以确保在读取时不会发生数据不一致的问题,同时提高了并发性能。
  • [技术干货] Java:方法的重载-转载
     为什么需要方法重载 在使用方法的过程中我们可能会遇到以下如同例子的情形: public class method1 {     public static void main(String[] args) {         int a1 = 10;         int b1 = 20;         double ret1 = add(a1, b1);         System.out.println("ret1 = " + ret1);           double a2 = 10.0;         double b2 = 20.0;         int ret2 = add(a2, b2);         System.out.println("ret2 = " + ret2);     }       public static int add(int x, int y) {         return x + y;     } } ​在计算ret1时我们可以很容易得到结果,但在计算ret2时由于double转换到参数的int会有损失而报错,这里我们一般是再另外写一个方法,然后给两个方法起不同的名字: public class method2 {     public static void main(String[] args) {         int a1 = 10;         int b1 = 20;         int ret1 = addInt(a1, b1);         System.out.println("ret1 = " + ret1);           double a2 = 10.0;         double b2 = 20.0;         double ret2 = addDouble(a2, b2);         System.out.println("ret2 = " + ret2);     }       public static int addInt(int x, int y) {         return x + y;     }       public static double addDouble(double x, double y) {         return x + y;     } } 这样做我们说确实能解决问题,但不友好的地方是:我们需要提供不同的方法名,如果方法一旦变多,给方法起名字显得非常地木乱,那是否能将这里所有表示相加的方法都命名为add呢?可以,这就涉及到了java的方法重载。 方法重载的概念 在自然语言中,一个词语如果有多重含义(就类似文言文的一词多义),那么就是说该词语被重载了,具体代表什么含义需要结合具体的场景。 在Java中如果多个方法的名字相同,参数列表不同,则称该几种方法被重载了。 举个栗子:  public class method3 {     public static void main(String[] args) {         add(2,3);         add(2,3,4);         add(2.0, 3.0);     }       public static int add(int x, int y) {         return x + y;     }       public static int add(int x, int y, int z) {         return x + y + z;     }       public static double add(double x, double y) {         return x + y;     } } 注意:1.方法名必须相同            2.参数列表必须不同(参数的个数不同,参数的类型不同,参数的顺序不同)。            3.与方法的返回类型无关(仅仅因为返回类型不同是无法构成重载的)            4.无需关心怎么选择调用哪个方法,编译器在编译的时候,会对实参进行推演,根据推演的结果来确定调用哪个方法。 方法签名 在同一个作用域中不能定义两个名字相同的变量,但为什么在同一个类中,能够使用相同名字的方法呢?这就用到了方法签名。 法签名即:经过编译器修改过之后得到最终的名字。具体方式:方法路径名+参数列表+返回值类型,构成方法完整的名字。 如何查看呢?还是以上面的代码为例: public class method3 {     public static void main(String[] args) {         add(2,3);         add(2,3,4);         add(2.0, 3.0);     }     public static int add(int x, int y) {         return x + y;     }     public static int add(int x, int y, int z) {         return x + y + z;     }       public static double add(double x, double y) {         return x + y;     } } 上述代码经过编译之后,然后使用JDK自带的javap反汇编工具查看,具体操作(可用cmd窗口): 1.先对工程进行编译生成.class字节码文件。 2.在控制台中进入到要查看的.class所在的目录 3.输入javap -v 字节码文件名字即可。 ———————————————— 版权声明:本文为CSDN博主「灰灰快醒醒」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/asdssadddd/article/details/131957838 
  • [技术干货] 【JAVA】String ,StringBuffer 和 StringBuilder 三者有何联系?-转载
     前言 在之前的文章中我们介绍了JAVA中String的运用方法,事实上在JAVA字符串操作中仅仅只知道String方法是远远不够的,今天我们要介绍的StringBuffer和StringBuilder在字符串操作中同样占据总要地位。 和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象  StringBuffer StringBuffer[^1]是Java中的一个类,用于表示可以修改的字符序列。它是一个可变对象,这意味着对象的值可以在创建后更改。  StringBuffer类提供了许多处理字符串数据的方法,例如添加或删除字符、将数据插入或附加到现有字符串,以及更改缓冲区的大小。与String类不同,StringBuffer对象可以在不创建新对象或复制现有对象的情况下进行修改。 StringBuffer通常用于需要执行大量字符串操作的情况,例如从较小的字符串构建大型字符串时。它在多线程应用程序中也很有用,因为不同的线程可能同时访问同一个StringBuffer对象并修改其内容。  StringBuffer方法 public StringBuffer append(String s) //将指定的字符串追加到此字符序列。 ```java public StringBuffer reverse() //将此字符序列用其反转形式取代 public delete(int start, int end) //移除此序列的子字符串中的字符。 public insert(int offset, int i) //将 int 参数的字符串表示形式插入此序列中。 insert(int offset, String str) //将 str 参数的字符串插入此序列中。 replace(int start, int end, String str) //使用给定 String 中的字符替换此序列的子字符串中的字符。 1.StringBuffer的直接父类是AbstractStringBuilder 2.StringBuffer实现了Serializable 即StringBuffer的对象可以串行化 3.在父类中 AbstractStringBuilder 有属性 char[] value,不是final 在该value数组存放字符串内容,引出存放在堆中的 4.StringBuffer 是一个final类 不能被继承 5.StringBuffer是存放在 char[] value ,所有的变化 不用每次创建新对象,更换地址所以效率高于String   StringBuilder Java中的StringBuilder是一个类,它允许以比简单的串联更有效的方式创建和操作字符串。它提供了在字符串中附加、插入、替换和删除字符的方法。与不可变(不能更改)的String对象不同,StringBuilder对象可以在每次不创建新对象的情况下进行修改。这使得StringBuilder成为需要大量字符串操作的情况下更有效的选择。  StringBuilder方法 //追加字符串         StringBuilder sb = new StringBuilder("x");         sb.append("a"); // 在当前字符串的尾部追加字符串a // xa         sb.append("b"); // 在当前字符串的尾部追加字符串a // xab //替换字符串 StringBuilder sb = new StringBuilder("天王盖地虎");         sb.replace(1, 3, "博爱他"); // 替换下标1-3的位置不包含3         sb.replace(0, 1, ""); // 替换下标0-1的位置不包含1         System.out.println(sb); // 替换会产生新内容 //删除字符串         StringBuilder sb = new StringBuilder();         sb.append("巴山楚水凄凉地,responsebility").delete(10, 12) // 按照下标内容删除                 .deleteCharAt(0); // 删除指定位置内容         System.out.println(sb); //指定下标新内容         StringBuilder sb = new StringBuilder("abcd");         // insert():在指定下标位置,插入新内容         sb.insert(2, "123")           .insert(2, true)           .insert(2, Math.PI); //字符串逆序         // 字符串逆序         StringBuilder sb=new StringBuilder("甲乙丙丁");         sb.reverse(); // 逆序反转         System.out.println(sb); //设置分隔符         // StringJoiner joiner = new StringJoiner("#"); // 设置分隔符         StringJoiner joiner = new StringJoiner("#", "@", "@"); // 设置分隔符 String ,StringBuffer 和 StringBuilder的区别  String和StringBuffer互相转换  ———————————————— 版权声明:本文为CSDN博主「许思王」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/weixin_73602725/article/details/132069620 
  • [技术干货] 数据结构-Java逆天操作-转载
     定义 线性表是一种数据结构,它是由一系列具有相同类型的元素组成的有序集合。线性表中的元素按照线性的顺序 排列,每个元素只有一个前驱元素和一个后继元素,除了第一个元素没有前驱元素,最后一个元素没有后继 元素。 可以表示为 表中的元素序列{x1,x2,...,xn},其中xi是表中的元素,它们具有相同的数据类型,n表示表中元素的个数。 线性表满足以下特性: 元素的有序性:线性表中的元素按照线性的顺序排列,每个元素都有一个确定的位置。 有限性:线性表中的元素个数是有限的。 相同数据类型:线性表中的元素具有相同的数据类型,即它们具有相同的属性和操作。 线性表可以用多种方式来表示和实现,常见的实现方式包括顺序表和链表两种。 顺序表 是一种基于数组的实现方式,元素在内存中连续存储,通过下标访问元素,插入和删除操作需要移动其他元素。 链表 是一种通过节点之间的指针来连接的实现方式,节点包含元素和指向下一个节点的指针,可以实现高效的插入 和删除操作,但访问元素的效率相对较低。 注意 线性表作为数据结构中的基本概念,广泛应用于各个领域的算法和程序设计中。掌握线性表的定义和实现方式, 能够帮助我们更好地理解和应用其他数据结构和算法。  线性表是一种常见的数据结构,它由一系列元素组成,这些元素之间存在着一对一的前后关系。线性表中的元 素可以是任何类型的数据,如整数、字符或对象等。  线性表中的元素排列有序,每个元素都有一个直接前驱元素和一个直接后继元素,除了第一个元素没有前驱元 素,最后一个元素没有后继元素。  线性表的访问方式可以根据元素在表中的位置进行操作,如按索引访问、插入、删除等。其中,按索引访问是 通过元素在表中的位置(索引)来获取对应的元素值。插入和删除可以在指定的位置上插入新的元素或者移除 现有的元素。  线性表有很多种实现方式,常见的包括数组和链表。数组作为一种静态数据结构,需要提前声明一个固定大小 的空间来存储元素,操作灵活性较差。链表则以节点的形式存储元素,每个节点包含了数据及指向下一个节点 的指针,操作相对灵活,但涉及到频繁的内存分配和释放。  线性表常用的算法包括遍历、查找和排序等。遍历操作用于依次访问线性表中的所有元素。查找操作可以根据 某个条件查找满足要求的元素,常见的方法有线性查找和二分查找。排序操作可以将线性表中的元素按照一定 的规则进行排列,常见的排序算法有冒泡排序、插入排序和快速排序等。  总之,线性表是一种简单、常用的数据结构,能够有效地组织和处理大量的数据,广泛应用于各个领域的算法 与程序设计中。 代码实现 在Java中,我们可以使用数组或链表来实现线性表。 使用数组实现线性表: public class ArrayList {     private int size;     private Object[] array;      public ArrayList() {         this.size = 0;         this.array = new Object[10]; // 初始化数组大小为10     }      public void add(Object item) {         if (size == array.length) {             Object[] newArray = new Object[array.length * 2]; // 当数组容量不足时,扩大数组             System.arraycopy(array, 0, newArray, 0, size); // 将原数组中的元素复制到新数组             array = newArray;         }         array[size++] = item;     }      public Object get(int index) {         if (index >= 0 && index < size) {             return array[index];         } else {             throw new IndexOutOfBoundsException();         }     }      public int size() {         return size;     } } 在Java语言中,我们可以使用数组来实现线性表的增删改查操作线性表的例子:  public class MyArrayList {     private Object[] array;     private int size;     private int capacity;      public MyArrayList() {         capacity = 10; // 初始化容量为10         array = new Object[capacity];         size = 0;     }      public int getSize() {         return size;     }      public boolean isEmpty() {         return size == 0;     }      public void add(Object element) {         if (size == capacity) {             increaseCapacity(); // 扩容         }         array[size] = element;         size++;     }      public void remove(int index) {         if (index < 0 || index >= size) {             throw new IndexOutOfBoundsException("Index out of range");         }         for (int i = index; i < size - 1; i++) {             array[i] = array[i + 1];         }         array[size - 1] = null;         size--;     }      public void set(int index, Object element) {         if (index < 0 || index >= size) {             throw new IndexOutOfBoundsException("Index out of range");         }         array[index] = element;     }      public Object get(int index) {         if (index < 0 || index >= size) {             throw new IndexOutOfBoundsException("Index out of range");         }         return array[index];     }      public boolean contains(Object element) {         for (int i = 0; i < size; i++) {             if (array[i].equals(element)) {                 return true;             }         }         return false;     }      private void increaseCapacity() {         capacity *= 2; // 扩大两倍         Object[] newArray = new Object[capacity];         for (int i = 0; i < size; i++) {             newArray[i] = array[i];         }         array = newArray;     } } 使用示例:  public class Main {     public static void main(String[] args) {         MyArrayList list = new MyArrayList();         list.add("A");         list.add("B");         list.add("C");          System.out.println("Size: " + list.getSize()); // 输出:Size: 3          list.remove(1); // 删除索引为1的元素         System.out.println("Size: " + list.getSize()); // 输出:Size: 2          list.set(0, "D"); // 将索引为0的元素设置为"D"         System.out.println(list.get(0)); // 输出:D          System.out.println(list.contains("C")); // 输出:false     } } 使用链表实现线性表: public class LinkedList {     private Node head;     private int size;      private class Node { // 链表节点类         Object data;         Node next;          public Node(Object data) {             this.data = data;             this.next = null;         }     }      public LinkedList() {         this.head = null;         this.size = 0;     }      public void add(Object item) {         Node newNode = new Node(item);         if (head == null) {             head = newNode;         } else {             Node current = head;             while (current.next != null) {                 current = current.next;             }             current.next = newNode;         }         size++;     }      public Object get(int index) {         if (index >= 0 && index < size) {             Node current = head;             for (int i = 0; i < index; i++) {                 current = current.next;             }             return current.data;         } else {             throw new IndexOutOfBoundsException();         }     }      public int size() {         return size;     } } 在Java语言中,我们用链表来实现线性表的增删改查操作线性表的例子: 代码演示了使用链表实现线性表的增加、删除、修改和查询操作,并使用 MyLinkedList类来实现这些功能。你可以根据需要进一步扩展和优化这个实现。 public class ListNode {     Object data;     ListNode next;      public ListNode(Object data) {         this.data = data;         this.next = null;     } }  public class MyLinkedList {     private ListNode head;     private int size;      public MyLinkedList() {         head = null;         size = 0;     }      public int getSize() {         return size;     }      public boolean isEmpty() {         return size == 0;     }      public void add(Object element) {         ListNode newNode = new ListNode(element);         if (head == null) {             head = newNode;         } else {             ListNode current = head;             while (current.next != null) {                 current = current.next;             }             current.next = newNode;         }         size++;     }      public void remove(int index) {         if (index < 0 || index >= size) {             throw new IndexOutOfBoundsException("Index out of range");         }         if (index == 0) {             head = head.next;         } else {             ListNode previous = getNode(index - 1);             ListNode current = previous.next;             previous.next = current.next;         }         size--;     }      public void set(int index, Object element) {         if (index < 0 || index >= size) {             throw new IndexOutOfBoundsException("Index out of range");         }         ListNode node = getNode(index);         node.data = element;     }      public Object get(int index) {         if (index < 0 || index >= size) {             throw new IndexOutOfBoundsException("Index out of range");         }         ListNode node = getNode(index);         return node.data;     }      public boolean contains(Object element) {         ListNode current = head;         while (current != null) {             if (current.data.equals(element)) {                 return true;             }             current = current.next;         }         return false;     }      private ListNode getNode(int index) {         ListNode current = head;         for (int i = 0; i < index; i++) {             current = current.next;         }         return current;     } } 使用示例:  public static void main(String[] args) {     MyLinkedList list = new MyLinkedList();     list.add("A");     list.add("B");     list.add("C");      System.out.println("Size: " + list.getSize()); // 输出:Size: 3      list.remove(1); // 删除索引为1的元素     System.out.println("Size: " + list.getSize()); // 输出:Size: 2      list.set(0, "D"); // 将索引为0的元素设置为"D"     System.out.println(list.get(0)); // 输出:D      System.out.println(list.contains("C")); // 输出:false } ———————————————— 版权声明:本文为CSDN博主「学编程的小程」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/weixin_74888502/article/details/131758653 
  • [技术干货] BIO、NIO、IO多路复用模型详细介绍&Java NIO 网络编程-转载
    前言 上文介绍了网络编程的基础知识,并基于 Java 编写了 BIO 的网络编程。我们知道 BIO 模型是存在巨大问题的,比如 C10K 问题,其本质就是因其阻塞原因,导致如果想要承受更多的请求就必须有足够多的线程,但是足够多的线程会带来内存占用问题、CPU上下文切换带来的性能问题,从而造成服务端崩溃的现象。怎么解决这一问题呢?优化呗,所以后面就有了NIO、AIO、IO多路复用。本文将对这几个模型详细说明并基于 Java 编写 NIO。  基本概念 I/O阻塞是哪里阻塞、怎么阻塞?先简单了解一些基本概念  用户空间:被分配给用户进程的虚拟地址空间,用来存储用户进程的代码、数据和堆栈等。 内核空间:操作系统的基础,负责管理计算机的硬件资源和提供系统调用接口,同时也是用户空间和硬件之间的桥梁。  为了保证操作系统的安全性和稳定性,用户进程和操作系统内核是隔离的,用户进程不能直接访问内核空间,而是需要通过系统调用等方式向内核发起请求,由内核代表用户进程执行操作。  也就是说我们的应用程序在向硬件设备,比如网卡、磁盘等读取或写入数据时需要经过内核。下面对BIO、NIO、IO多路复用模型逐一介绍,详细了解各模型IO过程。  BIO过程 首先明确一下,我们所说的IO阻塞是用户进程也就是用户空间中的程序在向硬件设备读取的这个过程,在还没有数据时给用户的反映是需要一直等待的,这个我们叫阻塞IO。过程如下图:  我们可以看到,在进程向内核发起调用后直到数据返回,整个过程都是阻塞的,结合Java BIO 编程,也就是说在 inputStream.read() 这个过程是阻塞的,就存在几个问题:  由于阻塞会占用当前线程,使之不能进行其他操作,当有新的请求时只能新建线程。在 Linux 系统中,每个线程的默认栈大小为 8MB,在不考虑其他因素的情况下,一个 8G 的服务器最多也就承载1000个请求量。 由于线程数会随着请求量增大而增大,当有大量的线程阻塞唤醒,CPU 频繁的切换上下文会导致性能的下降。 这个问题也就是C10K问题的本质,看上去很直观,使用少的线程就处理多个IO是不是就可以解决呢?继续看NIO过程。  NIO过程 NIO我们说的是非阻塞,通过对BIO的说明,NIO的非阻塞体现在:无论有无数据都直接响应给用户进程,如下图:   我们可以看到,确实是在用户进程调用recvfrom()函数后直接响应,但是在没有拿到数据之前一直在轮询调用,虽然没有因为阻塞造成CPU上下文的切换,但是CPU一直处于空转状态,不能充分发挥CPU的作用。与BIO一样,在单线程的情况下,只能依次处理IO事件,单个线程依然处理不了多个IO事件。  IO多路复用过程 既然NIO与BIO一样并不能解决因阻塞可能会造成的C10K问题,那如何让一个线程可以处理多个IO事件呢?可不可以这样:用一个线程专门监听这些IO,一旦哪个IO有数据了再去接收数据。IO多路复用就是这个原理,如下图:   我们可以看到,多了一个select()函数调用,select()会去监听指定的FD(这里注意一下,在Linux中,一切皆文件,包括socket),内核去监听FD对应的sockets。任意一个或多个socket有数据了就返回给select(),这个时候再去调用recvfrom()接收sockets的数据,从而实现了单个线程处理多个I/O操作,提高系统的效率和性能。  在Linux下,常用的I/O多路复用方式有三种:select、poll和epoll。  select和poll的原理是基于轮询,即不断地查询所有注册的I/O事件,如果有事件发生就立即通知应用程序。这种方式的效率较低,因为每次查询都需要遍历所有的I/O事件。  epoll的原理是基于事件通知,即只有当I/O事件发生时,才会通知应用程序。这种方式的效率更高,因为它避免了无效的查询。  Java NIO编程 相比Java BIO编程,Java NIO编程理解起来没有那么直观,不过在理解多个IO模型(尤其是IO多路复用)后就相对容易理解了,Java NIO实际上就是IO多路复用。  Java NIO 核心概念 在Java NIO编程中,有几个核心的概念(组件)需要了解:  通道(Channel):通道是对原始I/O操作的抽象,可以用于读取和写入数据。它可以与文件、套接字等进行交互。  缓冲区(Buffer):缓冲区是一个容器,用于存储数据。在进行读写操作时,数据会先被读取到缓冲区中,然后从缓冲区中写入或读取。  选择器(Selector):选择器是Java NIO提供的一种多路复用机制,可以通过一个线程管理多个通道的I/O操作。  相对于BIO,开发者不直接与Socket交互,而是通过Selector与多个Channel交互,同时Buffer提供了方法来管理缓冲区的容量、位置和限制,通过设置这些属性,可以控制数据的读写位置和范围。总之NIO在提升IO处理效率和性能的同时支持更丰富的功能,  Java NIO 示例 以下是一个简单的Java NIO网络编程示例,用于创建一个基于NIO的服务器和客户端:  服务端代码:  import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.Iterator;  public class NIOServer {      private Selector selector;      public static void main(String[] args) throws IOException {         NIOServer server = new NIOServer();         server.startServer();     }      public void startServer() throws IOException {         // 创建Selector         selector = Selector.open();          // 创建ServerSocketChannel,并绑定端口         ServerSocketChannel serverChannel = ServerSocketChannel.open();         serverChannel.configureBlocking(false);         serverChannel.socket().bind(new InetSocketAddress(8888));          // 将ServerSocketChannel注册到Selector上,并监听连接事件。当接收到一个客户端连接请求时就绪。该操作只给服务器使用。         serverChannel.register(selector, SelectionKey.OP_ACCEPT);          System.out.println("Server started on port 8888");          // 循环等待事件发生         while (true) {             // 等待事件触发,阻塞 | selectNow():非阻塞,立刻返回。             selector.select();              Iterator<SelectionKey> keys = selector.selectedKeys().iterator();             while (keys.hasNext()) {                 SelectionKey key = keys.next();                 // 移除当前处理的SelectionKey                 keys.remove();                  if (key.isAcceptable()) {                     // 处理连接请求                     handleAccept(key);                 }                  if (key.isReadable()) {                     // 处理读数据请求                     handleRead(key);                 }             }         }     }      private void handleAccept(SelectionKey key) throws IOException {         ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();         // 监听到ServerSocketChannel连接事件,获取到连接的客户端         SocketChannel clientChannel = serverChannel.accept();         clientChannel.configureBlocking(false);         // 将clientChannel注册到Selector上,并监听读事件,当操作系统读缓冲区有数据可读时就绪(该客户端的)。         clientChannel.register(selector, SelectionKey.OP_READ);          System.out.println("Client connected: " + clientChannel.getRemoteAddress());     }      private void handleRead(SelectionKey key) throws IOException {         SocketChannel clientChannel = (SocketChannel) key.channel();         ByteBuffer buffer = ByteBuffer.allocate(1024);         int bytesRead = clientChannel.read(buffer);          if (bytesRead == -1) {             // 客户端断开连接             key.cancel();             clientChannel.close();             System.out.println("Client disconnected ");             return;         }          byte[] data = new byte[bytesRead];         buffer.flip();         buffer.get(data);          String message = new String(data).trim();         System.out.println("Received message from client: " + message);          // 回复客户端         String response = "Server response: " + message;         ByteBuffer responseBuffer = ByteBuffer.wrap(response.getBytes());         clientChannel.write(responseBuffer);     } } 客户端代码:  import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.SocketChannel; import java.util.Iterator; import java.util.Scanner;  public class NIOClient {     private Selector selector;     private SocketChannel socketChannel;      public static void main(String[] args) {         NIOClient client = new NIOClient();         new Thread(() -> client.doConnect("localhost", 8888)).start();         Scanner scanner = new Scanner(System.in);         while (true) {             String message = scanner.nextLine();             if ("bye".equals(message)) {                 // 如果发送的消息是"bye",则关闭连接并退出循环                 client.doDisConnect();                 break;             }             client.sendMsg(message);         }      }      private void doDisConnect() {         try {             socketChannel.close();         } catch (IOException e) {             e.printStackTrace();         }     }      private void sendMsg(String message) {         // 发送消息到服务器         ByteBuffer buffer = ByteBuffer.wrap(message.getBytes());         try {             socketChannel.write(buffer);          } catch (IOException e) {             e.printStackTrace();         }     }      private void doConnect(String host, int port) {         try {             selector = Selector.open();             // 创建SocketChannel并连接服务器             socketChannel = SocketChannel.open();             socketChannel.configureBlocking(false);             socketChannel.connect(new InetSocketAddress(host, port));             // 等待连接完成             while (!socketChannel.finishConnect()) {                 // 连接未完成,可以做一些其他的事情             }             socketChannel.register(selector, SelectionKey.OP_READ);             System.out.println("连接成功!");             while (true) {                 // 等待事件触发,阻塞 | selectNow():非阻塞,立刻返回。                 selector.select();                  Iterator<SelectionKey> keys = selector.selectedKeys().iterator();                 while (keys.hasNext()) {                     SelectionKey key = keys.next();                     // 移除当前处理的SelectionKey                     keys.remove();                     if (key.isReadable()) {                         // 处理读数据请求                         handleRead(key);                     }                 }             }         } catch (IOException e) {             System.out.println("连接失败!!!");             e.printStackTrace();         }     }      private void handleRead(SelectionKey key) throws IOException {         SocketChannel clientChannel = (SocketChannel) key.channel();         ByteBuffer buffer = ByteBuffer.allocate(1024);         int bytesRead = clientChannel.read(buffer);          if (bytesRead == -1) {             // 释放资源             key.cancel();             clientChannel.close();             return;         }          byte[] data = new byte[bytesRead];         buffer.flip();         buffer.get(data);          String message = new String(data).trim();         System.out.println("Received message from server: " + message);     }  } 总结 通过本文介绍,我们可以了解各个IO模型原理,并且对很多概念有了更清晰的认识,比如: 阻塞体现在:用户进程发起系统调用接口后,不论有无数据,是否直接响应结果?如果直接响应就是非阻塞,等待就是阻塞; IO多路复用原理就是单个线程处理多个I/O操作,从而提高系统的效率和性能; 并且通过对IO多路复用的理解快速的入门了Java NIO 编程。 ———————————————— 版权声明:本文为CSDN博主「叫我二蛋」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/qq_28314431/article/details/132047951 
  • [专题汇总] 技术干货30篇,一次看过瘾。速进。
     大家好7月给大家带来codeArts板块的技术干货30篇合集,免去爬楼烦恼,希望可以帮到大家。  1.Nginx反向代理后,web服务器获取真实访问IP的方法【转】 https://bbs.huaweicloud.com/forum/thread-0212126166776222008-1-1.html  2.Eclipse中maven项目报错: org.springframework.web.filter.CharacterEncodingFilter https://bbs.huaweicloud.com/forum/thread-0212126166611645007-1-1.html  3.如何将公司外网数据库部署到客户内网服务器中,以MySQL为例【转】     https://bbs.huaweicloud.com/forum/thread-0218126166402927009-1-1.html  4.Mysql分组查询每组最新的一条数据(三种实现方法)【转】 https://bbs.huaweicloud.com/forum/thread-0212126166137614006-1-1.html  5.服务端回调报错。Cookie 的 domain 传入非法字符 【转】 https://bbs.huaweicloud.com/forum/thread-0284126165918635010-1-1.html  6.Java获取HttpServletRequest request中所有参数的方法【转】 https://bbs.huaweicloud.com/forum/thread-0249126165722109058-1-1.html  7.Java下载文件的几种方式【转】 https://bbs.huaweicloud.com/forum/thread-0284126165496966009-1-1.html  8.Python工程实践之np.loadtxt()读取数据 https://bbs.huaweicloud.com/forum/thread-0284126154810611008-1-1.html  9.python中的extend功能及用法【转】 https://bbs.huaweicloud.com/forum/thread-0218126154771208007-1-1.html  10.Python isalnum()函数的具体使用【转】 https://bbs.huaweicloud.com/forum/thread-0227126154735209007-1-1.html  11.Python endswith()函数的具体使用【转】 https://bbs.huaweicloud.com/forum/thread-0283126154645130002-1-1.html  12.Python Requests使用Cookie的几种方式详解【转】 https://bbs.huaweicloud.com/forum/thread-0205126154329369004-1-1.html  13.Python大批量写入数据(百万级别)的方法【转】 https://bbs.huaweicloud.com/forum/thread-0227126154192353006-1-1.html  14.python自动化神器pyautogui使用步骤【转】 https://bbs.huaweicloud.com/forum/thread-0249126153906646056-1-1.html  15.Python 获取图片GPS等信息锁定图片拍摄地点、拍摄时间(实例代码)【转】 https://bbs.huaweicloud.com/forum/thread-0212126153709428005-1-1.html  16.python绘制ROC曲线的示例代码【转】 https://bbs.huaweicloud.com/forum/thread-0284126153513019006-1-1.html  17.Python中map函数的技巧分享【转】 https://bbs.huaweicloud.com/forum/thread-0227126153401950004-1-1.html  18.Python列表pop()函数使用实例详解【转】 https://bbs.huaweicloud.com/forum/thread-0222126153273615007-1-1.html  19.使用Pandas计算系统客户名称的相似度【转】 https://bbs.huaweicloud.com/forum/thread-0283126152370390001-1-1.html  20.Python字典get()函数使用详解【转】 https://bbs.huaweicloud.com/forum/thread-0212126152189966004-1-1.html  21.Python集合add()函数使用详解【转】 https://bbs.huaweicloud.com/forum/thread-0218126152083399006-1-1.html  22.python中Scikit-learn库的高级特性和实践分享【转】 https://bbs.huaweicloud.com/forum/thread-0218126152004011005-1-1.html  23.MapUtils工具类【转】 https://bbs.huaweicloud.com/forum/thread-0222125918123973044-1-1.html  24.HTTP响应的状态码415解决【转】 https://bbs.huaweicloud.com/forum/thread-0283125917982618029-1-1.html  25.js保留两位小数方法总结【转】 https://bbs.huaweicloud.com/forum/thread-0222125917923319043-1-1.html  26.聊聊springboot项目引用第三平台私有jar踩到的坑【转】 https://bbs.huaweicloud.com/forum/thread-0284125917178124048-1-1.html  27.如何利用mysql5.7提供的虚拟列来提高查询效率【转】 https://bbs.huaweicloud.com/forum/thread-0284125916421713047-1-1.html  28.怎样修改检查约束条件 https://bbs.huaweicloud.com/forum/thread-0284125913342309042-1-1.html  29.【MySQL新手入门系列五】:MySQL的高级特性简介及MySQL的安全简介-转载 https://bbs.huaweicloud.com/forum/thread-0284125377030598012-1-1.html  30.【SQL应知应会】行列转换(二)• MySQL版-转载 https://bbs.huaweicloud.com/forum/thread-0249125376948578009-1-1.html 
  • [技术干货] 服务端回调报错。Cookie 的 domain 传入非法字符 【转】
    1、报错信息java.lang.IllegalArgumentException: An invalid domain [.javaex.cn] was specified for this cookie at org.apache.tomcat.util.http.Rfc6265CookieProcessor.validateDomain(Rfc6265CookieProcessor.java:203) at org.apache.tomcat.util.http.Rfc6265CookieProcessor.generateHeader(Rfc6265CookieProcessor.java:145) at org.apache.catalina.connector.Response.generateCookieString(Response.java:1019) at org.apache.catalina.connector.Response.addCookie(Response.java:967) at org.apache.catalina.connector.ResponseFacade.addCookie(ResponseFacade.java:386) at com.pactera.sso.client.utils.CookiesUtil.set(CookiesUtil.java:348) at com.pactera.sso.client.utils.CookiesUtil.setFilterCookies(CookiesUtil.java:299)2、报错原因tomcat 升级到 8.5 版本 使用了 Rfc6265CookieProcessor 就出现了 cookie domain 3、解决方案:重写 context.setCookieProcessor(new LegacyCookieProcessor());3.1、springboot 1.x@Configurationpublic class WebServletContextConfig { @Bean public EmbeddedServletContainerCustomizer cookieProcessorCustomizer() { return new EmbeddedServletContainerCustomizer() { @Override public void customize(ConfigurableEmbeddedServletContainer container) { if (container instanceof TomcatEmbeddedServletContainerFactory) { ((TomcatEmbeddedServletContainerFactory) container) .addContextCustomizers(new TomcatContextCustomizer() { @Override public void customize(Context context) { context.setCookieProcessor(new LegacyCookieProcessor()); } }); } } }; } }3.2、springboot 2.x@Configurationpublic class WebServletContextConfig { @Bean public WebServerFactoryCustomizer cookieProcessorCustomizer() { return new WebServerFactoryCustomizer() { @Override public void customize(WebServerFactory container) { if (container instanceof TomcatServletWebServerFactory) { ((TomcatServletWebServerFactory) container) .addContextCustomizers(new TomcatContextCustomizer() { @Override public void customize(Context context) { context.setCookieProcessor(new LegacyCookieProcessor()); } }); } } }; }}转载自https://blog.javaex.cn/article/detail/3856
  • [技术干货] Java获取HttpServletRequest request中所有参数的方法【转】
    获取request中单个参数String value = request.getParameter(name);获取request中所有的参数方法1Enumeration<String> param = request.getParameterNames();while (param.hasMoreElements()) { String key = param.nextElement(); String value = request.getParameter(key); System.out.println(key + ":" + value);}方法2Map map = request.getParameterMap();Set keSet = map.entrySet();for (Iterator iterator = keSet.iterator(); iterator.hasNext();) { Map.Entry me = (Map.Entry) iterator.next(); Object ok = me.getKey(); Object ov = me.getValue(); String[] value = new String[1]; if (ov instanceof String[]) { value = (String[]) ov; } else { value[0] = ov.toString(); } for (int k=0; k<value.length; k++) { System.out.println(ok + "=" + value[k]); }}转载自https://blog.javaex.cn/article/detail/3866
总条数:2301 到第 页
上滑加载中