很多的朋友在接觸到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