smart-socket如何实现字符串通信

不少的朋友在接触到smart-socket后,一上来就想写一个字符串通信的案例。例如客户端发送"Hello Server!",服务端接收到该消息并响应"Hi Client!"。但最终发现客户端可以成功将消息发送出去,但服务端就是无法正常接收。那是不是这个smart-socket框架不行?为什么原先用Netty很简单就实现了?

也许您是第一次接触通信,又或者此前有过一些通信编程经历,但只要无法用smart-socket写出一个简单的字符串通信示例,那说明您的通信之旅还未入门。本文尽量给大家解释清楚通信编程的常见套路,此后大家可以轻松玩转socket。

我们以两个人的对话场景为例,A对B说:"我叫A我今年3岁"。从这句话中,我们很容易解读出A对B传递了两个消息,一个是“我叫A”,另一个是“我今年3岁”。人为识别一句话是一件很自然的事,我们甚至不用去思考为什么我们可以从一句话中解读出多个消息,那是一种本能。在这个本能的背后有一套非常复杂的“算法”在帮你准确的识别并分析日常交流的信息。但是在计算机要模拟现实世界的信息通信场景,就需要由程序员为机器赋予消息识别能力,这个能力也是通信中非常重要的环节:信息编解码。

同样是“我叫A我今年3岁”,人可以通过逐个文字读取,结合上下文的语义分析识别,最终解析出两个消息,而将这套算法转换成机器算法却是一件非常困难的事。不过我们可以采用机器更容易接受的方式来实现这个功能,接下里给大家介绍两种。

方案一

首先,两个通信机器可以事先约定好在每一个消息之前,先告诉对方这个消息长度多少,这样在传输的过程中无论一次性传递多少个消息,对方都能准确识别出。例如机器A与机器B的通信方式可以是这样的。A告知B:“这个消息3个字,我叫A,这个消息5个字,我今年3岁”,网络传输的形态就是“3我叫A5我今年3岁”。机器B收到这串内容之后就很容易解析出A传递的两个消息,只要先识别出即将解析消息的长度,再读取指定长度的数据便是一个完整的消息。

方案二

机器A可以与机器B约定好“接下来我的消息都以某个分割符为标志,且这个分隔符肯定不会出现于消息内容中的”。比如双方约定好的分隔符为逗号,那么双方通信的内容本身必然不能出现该符号。此时机器A传输给B的数据为“我叫A,我今年3岁,”,机器B通过分隔符便识别出了两个消息。

总之大家要谨记两点:

  1. 你的程序没有识别白话文的能力;
  2. 绝大部分的通信编解码都可按照本文提供的两种方案处理。

如果您的悟性还不错的话,文章看到此处便完结了。如果本文解释的还不够清楚,那接下来用代码来给大家示范方案一的实现。

  1. 约定双方通信的编解码协议
/**
 * @author 三刀
 * @version V1.0 , 2018/8/25
 */
public class StringProtocol implements Protocol<String> {

    private static final int INT_LENGTH = 4;

    @Override
    public String decode(ByteBuffer readBuffer, AioSession<String> session, boolean eof) {
        //识别消息长度
        if (readBuffer.remaining() < INT_LENGTH) {
            return null;
        }
        //判断是否存在半包情况
        int len = readBuffer.getInt(0);
        if (readBuffer.remaining() < len) {
            return null;
        }
        readBuffer.getInt();//跳过length字段
        byte[] bytes = new byte[len - INT_LENGTH];
        readBuffer.get(bytes);
        return new String(bytes);
    }

    @Override
    public ByteBuffer encode(String msg, AioSession<String> session) {
        byte[] bytes = msg.getBytes();
        ByteBuffer buffer = ByteBuffer.allocate(INT_LENGTH + bytes.length);
        buffer.putInt(INT_LENGTH + bytes.length);
        buffer.put(bytes);
        buffer.flip();
        return buffer;
    }
}
  1. 服务端实现消息处理逻辑并启动服务
/**
 * @author 三刀
 * @version V1.0 , 2018/8/25
 */
public class StringServerProcessor implements MessageProcessor<String> {
    public static void main(String[] args) throws IOException {
        AioQuickServer<String> server = new AioQuickServer<>(8080, new StringProtocol(), new StringServerProcessor());
        server.start();
    }

    @Override
    public void process(AioSession<String> session, String msg) {
        System.out.println("收到客户端消息:" + msg);
        try {
            session.write("服务端收到了你的消息:" + msg);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void stateEvent(AioSession<String> session, StateMachineEnum stateMachineEnum, Throwable throwable) {

    }
}
  1. 客户端发送消息并接受服务的响应
/**
 * @author 三刀
 * @version V1.0 , 2018/8/25
 */
public class StringClientProcessor implements MessageProcessor<String> {
    private AioSession<String> session;

    public static void main(String[] args) throws IOException, InterruptedException, ExecutionException {
        StringClientProcessor processor = new StringClientProcessor();
        AioQuickClient<String> client = new AioQuickClient<>("localhost", 8080, new StringProtocol(), processor);
        client.start();
        int i = 0;
        while (i++ < 10) {
            processor.getSession().write("Hello:" + i);
        }
        Thread.sleep(1000);
        client.shutdown();
    }

    @Override
    public void process(AioSession<String> session, String msg) {
        System.out.println("收到服务端消息:" + msg);
    }

    @Override
    public void stateEvent(AioSession<String> session, StateMachineEnum stateMachineEnum, Throwable throwable) {
        if (stateMachineEnum == StateMachineEnum.NEW_SESSION) {
            this.session = session;
        }
    }

    public AioSession<String> getSession() {
        return session;
    }
}

如果您是坚持到文末的读者,希望能Star并支持一下我们的项目smart-socket,多谢!

转载于:https://my.oschina.net/u/2385344/blog/1933949

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值