>  기사  >  php教程  >  RPC(원격 프로시저 호출) 사용 방법

RPC(원격 프로시저 호출) 사용 방법

坏嘻嘻
坏嘻嘻원래의
2018-09-14 11:44:184210검색

HTTP 요청 소켓 프로그래밍을 해본 사람이라면 누구나 통신 프로토콜을 설계할 때 "메시지 헤더/메시지 본문" 분할 방법이 매우 일반적으로 사용된다는 것을 알고 있습니다. 메시지 헤더는 메시지의 목적을 상대방에게 알려주고, 메시지 본문은 메시지 본문입니다. 상대방에게 어떻게 해야 하는지 알려준다.

HTTP 프로토콜 기반 RPC와 TCP 프로토콜 기반 RPC 비교:

HTTP 프로토콜 기반 시스템 간의 RPC는 유연하고 구현하기 쉽고(다중 오픈 소스 웹 서버에서 지원) 개방적(국제 표준)이며 본질적으로 이기종 플랫폼 간의 호출을 지원하는 등 많은 장점을 가지고 있어 널리 사용되고 있습니다. 이에 대응하는 것은 더 효율적이지만 구현하기가 더 복잡하고 서로 다른 프로토콜과 표준으로 인해 플랫폼 간 및 기업 간 통신을 용이하게 하는 TCP 프로토콜의 구현 버전입니다.

HTTP 프로토콜 구현에는 단점이 있습니다. 상위 계층 프로토콜이므로 동일한 내용이 포함된 정보를 전송하면 TCP 프로토콜을 사용하는 것보다 HTTP 프로토콜을 사용하는 것이 확실히 더 많은 바이트를 차지하게 됩니다. 따라서 동일한 네트워크 환경에서는 동일한 콘텐츠를 HTTP 프로토콜을 통해 전송하는 효율성이 TCP 프로토콜을 통해 데이터를 전송하는 것보다 낮고 정보 전송에 시간이 더 오래 걸립니다. 물론 코드 구현을 최적화하고 gzip 데이터 압축을 사용하면 이러한 격차를 줄일 수 있습니다. 장단점을 비교하고 실제 환경에서 성능이 사용자 경험에 미치는 영향을 고려하면 HTTP 프로토콜 기반 RPC는 여전히 큰 장점을 가지고 있습니다.

1. TCP 프로토콜 기반 RPC 구현

서비스 인터페이스:

public interface SayHelloService{
     public String sayHello(String helloArg);
}

서비스 구현:

public class SayHelloServiceImpl implements SayHelloService {
    
    @Override
    public String sayHello(String helloArg) {
        if(helloArg.equals("Hello")) {
            return "hello";
        }else{
            return "bye bye";
        }
    }          
}

서비스 소비자 소비자 키 코드:

// 接口名称
String interfacename = SayHelloService.class.getName();
// 需要远程执行的方法
Method method = SayHelloService.class.getMethod("sayHello", java.lang.String.class);
// 需要传递到远端的参数
Object[] arguments = {"hello"};
Socket socket = new Socket("127.0.0.1", 1234);
// 将方法名称和参数传递到远端
ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
output.writeUTF(interfacename); // 接口名称
output.writeUTF(method.getName()); // 方法名称
output.writeObject(method.getParameterTypes());
output.writeObject(arguments);

// 从远端读取方法的执行结果
ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
Object result = input.readObject();

서비스 공급자 개인 키 코드:

ServiceSocket server = new ServerSocket(1234);
while(true){
    Socket socket = server.accept();

    //读取服务信息
    ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
    String interfacename = input.readUTF();    //接口名称
    String methodName = input.readUTF();    // 方法名称
    Class<?>[] parameterTypes = (Class<?>[])input.readObject(); //参数类型
    Object[] arguments = (Object[]) input.readObject(); //参数对象
    
    // 执行调用
    Class serviceinterfaceclass = Class.forName(interfacename);
    Object service = service.get(interfacename);
    Method method = serviceinterfaceclass.getMethod(methodName, parameterTypes);
    Object result = method.invoke(service, arguments);

    ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
    output.writeObject(result);
}

2.

프로토콜 요청 정의:

public class Request{
    
    /**
    * 协议编码
    */
    private byte encode;

    /**
    * 命令
    */
    private String command;

    /**
    * 命令长度
    */
    private int commandLength;
}

프로토콜 응답 정의:

public class Response {

    /**
    * 编码
    */
    private byte encode;

    /**
    * 响应长度
    */
    private int responseLength;

    /**
    * 响应
    */
    private String response;
}

클라이언트 구현 키 코드:

// 请求
Request request = new Request();
request.setCommand("HELLO");
request.setCommandLength(request.getCommand().length());
request.setEncode(Encode.UTF8.getValue());

Socket client = new Socket("127.0.0.1", 4567);
OutputStream output = client.getOutputStream();

// 发送请求
ProtocolUtil.writeRequest(output, request);
InputStream input = client.getInputStream();
Response = response = ProtocolUtil.readResponse(input);

서버 구현 키 코드:

ServerSocket server = new ServerSocket(4567);
while(true){
    Socket client  = server.accept();
   
    //读取响应数据
    InputStream input = client.getInputStream();
    Request request = ProtocolUtil.readRequest(input);
    OutputStream output = client.getOutputStream();
    
    // 组装响应
    Response response = new Response();
    response.setEncode(Encode.UTF8.getValue());
    if(request.getCommand().equals("HELLO")){
       response.setResponse("hello!"); 
    }else {
        response.setResponse("bye bye");    
    }
    
    resposne.setResponseLength(response.getResponse().length());
    ProtocolUtil.writeResponse(output, response);
}

ProtocolUtil 코드

public class ProtocolUtil {

    public static Request readRequest(InputStream input) throws IOException {
        //读取编码
        byte[] encodeByte = new byte[1];
        input.read(encodeByte);
        byte encode = encodeByte[0];
        
        //读取命令长度
        byte[] commandLengthBytes = new byte[4];
        input.read(commandLengthBytes);
        int commandLength = ByteUtil.bytes2Int(commandLengthBytes);

        //读取命令
        byte[] commandBytes = new byte[commandLength];
        input.read(commandBytes);
        String command = "";
        if(Encode.GBK.getValue() == encode){
            command = new String(commandBytes, "GBK");
        }else{
            command = new String(commandBytes, "UTF8");
        }

        // 组装请求返回
        Request request = new Request();
        request.setCommand(command);
        request.setEncode(encode);
        request.setCommandLength(commandLength);

        return request;
    }

    public static void writeResponse(OutputStream output, Response response) throws IOExceptiono{
        //将response响应返回给客户端
        output.write(response.getEncode());
       // output.write(response.getResponseLength()); 
        //直接write一个int类型会截取低8位传输,丢失高8位
        output.write(ByteUtil.int2ByteArray(response.getResponseLength()));
        if(Encode.GBK.getValue() == resposne.getEncode()){
            output.write(response.getResponse().getBytes("GBK"));
        }else{
            output.write(response.getResponse().getBytes("UTF8"));
        }

        output.flush();
    }
}
public static int bytes2Int(byte[] bytes){
    int num = bytes[3] & 0xFF;
    num |= ((bytes[2] << 8) & 0xFF00;
    num |= ((bytes[1] << 16) & 0xFF0000;
    num |= ((bytes[0] << 24) & oxFF000000;

    return num;
}

관련 권장 사항:

HTTP 예비 주석 - Yitoem

http://windows.php.net/ 및 http://php.net/ 모두 PHP 다운로드를 제공합니다. 차이점은 무엇입니까?


위 내용은 RPC(원격 프로시저 호출) 사용 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.