> For the complete documentation index, see [llms.txt](https://yangsx95.gitbook.io/notes/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://yangsx95.gitbook.io/notes/distributed/rpc-xie-yi.md).

# 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();
            }

        }
    }
}
```
