Netty编解码
2018-07-06 本文已影响31人
诺之林
本文的示例代码参考NettyCoder
目录
Startup
本文基于Netty入门NettyBasic项目
cp -R NettyBasic NettyCoder
mv ./src/main/java/com/example/NettyBasic ./src/main/java/com/example/NettyCoder
mv ./src/test/java/com/example/NettyBasic ./src/test/java/com/example/NettyCoder
grep -rl 'NettyBasic' * | xargs sed -i "" 's/NettyBasic/NettyCoder/g'
- 测试
# server
./gradlew bootrun
# client
telnet 127.0.0.1 10001
# server
read: hello
read complete
read: world
read complete
# client
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
hello
world
String
vim client.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socket
import unittest
HOST = '127.0.0.1'
PORT = 10001
ADDR = (HOST, PORT)
class Tests(unittest.TestCase):
def setUp(self):
self.socket = socket.socket(
socket.AF_INET, socket.SOCK_STREAM) # TCP socket
self.socket.connect(ADDR)
def tearDown(self):
self.socket.close()
def test_send_string(self):
data = bytearray('message', 'utf-8')
self.socket.send(data)
if __name__ == '__main__':
unittest.main()
本文基于Python3 安装方法: "brew upgrade python" 或者 pyenv
- 测试
# server
./gradlew bootrun
# client
python3 client.py
# server
server start
read: message
read complete
read complete
# client
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
Integer
vim client.py
# 这里省略了未修改代码
class Tests(unittest.TestCase):
def setUp(self):
self.socket = socket.socket(
socket.AF_INET, socket.SOCK_STREAM) # TCP socket
self.socket.connect(ADDR)
def tearDown(self):
self.socket.close()
# def test_send_string(self):
# data = bytearray('message', 'utf-8')
# self.socket.send(data)
def test_send_integer(self):
i = 1
data = bytearray(i.to_bytes(4, 'big'))
self.socket.send(data)
# 这里省略了未修改代码
vim src/main/java/com/example/NettyCoder/ByteToIntegerDecoder.java
package com.example.NettyCoder;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import java.util.List;
public class ByteToIntegerDecoder extends ByteToMessageDecoder {
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
if (in.readableBytes() >= 4) {
out.add(in.readInt());
}
}
}
sed -i "" 's/StringDecoder()/ByteToIntegerDecoder()/g' ./src/main/java/com/example/NettyCoder/NettyServer.java
- 测试
# server
./gradlew bootrun
# client
python3 client.py
# server
server start
read: 1
read complete
read complete
# client
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
字节序
python3
Python 3.7.0 (default, Jun 29 2018, 20:13:13)
[Clang 9.1.0 (clang-902.0.39.2)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> i = 1
>>> print(i.to_bytes(4, 'big'))
b'\x00\x00\x00\x01'
>>> print(i.to_bytes(4, 'little'))
b'\x01\x00\x00\x00'
sed -i "" 's/big/little/g' ./client.py
- 测试
# server
./gradlew bootrun
# client
python3 client.py
# server
server start
read: 16777216
read complete
read complete
# client
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
互动: 为什么服务端打印的结果是16777216?
Frame
vim client.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socket
import unittest
HOST = '127.0.0.1'
PORT = 10001
ADDR = (HOST, PORT)
class Frame(object):
def __init__(self, module, content):
self.module = module
self.content = content
def toBytes(self):
b1 = bytearray(self.module.to_bytes(4, 'big'))
b2 = bytearray(self.content, 'utf-8')
return b1 + b2
class Tests(unittest.TestCase):
def setUp(self):
self.socket = socket.socket(
socket.AF_INET, socket.SOCK_STREAM) # TCP socket
self.socket.connect(ADDR)
def tearDown(self):
self.socket.close()
# def test_send_string(self):
# data = bytearray('message', 'utf-8')
# self.socket.send(data)
# def test_send_integer(self):
# i = 1
# data = bytearray(i.to_bytes(4, 'big'))
# self.socket.send(data)
def test_send_frame(self):
frame = Frame(1, "message")
data = frame.toBytes()
self.socket.send(data)
if __name__ == '__main__':
unittest.main()
vim src/main/java/com/example/NettyCoder/Frame.java
package com.example.NettyCoder;
public class Frame {
private int module;
private String content;
public int getModule() {
return module;
}
public void setModule(int module) {
this.module = module;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Override
public String toString() {
return "Frame{" +
"module=" + module +
", content='" + content + '\'' +
'}';
}
}
vim src/main/java/com/example/NettyCoder/FrameDecoder.java
package com.example.NettyCoder;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import java.util.List;
public class FrameDecoder extends ByteToMessageDecoder {
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
if (in.readableBytes() >= 11) {
Frame frame = new Frame();
frame.setModule(in.readInt());
byte[] content = new byte[7];
in.readBytes(content);
frame.setContent(new String(content));
out.add(frame);
}
}
}
sed -i "" 's/ByteToIntegerDecoder()/FrameDecoder()/g' ./src/main/java/com/example/NettyCoder/NettyServer.java
- 测试
# server
./gradlew bootrun
# client
python3 client.py
# server
server start
read: Frame{module=1, content='message'}
read complete
read complete
# client
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
互动: 请大家思考经纬度和时间的编解码方式