你好,看完你的博客文章,感觉很不错!希望与你网站首页友情链接 流量卡知识网 http://53go.cn/ 专注于移动/联通/电信推出的大流量多语音活动长短期套餐手机卡的相关知识的介绍普及听说互换友情链接可以增加网站的收录量,特此来换,如果同意的话就给internetyewu@163.com[微信ganenboy]发信息或者就在此回复下吧!【建站问题也可以一起讨论!】
你好,看完你的博客文章,感觉很不错!希望与你网站首页友情链接 流量卡知识网 http://53go.cn/ 专注于移动/联通/电信推出的大流量多语音活动长短期套餐手机卡的相关知识的介绍普及听说互换友情链接可以增加网站的收录量,特此来换,如果同意的话就给internetyewu@163.com[微信ganenboy]发信息或者就在此回复下吧!【建站问题也可以一起讨论!】
你好
http://bigota.d.miui.com/V14.0.9.0.TLJCNXM/ingres_images_V14.0.9.0.TLJCNXM_20230323.0000.00_13.0_cn_chinatelecom_aff802bb3e.tgz
已添加贵站友链 Southerly 个人博客 || http://www.southerly.top || https://www.southerly.top/imgs/favicon.ico || 一个正在努力搬砖的兼职程序员,记录生活,分享生活,欢迎大家来访。
目前这种不行了
老哥呀,现在这种方法还能爬到数据嘛?可以聊聊不
https://www.aliyundrive.com/s/5N2bKDVZfxC
https://wwi.lanzoup.com/iU6FZ0o4as1i
04824ADB9F824ADB9F0400824ADB9F000F
https://lihh.lanzouf.com/ij6c80nhq7rg
https://cloud.189.cn/web/share?code=FvuIbuJBnEVr
https://lihh.lanzouf.com/ij6c80nhq7rg
https://developer.aliyun.com/plan/student?taskCode=vmfeitian2023&recordId=5246709&undefined&share_source=copy_link
已加,三天之后检查没加本站链接 就下了
首页
大佬聚集地
欢迎大家
教程分享
每日一看
Search
1
欢迎来到河马博客
41,755 阅读
2
守护者群管小栗子框架下载教程
40,885 阅读
3
烟花模拟器(php)
35,661 阅读
4
外链搜索引擎优化如何发布
13,617 阅读
5
一键搭建表白墙源码+教程
13,255 阅读
软件分享
教程分享
源码分享
游戏攻略
百科知识
SEO课程
登录
Search
标签搜索
推特
升学考试
账号
数学
饺子
笔记本电脑
笔记本
研究生考试
字符
英语
函数
马斯克
笔记本电脑排名前十
操作
初一
联想
考研
广告
注册
账户
河马
累计撰写
7,218
篇文章
累计收到
81
条评论
今日撰写
50
篇文章
首页
栏目
软件分享
教程分享
源码分享
游戏攻略
百科知识
SEO课程
页面
大佬聚集地
欢迎大家
教程分享
每日一看
用户登录
登录
搜索到
777
篇与
的结果
2023-12-03
越早知道越好(java创建websocket服务)java socketserver,JAVA socket服务器搭建,java soap 服务器,
(内网外网兼可行)注意事项:关闭防火墙,各种安全软件通通关掉,测试通过了在逐项重新开启,开启的时候记得跟随测试,遇到不能开启的就直接让他滚蛋吧。最好先用局域网测试,wifi就可以了。socket通信地址为 IP地址+端口号(202.202.43.125:5264)。端口号的范围1024---65536。本机开启WiFi,且用本机作为服务器,客服端连入wifi测试外网的时候可能会出现connection reset错误。服务器(MyEclipse):import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.PrintWriter;import java.net.ServerSocket;import java.net.Socket;import java.io.OutputStream;import com.ansj.vec.Word2VEC;public class server {// 能收能发 staticString sendString= "你好好";publicstatic void main(String[] args) throws IOException { while(true) { TestServer(); } } publicstatic void TestServer() throwsIOException {// 1.创建一个服务器端Socket,即ServerSocket,指定绑定的端口,并监听 ServerSocketserverSocket = new ServerSocket(65432); // 2.调用accept()方法开始监听,等待客服端的连接//System.out.println("***服务器即将启动,等待客服端连接***"); Socketsocket = serverSocket.accept(); // 3.获取输入流,并读取客服端信息 InputStreamis = socket.getInputStream();//字节输入流InputStreamReaderisr = new InputStreamReader(is);//将字节流转换为字符流 BufferedReaderbr = new BufferedReader(isr);//为输入流添加缓冲 Stringinfo = null;while((info=br.readLine())!=null) {//循环读取客服端的信息 System.out.println("\r"+info); } socket.shutdownInput();//关闭输入流 // 4.响应客服端 即给客服端发送信息OutputStreamos = socket.getOutputStream();//字节输出流 PrintWriterpw = new PrintWriter(os);//将输出流包装为打印流 pw.write(sendString);//写入客户端的信息+只能是纯数字字符串pw.flush();//调用flush()方法将缓冲输出 // 5.关闭资源 pw.close(); os.close(); br.close(); isr.close(); is.close(); socket.close(); serverSocket.close(); }}客服端(MyEclipse):import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;import java.io.PrintWriter;import java.net.Socket;import java.net.UnknownHostException;public class Client {publicstatic void main(String[] args) throws UnknownHostException, IOException { TestClient(); } publicstatic void TestClient() { try{ // 1. 创建客服端Socket,指定服务器地址和端口//Socket socket = newSocket("192.168.253.1", 65432);//本地IP Socket socket = newSocket("139.224.3.160", 65432);//本地IP System.out.println("客户端启动...");// 2. 获取输出流,向服务器端发送信息 OutputStreamos = socket.getOutputStream();//字节输出流 PrintWriterpw = new PrintWriter(os);//将输出流包装为打印流 pw.write("天王盖地虎,宝塔镇河妖");pw.flush(); socket.shutdownOutput();//关闭输出流 // 3. 获取输入流,接收服务器的信息 InputStreamis = socket.getInputStream();//字节输入流BufferedReaderbr = new BufferedReader(new InputStreamReader(is));//将字节流转换为字符流 为输入流添加缓冲 Stringinfo = null; while((info=br.readLine())!=null) {//循环读取客服端的信息System.out.println("我是客户端,服务器说: "+info); } // 4. 关闭相关资源 br.close(); is.close(); pw.close(); os.close(); socket.close(); }catch (UnknownHostException e) {//TODO Auto-generated catch block e.printStackTrace(); }catch (IOException e) { //TODO Auto-generated catch blocke.printStackTrace(); } }}客户端(Android):Android客户端和myeclipse客户端的主要区别是需要把网络放入run方法中运行,其次UI的更新要跳出线程(Thread),地方大幅度//==============/** Socket 客户端*/class MyThread extends Thread {@Overridepublic void run() {//定义消息Message msg = new Message();msg.what = 0x11;Bundle bundle = new Bundle();bundle.clear();try {//0. 获取输入的IP EditTextedit_ip = (EditText) IatDemo.this.findViewById(R.id.net_IP_01);String ip =edit_ip.getText().toString().trim();//1. 创建客服端Socket,指定服务器地址和端口Socket socket = new Socket(ip, 65432);//阿里云服务器 IP okSystem.out.println("localhost");//2. 获取输出流,并向服务器端发送信息OutputStreamos = socket.getOutputStream();//字节输出流PrintWriter pw = new PrintWriter(os);//将输出流包装为打印流int name= 3;pw.write(geted1);// 此地为 geted1 为发送到服务器的消息 pw.flush();socket.shutdownOutput();//关闭输出流//3. 获取输入流,接收服务器的信息 InputStreamis = socket.getInputStream();//字节输入流BufferedReader br = new BufferedReader(newInputStreamReader(is));//将字节流转换为字符流为输入流添加缓冲String info = null;/** 接收服务器返回的标签 */while ((info=br.readLine())!=null){//循环读取客服端的信息System.out.println("我是客户端,服务器说: "+info);String text0 = info;Display = info;/** 读出操作*/mTts.startSpeaking(text0,null);}/** 不可 在此处修改UI 因为其为县城*//**所以跳出三界外去更新UI即可 */ IatDemo.this.runOnUiThread(updateThread);//4. 关闭相关资源 br.close();is.close();pw.close();os.close();socket.close();} catch (UnknownHostException e) {System.err.println("错了 001");e.printStackTrace();} catch (IOException e) {System.err.println("错了 002");e.printStackTrace();}}// run()到此结束}//========== 线程外更新UI=======Runnable updateThread = new Runnable(){@Overridepublic void run(){//更新UIif (Display!= null) {mCommandText.append(Display);} else {mCommandText.append("尚未学习");}}};
2023年12月03日
0 阅读
0 评论
0 点赞
2023-12-03
一看就会(简述mvc设计模式的工作流程?)mvc设计模式分为哪三层,Java Web开发之MVC设计模式简介,java mvc外文翻译,
设计模式是一套被反复使用、成功的代码设计经验的总结。模式必须是典型问题(不是个别问题)的解决方案。在程序设计中,把采用模型(Model)、视图(View)、视图(Controller)的设计方式称为MVC设计模式。一、首先,给大家简述一下MVC设计模式的组成:(1) M(Model) 模型:处理业务逻辑,对应组件是JavaBean(Java类);(2) V(View)视图层:显示查询结果、收集用户数据,对应组件是jsp或html文件;(3) C(Controller)控制器层:接收 view 请求并将请求转交给对应的 Model 并向客户端作出相应,对应组件是Servlet;(4) 作用:实现了代码的分离,降低耦合度。模型可以分为业务逻辑和数据模型,它们代表应用程序的业务逻辑和状态。视图提供了可交互的客户界面,向客户显示模型数据。控制器响应客户的请求,根据客户的请求来操作模型,并且把模型的响应结果由视图展示给客户。 MVC模式二、MVC设计模型的优点和好处(1)、各司其职、互不干涉在MVC模式中,3个层各司其职,所以如果哪一层的需求发生了变化,就只需要更改相应层中的代码,而不会影响到其他层。(2)、有利于在开发中的分工在MVC模式中,由于按层把系统分开,那么就能更好地实现开发中的分工。网页设计人员可以开发JSP页面,对于业务熟悉的开发人员可以开发模型中相关业务处理的方法,而其他开发人员可开发控制器,以进行程序控制。(3)、有利于组件的重用分层更有利于组件的重用,如控制层可独立成一个通用的组件,视图层也可做成通用的操作界面。MVC最重要的特点是把显示与数据分离,这样就增加了各个模块的可重用性。三、MVC编程模式由Servlet接收客户端请求,调用相应的模型处理业务逻辑和数据,再由Servlet根据处理的结果,选择相应的JSP或HTML文件响应客户端。
2023年12月03日
0 阅读
0 评论
0 点赞
2023-12-03
满满干货(jdk使用)jdk运行命令,JDK/bin下工具列表说明及归纳,java htmlconverter,
JDK/bin下工具列表说明appletviewer.exe:一种执行HTML文件上的Java小程序类的Java浏览器apt.exe:注解处理工具(Annotation Processing Tool), SolarisTM 操作系统和 Linux上用于处理注释的工具extcheck.exe:扩展检测工具,检测目标 jar 文件与当前安装方式扩展jar 文件间的版本冲突HtmlConverter.exe:Java(TM) 插件 HTML 转换器是一种实用程序,可用于将任一包含小程序的 HTML 页面,转换为使用 Java(TM)插件的格式idlj.exe:IDL转Java编译器(IDL-to-Java Compiler),用于为指定的IDL文件生成Java绑定,IDL意即接口定义语言(Interface Definition Language)jabswitch.exe:Java访问桥开关(JavaAccess Bridge switch),用于启用/禁用Java访问桥。Java访问桥内置于Java 7 Update 6及以上版本,主要为Windows系统平台提供一套访问Java应用的APIjar.exe:文件管理工具,是个java应用程序,可将多个文件合并为单个JAR归档文件jarsigner.exe:密钥签名工具,为 Java 归档 (JAR) 文件产生签名,并校验已签名的 JAR文件的签名java.exe:运行工具,Java解释器,直接从类文件执行Java应用程序代码javac.exe:编译工具,Java编译器,将Java源代码换成字节代javadoc.exe:文档工具,根据Java源代码及其说明语句生成的HTML文档javafxpackager.exe:JavaFX包装器,用于执行与封装或签名JavaFX应用有关的任务javah.exe:头文件工具,用于根据Java类生成C/C++头文件和源文件(主要用于JNI开发领域)javap.exe:Java反编译工具,主要用于根据Java字节码文件反汇编为Java源代码文件javapackager.exe:Java包装器,执行与包装并签署Java和JavaFX应用程序的任务java-rmi.exe:Java远程方法调用(JavaRemote Method Invocation)工具,主要用于在客户机上调用远程服务器上的对象javaw.exe:Java运行工具,用于运行.class字节码文件或.jar文件,但不会显示控制台输出信息,适用于运行图形化程序Javaws.exe:用于启动和控制Web上的java程序。Java Web Start,可从Web下载和运行Java应用程序,下载、安装、运行、更新Java应用程序都非常简单方便jcmd.exe:Java 命令行(JavaCommand),用于向正在运行的JVM发送诊断命令请求jconsole.exe:图形化用户界面的监测工具,主要用于监测并显示运行于Java平台上的应用程序的性能和资源占用等信息Jdb.exe:Java调试工具(Java Debugger),主要用于对Java应用进行断点调试jdeps.exe:类依赖分析器,显示Java类的包级别或类级别的依赖,接受一个.class文件,一个目录,或者一个jar文件作为输入,默认把结果输出到系统输出(控制台)上 (Java8新特性)jhat.exe:java堆分析工具(Java Heap Analysis Tool),用于分析Java堆内存中的对象信息jinfo.exe:Java配置信息工具(Java Configuration Information),打印指定Java进程、核心文件或远程调试服务器的配置信息jjs.exe:Nashorn引擎,接受一些JavaScript源代码为参数,并且执行这些源代码 (Java8新特性)jmap.exe:Java内存映射工具(Java Memory Map),主要用于打印指定Java进程、核心文件或远程调试服务器的共享对象内存映射或堆内存细节jmc.exe:Java任务控制工具(Java Mission Control),主要用于HotSpot JVM的生产时间监测、分析、诊断jps.exe:JVM进程状态工具(JVM Process Status Tool),用于显示目标系统上的HotSpotJVM的Java进程信息jrunscript.exe:Java命令行脚本外壳工具(commandline script shell),用于解释执行javascript、groovy、ruby等脚本语言jsadebugd.exe:Java可用性代理调试守护进程(JavaServiceability Agent Debug Daemon),主要用于附加到指定的Java进程、核心文件,或充当一个调试服务器jstack.exe:Java堆栈跟踪工具,主要用于打印指定Java进程、核心文件或远程调试服务器的Java线程的堆栈跟踪信息jstat.exe:JVM统计监测工具(JVM Statistics Monitoring Tool),主要用于监测并显示JVM的性能统计信息jstatd.exe:jstatd(VM jstatd Daemon)工具是一个RMI服务器应用,用于监测HotSpotJVM的创建和终止,并提供一个接口,允许远程监测工具附加到运行于本地主机的JVM上jvisualvm.exe:JVM监测、故障排除、分析工具,主要以图形化界面的方式提供运行于指定虚拟机的Java应用程序的详细信息keytool.exe:密钥和证书管理工具,主要用于密钥和证书的创建、修改、删除等kinit.exe:主要用于获取或缓存Kerberos协议的票据授权票据klist.exe:允许用户查看本地凭据缓存和密钥表中的条目(用于Kerberos协议)ktab.exe:Kerberos密钥表管理工具,允许用户管理存储于本地密钥表中的主要名称和服务密钥native2ascii.exe:本地编码到ASCII编码的转换器(Native-to-ASCIIConverter),用于"任意受支持的字符编码"和与之对应的"ASCII编码和(或)Unicode转义"之间的相互转换orbd.exe:对象请求代理守护进程(Object Request Broker Daemon),它使客户端能够透明地定位和调用位于CORBA环境的服务器上的持久对象pack200.exe:AR文件打包压缩工具,它可以利用Java类特有的结构,对普通JAR文件进行高效压缩,以便于能够更快地进行网络传输packager.exe:这是微软提供的对象包装程序,用于对象安装包policytool.exe:策略工具,用于管理用户策略文件(.java.policy)rmic.exe:Java RMI 编译器,为使用JRMP或IIOP协议的远程对象生成stub、skeleton、和tie类,也用于生成OMG IDLrmid.exe:Java RMI 激活系统守护进程,rmid启动激活系统守护进程,允许在虚拟机中注册或激活对象rmiregistry.exe:Java 远程对象注册表,用于在当前主机的指定端口上创建并启动一个远程对象注册表schemagen.exe:XML schema生成器,用于生成XMLschema文件serialver.exe:序列版本命令,用于生成并返回serialVersionUIDservertool.exe:Java IDL 服务器工具,用于注册、取消注册、启动和终止持久化的服务器tnameserv.exe:Java IDL瞬时命名服务unpack200.exe:JAR文件解压工具,将一个由pack200打包的文件解压提取为JAR文件wsgen.exe:XML Web Service 2.0的Java API,生成用于JAX-WS Web Service的JAX-WS便携式产物wsimport.exe:XML Web Service 2.0的Java API,主要用于根据服务端发布的wsdl文件生成客户端存根及框架xjc.exe:主要用于根据XML schema文件生成对应的Java类JDK/bin下工具归纳基本工具 JDK的基础,用这些工具来编写应用程序javac.exe-- Java语言编译器java.exe -- Java应用程序启动器,JDK 1.6版里同时用于开发和部署,旧的部署启动器,jre,不在提供javadoc.exe -- Java API 文档生成器apt.exe -- java 注释处理器appletviewer.exe -- java applet 小程序查看器jar.exe -- java文件压缩打包工具jdb.exe-- Java 调试器.javah.exe -- C 头文件和stub生成器,用于写本地化方法,例如生产JNI样式的头文件javap.exe-- class文件 反编译工具extcheck.exe -- 用于检测jar包中的问题安全工具 用于设置系统的安全规则和生产可以工作在远端的安全规则下的应用程序keytool.exe-- 管理密钥库和证书.jarsigner.exe -- 生产和校验JAR签名policytool.exe -- 有用户界面的规则管理工具kinit.exe -- 用于获得和缓存网络认证协议Kerberos 票证的授予票证klist.exe -- 凭据高速缓存和密钥表中的 Kerberos 显示条目ktab.exe-- 密钥和证书管理工具国际化工具 帮助创建可本地化的应用程序native2ascii -- 见文本转化为 Unicode Latin-1http://java.sun.com/javase/6/docs/technotes/tools/windows/native2ascii.html远程方法调用工具 帮助创建可以和web和网络交互的应用程序rmic.exe -- 生成远程对象的stubs and skeletons(存根和框架)rmid.exe -- Java 远程方法调用(RMI:Remote Method Invocation) 活化系统守护进程rmiregistry.exe -- Java 远程对象注册表serialver.exe -- 返回类的 serialVersionUIDIDL and RMI-IIOP 工具 用于创建使用OMG-Standard IDL 和 CORBA/IIOP 的应用程序tnameserv.exe -- Provides access to the naming service.idlj.exe -- 生产映射到OMG IDL接口可以使Java应用程序使用CORBA的.java文件orbd.exe-- 为客户可以在CORBA环境下透明的定位和调用服务器的稳定的对象提供支持servertool.exe -- 为应用程序提供易于使用的接口用于注册,注销,启动,关闭服务器部署工具 用于JAVA部署pack200.exe -- 使用java gzip压缩工具将JAR文件转换为压缩的pack200文件,生产打包文件是高度压缩的JAR包,可以直接部署,减少下载时间unpack200.exe -- 解包pack200文件为JARs插件工具htmlconverter.exe -- Java Plug-in HTML转换器 htmlconverter -gui 可以启动图形界面web 启动工具javaws.exe-- Java web 启动命令行工具故障检修,程序概要分析,监视和管理工具jvisualvm.exe-- 一个图形化的Java虚拟机 //http://java.sun.com/javase/6/docs/technotes/guides/visualvm/index.htmljconsole.exe -- java监视台和管理控制台,图形界面的功能强大服务工具schemagen.exe -- Java构架的XML Schema生成器wsgen.exe -- 生成 JAX-WSwsimport.exe -- 生成 JAX-WSxjc.exe -- 绑定编译器监视工具 监视Java虚拟机的性能,不支持Windows 98 和Windows ME 平台jps.exe-- JVM Process Status 进程状态工具,列出目标系统的HotSpot JJVMjstat.exe-- 按照命令行的具体要求记录和收集一个JVM的性能数据jstatd.exe-- JVM jstat 的守护进程故障检测和修理工具jinfo.exe -- 配置或打印某个Java进程VM flagjhat.exe -- 堆储存查看器jmap.exe -- Java内存图jsadebugd.exe -- Java 的 Serviceability Agent Debug的守护进程jstack.exe-- Java堆栈跟踪脚本工具jrunscript.exe -- 运行脚本此外,可通过-help命令行参数来提供帮助
2023年12月03日
0 阅读
0 评论
0 点赞
2023-12-03
太疯狂了(javaweb开发技术教程第二版张娜电子书)javaweb开发技术教程李西明代码,Java工程师必备干货教材《Java Web开发实战》,java web开发实战,
一年一度毕业季,又到了简历、offer漫天飞,失望与希望并存的时节。在IT行业,高校毕业生求职时,面临的第一道门槛就是技能与经验的考验,但学校往往更注重学生的理论知识,忽略了对学生实践能力的培养,因而导致很多求职者在面试中败下阵来。在毕业生所学知识普遍脱离职场实战的大趋势下,《Java Web开发实战》应运而生,此教材由千锋教研院高教产品研发部编著、清华大学出版社出版,将理论应用于实践,切实提高学生的实战能力。整合多年实战案例 助力Java人才快速成长《Java Web开发实战》教材以提升读者实战技能作为编写目标,使用通俗易懂的语言、丰富多样的实例,对Java Web开发涉及的核心技术进行了详细的讲解。教材涵盖了JDBC基础、JDBC进阶、DBUtils工具包、XML、Web开发前奏、HTTP协议、Servlet详解、会话跟踪、JSP详解、EL表达式、JSTL标签库、Filter详解、Listener详解、文件上传和下载、MVC涉及模式、程序日志工具和人力资源管理系统共17章内容。其中最后一章通过人力资源管理系统这个项目案例,来讲解前面章节的知识点在实际开发中的应用,将理论知识系统地串联起来,让读者真正理解Java Web技术的精髓并做到融会贯通、学以致用。千锋教育自成立以来在Java学科积累了多年的实战经验,经过教研院高教产品研发部成员反复精雕细琢,多名经验丰富的院校老师悉心指导,以及千锋教育500多名精英学员通过试读给出的宝贵意见,使得《Java Web开发实战》一书更加趋于实战性。此教材由浅入深、循序渐进,在语法阐述时尽量避免术语和公式,使初学者能够快速入门,全面掌握实战技能。它既可以作为高等院校本、专科计算机相关专业的Java Web入门进阶教材,也可作为广大计算机编程爱好的学习参考书。配备完善学习资源 用良心打造精品教材除了精心打磨教材的内容,千锋教育还分别针对高校教师、高校学生推出了不同的教材配套服务。针对高校教师群体,千锋教育基于近七年来的教育培训经验,精心设计了“教材+授课资源+考试系统+测试题+辅助案例”的教学资源包,通过节约备课时间、缓解教学压力来提高教学质量;针对高校学生群体,千锋的“千问千知”IT社区平台,会有专业答疑,辅导老师承诺工作时间3小时内答复读者在教材学习中遇到的专业问题。近年来,千锋教研院百人精英教研团队专注研发课程体系,并在全国18个城市成立了教研中心,研发了授课项目3000余个,撰写了IT实用教材39套。因出版的教材内容新颖,实用性强,被近百所高校选择和使用,深受高校老师和学生的一致好评。此次出版的《Java Web开发实战》,延续了以往教材生动、实用的特点,倡导“快乐学习,实战就业”,让每一位读者在愉快的阅读中完成Java技术的进阶。
2023年12月03日
0 阅读
0 评论
0 点赞
2023-12-03
全程干货(java开发远程工具)java远程调用方法,Java中的远程过程调用(RPC),rpc java,
目录目录1. 背景2. 远程过程调用的定义3. 远程过程调用的优点4. 远程过程调用的缺点5. 实例5.1. 客户端5.2. 远程对象5.3. 服务端6. 参考文献1. 背景这学期上了《分布式系统》课程,内容主要是基于Java实现分布式计算,所以老师前几节课主要在给我们讲用Java做分布式可能会用到的一些技术。为了方便学习和记录,我将老师讲的内容结合书籍和资料做了一些整理,这一篇主要讨论远程过程调用。2. 远程过程调用的定义远程过程调用是一种进程间通信技术,用于基于客户端-服务器的应用程序。它也被称为子例程调用或函数调用。客户端有一个请求消息,RPC将其转换并发送给服务器。此请求可以是对远程服务器的过程或函数调用。当服务器接收到请求时,它将所需的响应发送回客户机。客户端在服务器处理调用时被阻塞,只有在服务器完成后才恢复执行。[1]远程过程调用的顺序如下:客户端存根由客户端调用。客户端存根发出一个系统调用,将消息发送到服务器,并将参数放入消息中。客户端操作系统将消息从客户端发送到服务器。消息由服务器操作系统传递到服务器存根。服务器存根从消息中删除参数。然后,服务器存根调用服务器执行操作。执行完成后,结果原路返回到客户端。过程如下图所示3. 远程过程调用的优点RPC的一些优点如下:远程过程调用支持面向过程和面向线程的模型。RPC的内部消息传递机制对用户隐藏。重写和重新开发代码的工作量在远程过程调用中是最小的。远程过程调用可以在分布式环境中使用,也可以在本地环境中使用。为了提高性能,RPC省略了许多协议层。4. 远程过程调用的缺点RPC的一些缺点如下:远程过程调用是一个可以用不同方式实现的概念。它不是一个标准。RPC对于硬件架构没有灵活性。它只基于交互。远程过程调用而增加了成本。5. 实例Java 中可以通过使用Socket、反射机制和动态代理来实现一个RPC框架。5.1. 客户端5.1.1. 客户端实现package service;import rpc.DynamicProxyFactory;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class clienTest {static void test(int threadId) {// 这里实现了一个登陆的操作 // 实现细节并不重要,所以没有给出 loginService 的代码 // 通过动态代理与服务器建立连接 loginService loginservice =DynamicProxyFactory.getProxy(loginService.class, "localhost", 8000);// 执行远程操作 String Result = loginservice.login("123", "123");// 输出结果 System.out.println(String.format("Client Thread %d result= %s",threadId, Result));}public static void main(String[] args) throws Exception {int threadNum = 4;// 创建多线程 ExecutorService executor = Executors.newFixedThreadPool(4);// 多线程调用 for (int i = 0; i < 4; i++) {int finalI = i;executor.submit(() -> {test(finalI + 1);});}}}5.1.2. 动态代理类package rpc;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Proxy;// 动态代理类public class DynamicProxyFactory {@SuppressWarnings("unchecked")public static <T> T getProxy(final Class<T> classType, final String host, final int port) {//泛型方法,传入什么类型返回什么类型InvocationHandler handler = (proxy, method, args) -> {Connector connector = null;try {connector = new Connector(host, port);RemoteCall call = new RemoteCall(classType.getName(), method.getName(), method.getParameterTypes(), args);connector.send(call);call = (RemoteCall) connector.receive();return call.getResult();} finally {if (connector != null) connector.close();}};System.out.println("代理开始执行");return (T) Proxy.newProxyInstance(classType.getClassLoader(),new Class<?>[]{classType}, handler);}}5.1.3. 连接器package rpc;import java.io.InputStream;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.OutputStream;import java.net.Socket;public class Connector {private String host;private int port;private Socket skt;private InputStream is;private ObjectInputStream ois;private OutputStream os;private ObjectOutputStream oos;public Connector(String host, int port) throws Exception {this.host = host;this.port = port;connect(host, port);}// 发送对象方法 public void send(Object obj) throws Exception {oos.writeObject(obj);}// 接收对象方法 public Object receive() throws Exception {return ois.readObject();}// 建立与远程服务器的连接 public void connect() throws Exception {connect(host, port);}// 建立与远程服务器的连接 public void connect(String host, int port) throws Exception {skt = new Socket(host, port);os = skt.getOutputStream();oos = new ObjectOutputStream(os);is = skt.getInputStream();ois = new ObjectInputStream(is);}// 关闭连接 public void close() {try {ois.close();oos.close();skt.close();} catch (Exception e) {System.out.println(" Conector.close :" + e);}}}5.2. 远程对象package rpc;import java.io.Serializable;//相当于一个javaBeanpublic class RemoteCall implements Serializable {private static final long serialVersionUID = 1L;private String className;// 表示服务类名或接口名private String methodName; // 表示功能方法名private Class<?>[] paramTypes;//表示方法参数类型 private Object[] params;//表示方法参数值/如果方法正常执行,则resul 为方法返回值,如果方法抛出异常,则resul 为该异常 private Object result;public RemoteCall() {}public RemoteCall(String className, String methodName, Class<?>[] paramTypes, Object[] params) {this.className = className;this.methodName = methodName;this.paramTypes = paramTypes;this.params = params;}public String getClassName() {return className;}public void setClassName(String className) {this.className = className;}public String getMethodName() {return methodName;}public void setMethodName(String methodName) {this.methodName = methodName;}public Class<?>[] getParamTypes() {return paramTypes;}public void setParamTypes(Class<?>[] paramTypes) {this.paramTypes = paramTypes;}public Object[] getParams() {return params;}public void setParams(Object[] params) {this.params = params;}public Object getResult() {return result;}public void setResult(Object result) {this.result = result;}public String toString() {return "className=" + className + " methodName=" + methodName;}}5.3. 服务端package rpc;import java.io.InputStream;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.OutputStream;import java.lang.reflect.Method;import java.net.Proxy;import java.net.ServerSocket;import java.net.Socket;import java.util.HashMap;import java.util.Map;import service.loginServiceImp;import java.util.Random;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;public class Server {private final static String CLASS_PATH = "service.";// 存放远程对象的缓存 private HashMap<String, Object> remoteObjects = new HashMap<>();//注册服务:把一个远程对象放到缓存中 public void register(String className, Object remoteObject) {remoteObjects.put(className, remoteObject);}// 8000端口负载均衡 public void transferService(ServerSocket serverSocket, int threadId) throws Exception {//随机数生成器 final Random random = new Random();// 循环运行 while (true) {System.out.println(String.format("Thread:%d 负载均衡启动......", threadId));// 创建hashMap HashMap<String, Object> map = new HashMap<>();// 等待服务 Socket socket = serverSocket.accept();// 获取客户端输入流 ObjectInputStream clientOis = new ObjectInputStream(socket.getInputStream());// 获取客户端输出流 ObjectOutputStream clientOos = new ObjectOutputStream(socket.getOutputStream());// 将客户端传输的对象存入HashMap map.put("clientObject", (RemoteCall) clientOis.readObject());// 随机获取一个端口 int serverIndex = 8001 + random.nextInt(2);// 打开端口 Socket targetSocket = new Socket("localhost", serverIndex);// 输出 System.out.println(String.format("Thread:%d 负载均衡传输任务到端口 %d......", threadId, serverIndex));// 获取输出对象流 ObjectOutputStream oos = new ObjectOutputStream(targetSocket.getOutputStream());// 传输hashMap oos.writeObject(map);// 获取输入对象流 ObjectInputStream serverOis = new ObjectInputStream(targetSocket.getInputStream());// 接收服务器发送的Call 对象 RemoteCall remotecallobj = (RemoteCall) serverOis.readObject();// 向客户端发送对象 clientOos.writeObject(remotecallobj);// 关闭资源 oos.close();socket.close();clientOos.close();}}// 暴露服务,创建基于流的Socket,并在8001、8002 端口监听 public void exportService(ServerSocket serverSocket, int threadId) throws Exception {// 循环运行 while (true) {System.out.println(String.format("Thread:%d 服务器启动......", threadId));Socket socket = serverSocket.accept();// 获取负载服务器输入流 ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());// 获取负载服务器输出流 ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());// 获取负载服务器传入的hashMap HashMap<String, Object> map = (HashMap<String, Object>) ois.readObject();// 接收客户发送的Call 对象 RemoteCall remotecallobj = (RemoteCall) map.get("clientObject");// 输出 System.out.println(remotecallobj);// 调用相关对象的方法 System.out.println(String.format("Thread:%d calling......", threadId));remotecallobj = invoke(remotecallobj);// 向客户发送包含了执行结果的remotecallobj 对象 oos.writeObject(remotecallobj);ois.close();oos.close();socket.close();}}public RemoteCall invoke(RemoteCall call) {Object result = null;try {String className = call.getClassName();String methodName = call.getMethodName();Object[] params = call.getParams();Class<?> classType = Class.forName(className);Class<?>[] paramTypes = call.getParamTypes();Method method = classType.getMethod(methodName, paramTypes);// 从hashmap缓存中取出相关的远程对象Object Object remoteObject = remoteObjects.get(className);if (remoteObject == null) {throw new Exception(className + " 的远程对象不存在");} else {result = method.invoke(remoteObject, params);System.out.println("远程调用结束:remotObject:" + remoteObject.toString() + ",params:" + params.toString());}} catch (Exception e) {System.out.println("错误:" + e.getMessage());}call.setResult(result);return call;}public static void main(String args[]) throws Exception {// 线程数量 int threadNum = 6;// 初始化 Server server = new Server();// 创建多线程 ExecutorService executor = Executors.newFixedThreadPool(threadNum);//把事先创建的RemoteServceImpl 对象加人到服务器的缓存中 //在服务注册中心注册服务 server.register(CLASS_PATH + "loginService", new loginServiceImp());// 多线程运行 Future[] future = new Future[threadNum];// 创建端口数组 ServerSocket[] serverSocket = new ServerSocket[threadNum];// 创建8000端口 ServerSocket port8000 = new ServerSocket(8000);// 创建8001端口 ServerSocket port8001 = new ServerSocket(8001);// 创建8002端口 ServerSocket port8002 = new ServerSocket(8002);for (int i = 0; i < threadNum; i++) {// 第一、二个线程端口为8000,负责调度资源,负载均衡 if (i <= 1) {serverSocket[i] = port8000;} else if (i <= 3) {// 第三、四个线程端口为8001,模拟第一台主机 serverSocket[i] = port8001;} else {// 第五、六个线程端口为8002,模拟第二台主机 serverSocket[i] = port8002;}}// 循环创建线程 for (int i = 0; i < threadNum; i++) {int finalI = i;future[i] = executor.submit(() -> {try {// 8000端口负载均衡 if (finalI <= 1) {server.transferService(serverSocket[finalI], finalI + 1);} else {//打开网络端口,接受外部请求,执行服务功能,返回结果 server.exportService(serverSocket[finalI], finalI + 1);}} catch (Exception e) {e.printStackTrace();}return 1;});}// 循环获取线程结果,阻塞同步 for (int i = 0; i < threadNum; i++) {future[i].get();}// 关闭端口 for (int i = 0; i < threadNum; i++) {serverSocket[i].close();}}}6. 参考文献[1] https://www.tutorialspoint.com/remote-procedure-call-rpc联系邮箱:curren_wong@163.comGithub:https://github.com/CurrenWong欢迎转载/Star/Fork,有问题欢迎通过邮箱交流。
2023年12月03日
0 阅读
0 评论
0 点赞
1
2
...
156