# RPC协议

## Java网络通信

Java中提供了一套网络API用于网络通信，可以使用这套API进行分布式网络通信。其中就包含UDP与TCP以及组播Multicast的实现：

```
# 这些类都是对传输层，即TCP和UDP协议的封装

UDP:
    DatagramSocket
    DatagramChannel
TCP
    Socket/ServerSocket
    SocketChannel
Multicast
    MulticastSocket
```

> 注：组播
>
> 1. 单播，点对点通信
> 2. 广播，一对多通信
> 3. 组播，介于单播和广播之间，针对组进行通信

除此之外，也可以基于开源框架进行分布式通信，比如Mina、Netty等，你可以理解他们是对socket的封装和增强。

### Socket/ServerSocket

必须拥有以下几个条件才能保证两台服务器之间可以通信，所以在任何网络API中，这些条件都是必须指定的参数或者属性：

* IP地址
* 端口
* 通信协议

**示例代码**：

```java
// Socket服务端
public class SocketServer {

    public static void main(String[] args) throws Exception {
        ServerSocket server = new ServerSocket(8888);
        while (true) {
            final Socket socket = server.accept();
            new Thread() {
                @Override
                public void run() {
                    try {
                        BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                        PrintWriter writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
                        while (true) {
                            //读取客户端发送过来的消息
                            String line = reader.readLine(); 
                            if (line == null) {
                                break;
                            } else {
                                System.out.println(System.currentTimeMillis() +  "服务端收到数据：" + line);
                            }
                            //给客户端发送一条消息回复
                            writer.println(" - 我收到了你的消息，客户端");
                            writer.flush();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }.start();
        }
    }
}

// Socket客户端
public class SocketClient {

    public static void main(String[] args) throws Exception {
        Socket socket = new Socket("localhost", 8888);
        BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); //读取服务端信息
        PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);  // 往服务端写数据
        writer.println("你好，服务端");
        while (true) {
            String serverData = reader.readLine();
            if (serverData == null) {
                break;
            } else {
                System.out.println(System.currentTimeMillis() + " - 客户端收到数据：" + serverData);
            }
        }
        writer.close();
        socket.close();
    }
}

```

### Multicast

**Java组播示例：**

```java
/**
 * 组播
 * 如果你在大街上喊一声美女，将会有一组人(女)回头看你
 */
public class Multicast {

    public static class MulticastServer {
        public static void main(String[] args) {
            try {
                //  组定义
                //  组的地址端处于 224.0.0.0 - 239.255.255.255
                InetAddress group = InetAddress.getByName("224.5.5.6");
                MulticastSocket server = new MulticastSocket();
                for (int i = 0; i < 10; i++) {
                    String data = "你好年轻人";
                    server.send(new DatagramPacket(data.getBytes(), data.getBytes().length, group, 8888)); // DatagramPacket: UDP数据包
                    TimeUnit.SECONDS.sleep(2);
                }
            } catch (UnknownHostException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static class MulticastClient {
        public static void main(String[] args) {
            try {
                InetAddress group = InetAddress.getByName("224.5.5.6");
                MulticastSocket client = new MulticastSocket(8888);
                client.joinGroup(group); // 加入指定的组中
                byte[] buf = new byte[256];
                while (true) {
                    DatagramPacket msgPkg = new DatagramPacket(buf, buf.length);
                    client.receive(msgPkg);
                    
                    String msg = new String(msgPkg.getData());
                    System.out.println(msg);
                }
            } catch (UnknownHostException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://yangsx95.gitbook.io/notes/distributed/rpc-xie-yi.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
