记录php中生活难点尝试vue间接吸出

最古老也是最有效,并且永不过时的,TCP/UDP的二进制传输,事实上所有的通信方式归根结底都是TCP/UDP
CORBA Common Object Request Broker Architecture。古老而复杂的,支持面向对象的通信协议。
Web Service(SOA SOAP RDDI WSDL …)基于http+xml的标准化Web API
RestFul 回归简单化本源的Web API的事实标准,http+json
RMI Remote Method Invocation Java内部的分布式通信协议
JMS Java Message Service JavaEE中的消息框架标准,为很多MQ所支持
RPC Remote Procudure Call 远程过程方法调用,这只是一个统称概念,远程通信的方式,重点在于方法调用(不支持对象的概念),具体实现甚至可以用RMI RestFul等去实现,但一般不用,因为RMI不能跨语言,而RestFul效率太低。多用于服务器集群间的通信,因此常使用更加高效,短小精悍的传输模式以提高效率。
从单机到分布式->分布式通信(一台机器解决不了的问题,需要多台机器解决,多台机器内部需要进行通信)->最基本:二进制,两台机器之间通过网络通信一定是二进制数据传输TCP/IP(socket)

RPC01#
首先构造一个用于传输的类User,该类实现了序列化可以进行序列化从而通过网络传输二进制数据,他会跑在一台机器上去访问数据库,有人想拿到这个User的话我会对外提供一些服务

然后通过AUserService暴露FindById接口来进行数据查询,你给我一个ID,我给你一个User
User.java

Copy
package com.airsky.demo.rpc.Common;

import java.io.Serializable;

public class User implements Serializable {
private static final long serialVersionUID = 1L;
int id;
String name;

public User(int id, String name) {
    this.id = id;
    this.name = name;
}

public int getId() {
    return id;
}

public void setId(int id) {
    this.id = id;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

@Override
public String toString() {
    return "User{" +
            "id=" + id +
            ", name='" + name + '\'' +
            '}';
}

}
AUserService.java

Copy
package com.airsky.demo.rpc.Common;

public interface AUserService {
User findById(int id);
}
最终在AUserServiceImpl进行了实现,对传入的id进行了模拟数据库查询,返回一个User对象。这里只进行一个模拟,具体实现的话也很简单。

Copy
package com.airsky.demo.rpc.Common;

public class AUserServiceImpl implements AUserService{

@Override
public User findById(int id) {
    //模拟数据库查询
    return new User(id,"AirSky");
}

}
如果我们想通过最原始的方式来完成上述操作该怎么做呢?这个也是很多游戏和软件类似功能最底层的实现。
首先我们这台机器对外提供服务,就需要提供一个Server打开一个Socket端口进行监听,下面的实现是在Server类中新建了一个ServerSocket对象,并监听8888端口,accept接收一个客户端连接,然后通过send方法对连接进行处理。

Copy
public class Server {
//加上条件变量,不然s.close()不可达
private static boolean running = true;
public static void main(String[] args) throws Exception {
ServerSocket s=new ServerSocket(8888);
while (running){
System.out.println(“接收连接中…”);
Socket client=s.accept();
System.out.println(“连接主机:” + client.getInetAddress());
send(client);
client.close();
}
s.close();
}
下面来实现send方法对连接进行进一步处理。大概就是你给我一个id,我给你一个id和id对应的名字,就是这么简单。send方法传入了一个socket对象,我们可以通过socket对象的getInputStream方法来打开一个输入流,getOutputStream方法打开一个输出流。使用DataOutputStream的readInt对输入流中的数据进行指定方式读取,使用该包装流来简化读写操作,如果客户端以正确的方式传送了ID的即可读取到,然后调用AUserService的findById方法来查询id对应的User对象,最后通过DataOutputStream的writeInt和writeUTF以指定的方式分别向输出流中写入获取到的id和name。

Copy
private static void send(Socket client) throws Exception {
//获取Socket的输入流,用Data流包装读取二进制数据
DataInputStream dis = new DataInputStream(client.getInputStream());
//获取Socket的输出流,用Data流包装写出二进制数据
DataOutputStream dos = new DataOutputStream(client.getOutputStream());

    //读取Id
    int id = dis.readInt();
    System.out.println("接收到ID为:"+id);
    AUserService service= new AUserServiceImpl();
    User user = service.findById(id);
    //写出数据
    System.out.println("返回的对象为:"+user);
    dos.writeInt(user.getId());
    dos.writeUTF(user.getName());
    dos.flush();
    dis.close();
    dos.close();
}

服务端实现了我们再来实现以下客户端。服务端监听了8888端口我们是不是就需要新建一个Socket来连接8888端口,同样使用getOutputStream来获取一个输出流,再用DataOutputStream向流中写指定格式数据(二进制),最后来使用getInputStream获取输入流得到数据n。得到数据之后new一个新对象拿来用。

Copy
public class Client {
public static void main(String[] args) throws Exception {
Socket s = new Socket(“127.0.0.1”,8888);
//使用DataOutputStream包装以二进制写入
DataOutputStream dos = new DataOutputStream(s.getOutputStream());
dos.writeInt(8888);
DataInputStream dis = new DataInputStream(s.getInputStream());
int id = dis.readInt();
String name = dis.readUTF();
User user = new User(id,name);
System.out.println(user);
}
}
现在我们启动服务端,然后启动客户端后,服务端和客户端就会收到以下数据

以上这种是最简单最原始的方式,这种方式非常的不灵活,这种方式只能传输单一的对象,对于传输的对象必须了解才能传的过去拿的过来,如果在代码量大的情况下需要对某个或者多个对象加属性,那么我们的就需要大量整 改,尤其是传输过程和业务逻辑代码全部混合在一起的时候,所以我们就需要一种写起来更加爽的方式。RPC02应运而生。

RPC02#
假如我现在只是个业务开发,对网络这块儿不太熟,现在我想告诉自己,能不能给个简单的方法,让我直接访问接口编写逻辑代码就行了。所以这里我们就需要对网络这块儿进行一个简单的封装。这就是RPC的演进过程。
最简单的方法是将网络操作封装为代理类Stub,Stub屏蔽了关于网络的细节

Copy
package com.airsky.demo.rpc.rpc02;

import com.airsky.demo.rpc.Common.User;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.Socket;

public class Stub {
public User findUserById(Integer id) throws Exception {
Socket s = new Socket(“127.0.0.1”,8888);
//使用DataOutputStream包装以二进制写入
DataOutputStream dos = new DataOutputStream(s.getOutputStream());
dos.writeInt(id);
DataInputStream dis = new DataInputStream(s.getInputStream());
int id1 = dis.readInt();
String name = dis.readUTF();
User user = new User(id1,name);
return user;
}
}
现在只要在new一个Stub出来,用Stub的findUserById方法就能拿到对象
Client中调用代理类

Copy
package com.airsky.demo.rpc.rpc02;

public class Client {
public static void main(String[] args) throws Exception {
Stub stub = new Stub();
System.out.println(stub.findUserById(33));
}
}
这就是第一步的演进,开发是一个不断螺旋递增的迭代过程,瀑布式的模型在很多场景下,尤其是互联网下早就被敏捷开发所替代了,敏捷一定要迭代。我们很多时候了解到的都是结果,直接接触到了最终的版本,所以我们根本理解不了中间的演进过程,也理解不了前人们为什么做出来这么多的改进,这就是我们不能理解RPC的原因。从历史演进学习技术,会理解得更透彻,知道前因后果,怎么问题的步骤与思路。

RPC03#
到了这里大家可能会说,作为一个Stub,这非常的不完善,你只能代理一个方法,返回一个类,这也太弱了。那我们就一点点来演进。
如果说Stub能给我提供这样的一个接口,我们想使用Service的findUserById,而Stub的接口提供给我这个方法。通过Stub代理过的findUserById方法我们就能远程访问了。当我们调用findUserById的时候,他帮我们加进去了一些代码,这些代码就是网络服务,所以Stub这里实现了代理模式里面的动态代理,这里最难的。
Stub

Copy
package com.airsky.demo.rpc.rpc03;

import com.airsky.demo.rpc.Common.IUserService;
import com.airsky.demo.rpc.Common.User;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.Socket;

public class Stub {
public static IUserService getStub(){
InvocationHandler h=new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Socket s = new Socket(“127.0.0.1”,8888);
//使用ByteArrayOutputStream在内存中声明一个数组流
// ByteArrayOutputStream bos = new ByteArrayOutputStream();
//使用DataOutputStream包装以二进制写入
DataOutputStream dos = new DataOutputStream(s.getOutputStream());
dos.writeInt(456);//这里写死了需要改进
// s.getOutputStream().write(bos.toByteArray());
//
// System.out.println(s.getInputStream().read());
DataInputStream dis = new DataInputStream(s.getInputStream());
int id1 = dis.readInt();
String name = dis.readUTF();
User user = new User(id1,name);

            dos.close();
            dis.close();
            s.close();
            return user;
        }
    };
    Object o= Proxy.newProxyInstance(IUserService.class.getClassLoader(),new Class[]{IUserService.class},h);
    System.out.println(o.getClass().getName());
    System.out.println(o.getClass().getInterfaces()[0]);
    return (IUserService)o;

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值