博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
smart-socket如何实现字符串通信
阅读量:2291 次
发布时间:2019-05-09

本文共 3947 字,大约阅读时间需要 13 分钟。

不少的朋友在接触到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
{ private static final int INT_LENGTH = 4; @Override public String decode(ByteBuffer readBuffer, AioSession
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
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
{ public static void main(String[] args) throws IOException { AioQuickServer
server = new AioQuickServer<>(8080, new StringProtocol(), new StringServerProcessor()); server.start(); } @Override public void process(AioSession
session, String msg) { System.out.println("收到客户端消息:" + msg); try { session.write("服务端收到了你的消息:" + msg); } catch (IOException e) { e.printStackTrace(); } } @Override public void stateEvent(AioSession
session, StateMachineEnum stateMachineEnum, Throwable throwable) { }}
  1. 客户端发送消息并接受服务的响应
/** * @author 三刀 * @version V1.0 , 2018/8/25 */public class StringClientProcessor implements MessageProcessor
{ private AioSession
session; public static void main(String[] args) throws IOException, InterruptedException, ExecutionException { StringClientProcessor processor = new StringClientProcessor(); AioQuickClient
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
session, String msg) { System.out.println("收到服务端消息:" + msg); } @Override public void stateEvent(AioSession
session, StateMachineEnum stateMachineEnum, Throwable throwable) { if (stateMachineEnum == StateMachineEnum.NEW_SESSION) { this.session = session; } } public AioSession
getSession() { return session; }}

转载地址:http://wobnb.baihongyu.com/

你可能感兴趣的文章
DenyHosts
查看>>
Maven构建环境安装
查看>>
SVN检出报错
查看>>
SVN同步版本库
查看>>
网络流量分析工具TCPDUMP
查看>>
系统弱密码检查John
查看>>
用户特权管理
查看>>
Linux软件包管理
查看>>
SUID和SGID可执行文件
查看>>
恢复已删除文件
查看>>
对敏感备份数据加密
查看>>
升级zlib
查看>>
扫描工具nmap
查看>>
linux Rootkit检查
查看>>
日志集中收集工具Syslog-ng+rsyslog+logrotate
查看>>
缓存的作用和重要指标
查看>>
Docker定制私有镜像
查看>>
Docker资源限制
查看>>
Docker容器跨主机通讯
查看>>
Docker单机编排docker-compose
查看>>