1、实现思路
IM每个节点定义唯一标识A,A = 机器码加im端口号。
当客户端连接到IM节点后,把客户端的用户唯一标识ID和连接的IM服务端的唯一标识A进行绑定。
当两个用户相互发送消息时,判断接收用户是否在线,在线,则获取接收消息用户的socketclient,若获取不到,则根据接收用户ID获取接收用户所在节点的唯一标识。
然后通过redis的订阅发布,发送消息到接收用户所在的节点。每个节点只订阅和该节点唯一标识相同的topic。
2、代码
pom
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.72</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.1</version>
</dependency>
<dependency>
<groupId>com.corundumstudio.socketio</groupId>
<artifactId>netty-socketio</artifactId>
<version>1.7.18</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.7</version>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.12.0</version>
</dependency>
</dependencies>
3、配置文件application.yml
spring:
redis:
redisson:
config:
classpath:redisson.yaml
server:
port: 8080
im:
port: 9092
4、配置文件redisson.yaml
singleServerConfig:
idleConnectionTimeout: 10000
connectTimeout: 10000
timeout: 3000
retryAttempts: 3
retryInterval: 1500
address: redis://192.168.5.174:6379
password: ld123456
clientName: null
keepAlive: false
tcpNoDelay: false
threads: 16
nettyThreads: 32
codec: !<org.redisson.codec.JsonJacksonCodec> {}
transportMode: "NIO"
5、启动类
VoiceApplication.java
package com.luding.voice.lib;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class VoiceApplication {
public static void main(String[] args) {
SpringApplication.run(VoiceApplication.class, args);
}
}
6、获取机器码工具类
MachineUtil.java
package com.luding.voice.lib.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Scanner;
public class MachineUtil {
public static String getMechineCode() {
String property = System.getProperty("os.name").toLowerCase();
String cpuSerialNumber = "";
String hardDiskSerialNumber = "";
String md5Result = "";
if (property.contains("windows")) {
// 获取cpu序列号
cpuSerialNumber = MachineUtil.getCPUSerialNumber();
// 获取 硬盘号
hardDiskSerialNumber = MachineUtil.getHardDiskSerialNumber();
} else if (property.contains("linux")) {
// 获取cpu序列号
cpuSerialNumber = MachineUtil.getUUID();
// 获取 硬盘号
hardDiskSerialNumber = MachineUtil.getBoisVersion();
}
// 获取到cpu序列号和硬盘号
return cpuSerialNumber + hardDiskSerialNumber;
}
/**
* 获取CPU序列号(Windows)
*
* @return
* @throws IOException
*/
public static String getCPUSerialNumber() {
String serial;
try {
Process process = Runtime.getRuntime().exec(new String[]{"wmic", "cpu", "get", "ProcessorId"});
process.getOutputStream().close();
Scanner sc = new Scanner(process.getInputStream());
serial = sc.next();
serial = sc.next();
} catch (IOException e) {
throw new RuntimeException("获取CPU序列号失败");
}
return serial;
}
/**
* 获取 硬盘序列号(Windows)
*
* @return
* @throws IOException
* @throws InterruptedException
*/
public static String getHardDiskSerialNumber() {
String serial;
try {
Process process = Runtime.getRuntime().exec(new String[]{"wmic", "path", "win32_physicalmedia", "get", "serialnumber"});
process.getOutputStream().close();
Scanner sc = new Scanner(process.getInputStream());