在TCP鏈接開始到結束鏈接,之間可能會屢次傳輸數據,也就是服務器和客戶端之間可能會在鏈接過程當中互相傳輸多條消息。理想情況是一方每發送一條消息,另外一方就當即接收到一條,也就是一次write對應一次read。可是,現實不老是按照劇原本走。html
MINA官方文檔節選:java
TCP guarantess delivery of all packets in the correct order. But there is no guarantee that one write operation on the sender-side will result in one read event on the receiving side. One call of IoSession.write(Object message) by the sender can result in multiple messageReceived(IoSession session, Object message) events on the receiver; and multiple calls of IoSession.write(Object message) can lead to a single messageReceived event.服務器
Netty官方文檔節選:session
In a stream-based transport such as TCP/IP, received data is stored into a socket receive buffer. Unfortunately, the buffer of a stream-based transport is not a queue of packets but a queue of bytes. It means, even if you sent two messages as two independent packets, an operating system will not treat them as two messages but as just a bunch of bytes. Therefore, there is no guarantee that what you read is exactly what your remote peer wrote.app
上面兩段話表達的意思相同:TCP是基於字節流的協議,它只能保證一方發送和另外一方接收到的數據的字節順序一致,可是,並不能保證一方每發送一條消息,另外一方就能完整的接收到一條信息。有可能發送了兩條對方將其合併成一條,也有可能發送了一條對方將其拆分紅兩條。socket
對此,MINA的官方文檔提供瞭如下幾種解決方案:ide
一、use fixed length messages
編碼
使用固定長度的消息。好比每一個長度4字節,那麼接收的時候按每條4字節拆分就能夠了。spa
二、use a fixed length header that indicates the length of the body
netty
使用固定長度的Header,Header中指定Body的長度(字節數),將信息的內容放在Body中。例如Header中指定的Body長度是100字節,那麼Header以後的100字節就是Body,也就是信息的內容,100字節的Body後面就是下一條信息的Header了。
三、using a delimiter; for example many text-based protocols append a newline (or CR LF pair) after every message
使用分隔符。例如許多文本內容的協議會在每條消息後面加上換行符(CR LF,即"\r\n"),也就是一行一條消息。固然也能夠用其餘特殊符號做爲分隔符,例如逗號、分號等等。
mina server
IoAcceptor acceptor = new NioSocketAcceptor(); // 添加一個Filter,用於接收、發送的內容按照"\r\n"分割 acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter((ProtocolCodecFactory) new TextLineCodecFactory(Charset.forName("UTF-8"), "\r\n", "\r\n"))); acceptor.setHandler((IoHandler) new TcpServerHandle2()); acceptor.bind(new InetSocketAddress(8080));
netty server
ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); // LineBasedFrameDecoder按行分割消息 pipeline.addLast(new LineBasedFrameDecoder(80)); // 再按UTF-8編碼轉成字符串 pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8)); pipeline.addLast(new TcpServerHandler2()); } }); ChannelFuture f = b.bind(8080).sync(); f.channel().closeFuture().sync();
client
socket = new Socket("localhost", 8080); out = socket.getOutputStream(); // 請求服務器 String lines = "牀前明月光\r\n疑是地上霜\r\n舉頭望明月\r\n低頭思故鄉\r\n"; byte[] outputBytes = lines.getBytes("UTF-8"); out.write(outputBytes); out.flush();
可是這樣是有問題的,若是消息內容自己就有換行符,這個確定是不對的
原文地址:http://www.cnblogs.com/wucao/p/3936559.html