IM的实现到优化思路

实现IM通讯的基本方式:

  1. 基于bio阻塞的socket,消息分发是activemq
  2. 私聊activeMQ做持久化(弃用数据库,因为数据库容易挂掉)
  3. 并发底、扩展性底、集群不了

优化思路:(使用netty)nio

  1. 客户端访问,经过Nginx转发到im service集群下
  2. 通过service集群,先执行登录,成功后返回im server的ip,port(轮询),并保存用户及ip,port连接关系
  3. 客户端获得ip,port,执行连接im server
  4. 连接到im server

示意图:

 

注意事项:

  1. 对客户端来讲,需要处理的是重连情况,应该要设置重连次数和间隔重连时间
  2. im service和server都是通过zookeeper维护,如果某一台服务挂掉,通过zookeeper移除,挂掉的服务上的连接进入重连过程,这样就不会再次连到已挂的服务上
  3. 对于粘包拆包问题,就是通过消息头定长策略

关于粘包拆包代码:

    /**
	 * 解socket数据包体
	 * @param is
	 * @return
	 * @throws IOException 
	 */
	public static String getDataBody(InputStream is) throws IOException {
		String dataBody = null;
		// 获取头部
		byte[] head = getData(is, 4);
		int dataLength = ByteUtil.toInt(head);

		// 获取数据
		byte[] data = getData(is, dataLength);
		dataBody = GZipUtil.uncompressToString(data);

		return dataBody;
	}
	

    /**
	 * 拆包
	 * @param is
	 * @param length
	 * @return
	 * @throws IOException
	 */
	private static  byte[] getData(InputStream is, int length) throws IOException {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		byte[] buffer = new byte[1024];
		int nIdx = 0; //累计读取了多少位
		int nReadLen = 0; //一次读取了多少位

		while (nIdx < length) { //循环读取足够长度的数据

			if(length - nIdx >= buffer.length){ //剩余数据大于缓存,则全部读取
				nReadLen = is.read(buffer);
			}else{ //剩余数据小于缓存,则注意拆分其他包,只取当前包剩余数据
				nReadLen = is.read(buffer, 0, length - nIdx);
			}
			
			if (nReadLen > 0) {
				baos.write(buffer, 0, nReadLen);
				nIdx = nIdx + nReadLen;
			} else {
				break;
			}
			
		}
		
		return baos.toByteArray();
	}
public void send(String content, OutputStream writer){   
 ****代码省略
	BufferedOutputStream bops = new BufferedOutputStream(writer,
					4 * SIZE);
			// 压缩过后的byte数
			byte[] contentbytes = GZipUtil.compressToBtyes(content
					.getBytes("UTF-8"));
			// 压缩过后 内容的长度
			int length = contentbytes.length;
			// 最后传输的数据
			byte[] data = new byte[length + 4];
			// 内容长度的字节数
			byte[] lengthdata = ByteUtil.toByteArray(length, 4);
			// 发送的字节 要先拼了内容长度的字节数 再拼上真实内容的字节数
			for (int i = 0; i < (length + 4); i++) {
				if (i < 4) {
					data[i] = lengthdata[i];
				} else {
					data[i] = contentbytes[i - 4];
				}
			}
			bops.write(data);
			bops.flush();

    ****代码省略
}

特别鸣谢:翔哥

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值