遠(yuǎn)程辦公”">國務(wù)院聯(lián)防聯(lián)控機(jī)制新聞發(fā)布會,多次肯定“云辦公”、“遠(yuǎn)程辦公”
733
2025-03-31
mina、netty消息邊界問題(采用換行符)
在TCP連接開始到結(jié)束連接,之間可能會多次傳輸數(shù)據(jù),也就是服務(wù)器和客戶端之間可能會在連接過程中互相傳輸多條消息。理想狀況是一方每發(fā)送一條消息,另一方就立即接收到一條,也就是一次write對應(yīng)一次read。但是,現(xiàn)實(shí)不總是按照劇本來走。
MINA官方文檔節(jié)選:
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官方文檔節(jié)選:
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.
上面兩段話表達(dá)的意思相同:TCP是基于字節(jié)流的協(xié)議,它只能保證一方發(fā)送和另一方接收到的數(shù)據(jù)的字節(jié)順序一致,但是,并不能保證一方每發(fā)送一條消息,另一方就能完整的接收到一條信息。有可能發(fā)送了兩條對方將其合并成一條,也有可能發(fā)送了一條對方將其拆分成兩條。
對此,MINA的官方文檔提供了以下幾種解決方案:
1、use fixed length messages
使用固定長度的消息。比如每個長度4字節(jié),那么接收的時候按每條4字節(jié)拆分就可以了。
2、use a fixed length header that indicates the length of the body
使用固定長度的Header,Header中指定Body的長度(字節(jié)數(shù)),將信息的內(nèi)容放在Body中。例如Header中指定的Body長度是100字節(jié),那么Header之后的100字節(jié)就是Body,也就是信息的內(nèi)容,100字節(jié)的Body后面就是下一條信息的Header了。
3、using a delimiter; for example many text-based protocols append a newline (or CR LF pair) after every message
使用分隔符。例如許多文本內(nèi)容的協(xié)議會在每條消息后面加上換行符(CR LF,即"\r\n"),也就是一行一條消息。當(dāng)然也可以用其他特殊符號作為分隔符,例如逗號、分號等等。
mina server
1
2
3
4
5
6
7
8
IoAcceptor acceptor = new NioSocketAcceptor();
// 添加一個Filter,用于接收、發(fā)送的內(nèi)容按照"\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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Serverbootstrap b = new Serverbootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel. class )
.childHandler( new ChannelInitializer
@Override
public void initChannel(SocketChannel ch)
throws Exception {
ChannelPipeline pipeline = ch.pipeline();
// LineBasedFrameDecoder按行分割消息
pipeline.addLast( new LineBasedFrameDecoder( 80 ));
// 再按UTF-8編碼轉(zhuǎn)成字符串
pipeline.addLast( new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast( new TcpServerHandler2());
}
});
ChannelFuture f = b.bind( 8080 ).sync();
f.channel().closeFuture().sync();
client
1
2
3
4
5
6
7
8
socket = new Socket( "localhost" , 8080 );
out = socket.getOutputStream();
// 請求服務(wù)器
String lines = "床前明月光\r\n疑是地上霜\r\n舉頭望明月\r\n低頭思故鄉(xiāng)\r\n" ;
byte [] outputBytes = lines.getBytes( "UTF-8" );
out.write(outputBytes);
out.flush();
但是這樣是有問題的,如果消息內(nèi)容本身就有換行符,這個肯定是不對的
原文地址:http://www.cnblogs.com/wucao/p/3936559.html
TCP/IP
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。