很多的朋友在接触到smart-socket后,一上来就想写一个字符串通讯的案例。例如客户端发送"Hello Server!",服务端接收到该消息并响应"Hi Client!"。但最终发现客户端能够成功将消息发送出去,但服务端就是没法正常接收。那是否是这个smart-socket框架不行?为何原先用Netty很简单就实现了?java
也许您是第一次接触通讯,又或者此前有过一些通讯编程经历,但只要没法用smart-socket写出一个简单的字符串通讯示例,那说明您的通讯之旅还未入门。本文尽可能给你们解释清楚通讯编程的常见套路,此后你们能够轻松玩转socket。git
咱们以两我的的对话场景为例,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经过分隔符便识别出了两个消息。网络
总之你们要谨记两点:session
若是您的悟性还不错的话,文章看到此处便完结了。若是本文解释的还不够清楚,那接下来用代码来给你们示范方案一的实现。框架
/** * @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; } }
/** * @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) { } }
/** * @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,多谢!socket