├── .gitignore
├── README.md
├── pom.xml
└── src
└── main
└── java
└── com
└── xxg
└── network
├── lesson01
├── MinaServer.java
├── NettyServer.java
├── TcpClient.java
└── TwistedServer.py
├── lesson02
├── MinaServer.java
├── NettyServer.java
├── TcpClient.java
└── TwistedServer.py
├── lesson03
├── MinaServer.java
├── NettyServer.java
├── TcpClient.java
└── TwistedServer.py
├── lesson04
├── LittleEndian.java
├── MinaServer.java
├── MyMinaDecoder.java
├── MyMinaEncoder.java
├── MyNettyDecoder.java
├── MyNettyEncoder.java
├── NettyServer.java
├── TcpClient.java
└── TwistedServer.py
├── lesson05
├── MinaProtobufDecoder.java
├── MinaProtobufEncoder.java
├── MinaServer.java
├── NettyServer.java
├── StudentMsg.java
├── StudentMsg.proto
├── StudentMsg_pb2.py
├── TcpClient.java
└── TwistedServer.py
├── lesson06
├── MinaServer.java
├── NettyServer.java
├── NettyServer2.java
├── TcpClient.java
└── TwistedServer.py
├── lesson07
├── MinaServer.java
├── NettyServer.java
├── PublishClient.java
├── SubscribeClient.java
└── TwistedServer.py
├── lesson08
├── MinaServer.java
├── NettyServer.java
└── TwistedServer.py
├── lesson11
├── MinaServer.java
├── NettyServer.java
├── SslClient.java
├── TwistedServer.py
├── cert.crt
├── private.der
└── private.pem
├── lesson12
├── 1_gw2.vsgames.cn_bundle.crt
├── 2_gw2.vsgames.cn.key
├── MinaServer.java
├── NettyServer.java
├── TwistedServer.py
├── private.der
└── private.pem
└── netty
└── websocket
└── WebSocketServer.java
/.gitignore:
--------------------------------------------------------------------------------
1 | /*.iml
2 | /target
3 | /.idea
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 《MINA、Netty、Twisted一起学》系列教程源码
2 | [MINA、Netty、Twisted一起学(一):实现简单的TCP服务器](http://xxgblog.com/2014/08/15/mina-netty-twisted-1/)
3 |
4 | [MINA、Netty、Twisted一起学(二):TCP消息边界问题及按行分割消息](http://xxgblog.com/2014/08/21/mina-netty-twisted-2/)
5 |
6 | [MINA、Netty、Twisted一起学(三):TCP消息固定大小的前缀(Header)](http://xxgblog.com/2014/08/22/mina-netty-twisted-3/)
7 |
8 | [MINA、Netty、Twisted一起学(四):定制自己的协议](http://xxgblog.com/2014/08/25/mina-netty-twisted-4/)
9 |
10 | [MINA、Netty、Twisted一起学(五):整合protobuf](http://xxgblog.com/2014/08/27/mina-netty-twisted-5/)
11 |
12 | [MINA、Netty、Twisted一起学(六):session](http://xxgblog.com/2014/09/10/mina-netty-twisted-6/)
13 |
14 | [MINA、Netty、Twisted一起学(七):发布/订阅(Publish/Subscribe)](http://xxgblog.com/2014/09/19/mina-netty-twisted-7/)
15 |
16 | [MINA、Netty、Twisted一起学(八):HTTP服务器](http://xxgblog.com/2014/09/23/mina-netty-twisted-8/)
17 |
18 | [MINA、Netty、Twisted一起学(九):异步IO和回调函数](http://xxgblog.com/2014/10/12/mina-netty-twisted-9/)
19 |
20 | [MINA、Netty、Twisted一起学(十):线程模型](http://xxgblog.com/2014/10/16/mina-netty-twisted-10/)
21 |
22 | [MINA、Netty、Twisted一起学(十一):SSL/TLS](http://xxgblog.com/2017/02/27/mina-netty-twisted-11/)
23 |
24 | [MINA、Netty、Twisted一起学(十二):HTTPS](http://xxgblog.com/2017/02/28/mina-netty-twisted-12/)
25 |
26 | [基于 Netty 实现 WebSocket 服务器](https://xxgblog.com/2021/04/14/netty-websocket/)
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.xxg
8 | network
9 | 1.0.0
10 |
11 |
12 |
13 | org.apache.maven.plugins
14 | maven-compiler-plugin
15 |
16 | 1.8
17 | 1.8
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | io.netty
26 | netty-all
27 | 4.1.42.Final
28 |
29 |
30 | org.apache.mina
31 | mina-core
32 | 2.0.16
33 |
34 |
35 | org.apache.mina
36 | mina-http
37 | 2.0.16
38 |
39 |
40 | com.google.protobuf
41 | protobuf-java
42 | 2.5.0
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/src/main/java/com/xxg/network/lesson01/MinaServer.java:
--------------------------------------------------------------------------------
1 | package com.xxg.network.lesson01;
2 |
3 | import org.apache.mina.core.buffer.IoBuffer;
4 | import org.apache.mina.core.service.IoAcceptor;
5 | import org.apache.mina.core.service.IoHandlerAdapter;
6 | import org.apache.mina.core.session.IoSession;
7 | import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
8 |
9 | import java.io.IOException;
10 | import java.net.InetSocketAddress;
11 |
12 | /**
13 | * Created by wucao on 17/2/27.
14 | */
15 | public class MinaServer {
16 |
17 | public static void main(String[] args) throws IOException {
18 | IoAcceptor acceptor = new NioSocketAcceptor();
19 | acceptor.setHandler(new TcpServerHandle());
20 | acceptor.bind(new InetSocketAddress(8080));
21 | }
22 | }
23 |
24 | class TcpServerHandle extends IoHandlerAdapter {
25 |
26 | @Override
27 | public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
28 | cause.printStackTrace();
29 | }
30 |
31 | // 接收到新的数据
32 | @Override
33 | public void messageReceived(IoSession session, Object message) throws Exception {
34 |
35 | // 接收客户端的数据
36 | IoBuffer ioBuffer = (IoBuffer) message;
37 | byte[] byteArray = new byte[ioBuffer.limit()];
38 | ioBuffer.get(byteArray, 0, ioBuffer.limit());
39 | System.out.println("messageReceived:" + new String(byteArray, "UTF-8"));
40 |
41 | // 发送到客户端
42 | byte[] responseByteArray = "你好".getBytes("UTF-8");
43 | IoBuffer responseIoBuffer = IoBuffer.allocate(responseByteArray.length);
44 | responseIoBuffer.put(responseByteArray);
45 | responseIoBuffer.flip();
46 | session.write(responseIoBuffer);
47 | }
48 |
49 | @Override
50 | public void sessionCreated(IoSession session) throws Exception {
51 | System.out.println("sessionCreated");
52 | }
53 |
54 | @Override
55 | public void sessionClosed(IoSession session) throws Exception {
56 | System.out.println("sessionClosed");
57 | }
58 | }
--------------------------------------------------------------------------------
/src/main/java/com/xxg/network/lesson01/NettyServer.java:
--------------------------------------------------------------------------------
1 | package com.xxg.network.lesson01;
2 |
3 | import io.netty.bootstrap.ServerBootstrap;
4 | import io.netty.buffer.ByteBuf;
5 | import io.netty.channel.*;
6 | import io.netty.channel.nio.NioEventLoopGroup;
7 | import io.netty.channel.socket.SocketChannel;
8 | import io.netty.channel.socket.nio.NioServerSocketChannel;
9 | import io.netty.util.CharsetUtil;
10 | import io.netty.util.ReferenceCountUtil;
11 |
12 | import java.io.UnsupportedEncodingException;
13 |
14 | /**
15 | * Created by wucao on 17/2/27.
16 | */
17 | public class NettyServer {
18 |
19 | public static void main(String[] args) throws InterruptedException {
20 | EventLoopGroup bossGroup = new NioEventLoopGroup();
21 | EventLoopGroup workerGroup = new NioEventLoopGroup();
22 | try {
23 | ServerBootstrap b = new ServerBootstrap();
24 | b.group(bossGroup, workerGroup)
25 | .channel(NioServerSocketChannel.class)
26 | .childHandler(new ChannelInitializer() {
27 | @Override
28 | public void initChannel(SocketChannel ch)
29 | throws Exception {
30 | ch.pipeline().addLast(new TcpServerHandler());
31 | }
32 | });
33 | ChannelFuture f = b.bind(8080).sync();
34 | f.channel().closeFuture().sync();
35 | } finally {
36 | workerGroup.shutdownGracefully();
37 | bossGroup.shutdownGracefully();
38 | }
39 | }
40 | }
41 |
42 | class TcpServerHandler extends ChannelInboundHandlerAdapter {
43 |
44 | // 接收到新的数据
45 | @Override
46 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws UnsupportedEncodingException {
47 | try {
48 | // 接收客户端的数据
49 | ByteBuf in = (ByteBuf) msg;
50 | System.out.println("channelRead:" + in.toString(CharsetUtil.UTF_8));
51 |
52 | // 发送到客户端
53 | byte[] responseByteArray = "你好".getBytes("UTF-8");
54 | ByteBuf out = ctx.alloc().buffer(responseByteArray.length);
55 | out.writeBytes(responseByteArray);
56 | ctx.writeAndFlush(out);
57 |
58 | } finally {
59 | ReferenceCountUtil.release(msg);
60 | }
61 | }
62 |
63 | @Override
64 | public void channelActive(ChannelHandlerContext ctx) {
65 | System.out.println("channelActive");
66 | }
67 |
68 | @Override
69 | public void channelInactive(ChannelHandlerContext ctx){
70 | System.out.println("channelInactive");
71 | }
72 |
73 | @Override
74 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
75 | cause.printStackTrace();
76 | ctx.close();
77 | }
78 | }
--------------------------------------------------------------------------------
/src/main/java/com/xxg/network/lesson01/TcpClient.java:
--------------------------------------------------------------------------------
1 | package com.xxg.network.lesson01;
2 |
3 | import java.io.IOException;
4 | import java.io.InputStream;
5 | import java.io.OutputStream;
6 | import java.net.Socket;
7 |
8 | /**
9 | * Created by wucao on 17/2/27.
10 | */
11 | public class TcpClient {
12 |
13 | public static void main(String[] args) throws IOException, InterruptedException {
14 |
15 | Socket socket = null;
16 | OutputStream out = null;
17 | InputStream in = null;
18 |
19 | try{
20 |
21 | socket = new Socket("localhost", 8080);
22 | out = socket.getOutputStream();
23 | in = socket.getInputStream();
24 |
25 | // 请求服务器
26 | out.write("第一次请求".getBytes("UTF-8"));
27 | out.flush();
28 |
29 | // 获取服务器响应,输出
30 | byte[] byteArray = new byte[1024];
31 | int length = in.read(byteArray);
32 | System.out.println(new String(byteArray, 0, length, "UTF-8"));
33 |
34 | Thread.sleep(5000);
35 |
36 | // 再次请求服务器
37 | out.write("第二次请求".getBytes("UTF-8"));
38 | out.flush();
39 |
40 | // 再次获取服务器响应,输出
41 | byteArray = new byte[1024];
42 | length = in.read(byteArray);
43 | System.out.println(new String(byteArray, 0, length, "UTF-8"));
44 |
45 |
46 | } finally {
47 | // 关闭连接
48 | in.close();
49 | out.close();
50 | socket.close();
51 | }
52 |
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/com/xxg/network/lesson01/TwistedServer.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 –*-
2 |
3 | from twisted.internet.protocol import Protocol
4 | from twisted.internet.protocol import Factory
5 | from twisted.internet import reactor
6 |
7 | class TcpServerHandle(Protocol):
8 |
9 | # 新的连接建立
10 | def connectionMade(self):
11 | print 'connectionMade'
12 |
13 | # 连接断开
14 | def connectionLost(self, reason):
15 | print 'connectionLost'
16 |
17 | # 接收到新数据
18 | def dataReceived(self, data):
19 | print 'dataReceived', data
20 | self.transport.write('你好')
21 |
22 | factory = Factory()
23 | factory.protocol = TcpServerHandle
24 | reactor.listenTCP(8080, factory)
25 | reactor.run()
--------------------------------------------------------------------------------
/src/main/java/com/xxg/network/lesson02/MinaServer.java:
--------------------------------------------------------------------------------
1 | package com.xxg.network.lesson02;
2 |
3 | import org.apache.mina.core.service.IoAcceptor;
4 | import org.apache.mina.core.service.IoHandlerAdapter;
5 | import org.apache.mina.core.session.IoSession;
6 | import org.apache.mina.filter.codec.ProtocolCodecFilter;
7 | import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
8 | import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
9 |
10 | import java.io.IOException;
11 | import java.net.InetSocketAddress;
12 | import java.nio.charset.Charset;
13 |
14 | /**
15 | * Created by wucao on 17/2/27.
16 | */
17 | public class MinaServer {
18 |
19 | public static void main(String[] args) throws IOException {
20 | IoAcceptor acceptor = new NioSocketAcceptor();
21 |
22 | // 添加一个Filter,用于接收、发送的内容按照"\r\n"分割
23 | acceptor.getFilterChain().addLast("codec",
24 | new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"), "\r\n", "\r\n")));
25 |
26 | acceptor.setHandler(new TcpServerHandle());
27 | acceptor.bind(new InetSocketAddress(8080));
28 | }
29 |
30 | }
31 |
32 | class TcpServerHandle extends IoHandlerAdapter {
33 |
34 | @Override
35 | public void exceptionCaught(IoSession session, Throwable cause)
36 | throws Exception {
37 | cause.printStackTrace();
38 | }
39 |
40 | // 接收到新的数据
41 | @Override
42 | public void messageReceived(IoSession session, Object message)
43 | throws Exception {
44 |
45 | // 接收客户端的数据,这里接收到的不再是IoBuffer类型,而是字符串
46 | String line = (String) message;
47 | System.out.println("messageReceived:" + line);
48 |
49 | }
50 |
51 | @Override
52 | public void sessionCreated(IoSession session) throws Exception {
53 | System.out.println("sessionCreated");
54 | }
55 |
56 | @Override
57 | public void sessionClosed(IoSession session) throws Exception {
58 | System.out.println("sessionClosed");
59 | }
60 | }
--------------------------------------------------------------------------------
/src/main/java/com/xxg/network/lesson02/NettyServer.java:
--------------------------------------------------------------------------------
1 | package com.xxg.network.lesson02;
2 |
3 | import io.netty.bootstrap.ServerBootstrap;
4 | import io.netty.channel.*;
5 | import io.netty.channel.nio.NioEventLoopGroup;
6 | import io.netty.channel.socket.SocketChannel;
7 | import io.netty.channel.socket.nio.NioServerSocketChannel;
8 | import io.netty.handler.codec.LineBasedFrameDecoder;
9 | import io.netty.handler.codec.string.StringDecoder;
10 | import io.netty.util.CharsetUtil;
11 |
12 | /**
13 | * Created by wucao on 17/2/27.
14 | */
15 | public class NettyServer {
16 | public static void main(String[] args) throws InterruptedException {
17 | EventLoopGroup bossGroup = new NioEventLoopGroup();
18 | EventLoopGroup workerGroup = new NioEventLoopGroup();
19 | try {
20 | ServerBootstrap b = new ServerBootstrap();
21 | b.group(bossGroup, workerGroup)
22 | .channel(NioServerSocketChannel.class)
23 | .childHandler(new ChannelInitializer() {
24 | @Override
25 | public void initChannel(SocketChannel ch)
26 | throws Exception {
27 | ChannelPipeline pipeline = ch.pipeline();
28 |
29 | // LineBasedFrameDecoder按行分割消息
30 | pipeline.addLast(new LineBasedFrameDecoder(80));
31 | // 再按UTF-8编码转成字符串
32 | pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
33 |
34 | pipeline.addLast(new TcpServerHandler());
35 | }
36 | });
37 | ChannelFuture f = b.bind(8080).sync();
38 | f.channel().closeFuture().sync();
39 | } finally {
40 | workerGroup.shutdownGracefully();
41 | bossGroup.shutdownGracefully();
42 | }
43 | }
44 | }
45 |
46 | class TcpServerHandler extends ChannelInboundHandlerAdapter {
47 |
48 | // 接收到新的数据
49 | @Override
50 | public void channelRead(ChannelHandlerContext ctx, Object msg) {
51 |
52 | // msg经过StringDecoder后类型不再是ByteBuf而是String
53 | String line = (String) msg;
54 | System.out.println("channelRead:" + line);
55 | }
56 |
57 | @Override
58 | public void channelActive(ChannelHandlerContext ctx) {
59 | System.out.println("channelActive");
60 | }
61 |
62 | @Override
63 | public void channelInactive(ChannelHandlerContext ctx) {
64 | System.out.println("channelInactive");
65 | }
66 |
67 | @Override
68 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
69 | cause.printStackTrace();
70 | ctx.close();
71 | }
72 | }
--------------------------------------------------------------------------------
/src/main/java/com/xxg/network/lesson02/TcpClient.java:
--------------------------------------------------------------------------------
1 | package com.xxg.network.lesson02;
2 |
3 | import java.io.IOException;
4 | import java.io.OutputStream;
5 | import java.net.Socket;
6 |
7 | /**
8 | * Created by wucao on 17/2/27.
9 | */
10 | public class TcpClient {
11 |
12 | public static void main(String[] args) throws IOException, InterruptedException {
13 |
14 | Socket socket = null;
15 | OutputStream out = null;
16 |
17 | try{
18 |
19 | socket = new Socket("localhost", 8080);
20 | out = socket.getOutputStream();
21 |
22 | String lines = "床前";
23 | byte[] outputBytes = lines.getBytes("UTF-8");
24 | out.write(outputBytes);
25 | out.flush();
26 |
27 | Thread.sleep(1000);
28 |
29 | lines = "明月";
30 | outputBytes = lines.getBytes("UTF-8");
31 | out.write(outputBytes);
32 | out.flush();
33 |
34 | Thread.sleep(1000);
35 |
36 | lines = "光\r\n疑是地上霜\r\n举头";
37 | outputBytes = lines.getBytes("UTF-8");
38 | out.write(outputBytes);
39 | out.flush();
40 |
41 | Thread.sleep(1000);
42 |
43 | lines = "望明月\r\n低头思故乡\r\n";
44 | outputBytes = lines.getBytes("UTF-8");
45 | out.write(outputBytes);
46 | out.flush();
47 |
48 | } finally {
49 | // 关闭连接
50 | out.close();
51 | socket.close();
52 | }
53 |
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/com/xxg/network/lesson02/TwistedServer.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 –*-
2 |
3 | from twisted.protocols.basic import LineOnlyReceiver
4 | from twisted.internet.protocol import Factory
5 | from twisted.internet import reactor
6 |
7 | class TcpServerHandle(LineOnlyReceiver):
8 |
9 | # 新的连接建立
10 | def connectionMade(self):
11 | print 'connectionMade'
12 |
13 | # 连接断开
14 | def connectionLost(self, reason):
15 | print 'connectionLost'
16 |
17 | # 接收到新的一行数据
18 | def lineReceived(self, data):
19 | print 'lineReceived:' + data
20 |
21 | factory = Factory()
22 | factory.protocol = TcpServerHandle
23 | reactor.listenTCP(8080, factory)
24 | reactor.run()
--------------------------------------------------------------------------------
/src/main/java/com/xxg/network/lesson03/MinaServer.java:
--------------------------------------------------------------------------------
1 | package com.xxg.network.lesson03;
2 |
3 | import org.apache.mina.core.service.IoAcceptor;
4 | import org.apache.mina.core.service.IoHandlerAdapter;
5 | import org.apache.mina.core.session.IoSession;
6 | import org.apache.mina.filter.codec.ProtocolCodecFilter;
7 | import org.apache.mina.filter.codec.prefixedstring.PrefixedStringCodecFactory;
8 | import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
9 |
10 | import java.io.IOException;
11 | import java.net.InetSocketAddress;
12 | import java.nio.charset.Charset;
13 |
14 | /**
15 | * Created by wucao on 17/2/27.
16 | */
17 | public class MinaServer {
18 |
19 | public static void main(String[] args) throws IOException {
20 | IoAcceptor acceptor = new NioSocketAcceptor();
21 |
22 | // 4字节的Header指定Body的字节数,对这种消息的处理
23 | acceptor.getFilterChain().addLast("codec",
24 | new ProtocolCodecFilter(new PrefixedStringCodecFactory(Charset.forName("UTF-8"))));
25 |
26 | acceptor.setHandler(new TcpServerHandle());
27 | acceptor.bind(new InetSocketAddress(8080));
28 | }
29 | }
30 |
31 | class TcpServerHandle extends IoHandlerAdapter {
32 |
33 | @Override
34 | public void exceptionCaught(IoSession session, Throwable cause)
35 | throws Exception {
36 | cause.printStackTrace();
37 | }
38 |
39 | // 接收到新的数据
40 | @Override
41 | public void messageReceived(IoSession session, Object message)
42 | throws Exception {
43 |
44 | String msg = (String) message;
45 | System.out.println("messageReceived:" + msg);
46 |
47 | }
48 |
49 | @Override
50 | public void sessionCreated(IoSession session) throws Exception {
51 | System.out.println("sessionCreated");
52 | }
53 |
54 | @Override
55 | public void sessionClosed(IoSession session) throws Exception {
56 | System.out.println("sessionClosed");
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/com/xxg/network/lesson03/NettyServer.java:
--------------------------------------------------------------------------------
1 | package com.xxg.network.lesson03;
2 |
3 | import io.netty.bootstrap.ServerBootstrap;
4 | import io.netty.channel.*;
5 | import io.netty.channel.nio.NioEventLoopGroup;
6 | import io.netty.channel.socket.SocketChannel;
7 | import io.netty.channel.socket.nio.NioServerSocketChannel;
8 | import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
9 | import io.netty.handler.codec.string.StringDecoder;
10 | import io.netty.util.CharsetUtil;
11 |
12 | /**
13 | * Created by wucao on 17/2/27.
14 | */
15 | public class NettyServer {
16 |
17 | public static void main(String[] args) throws InterruptedException {
18 | EventLoopGroup bossGroup = new NioEventLoopGroup();
19 | EventLoopGroup workerGroup = new NioEventLoopGroup();
20 | try {
21 | ServerBootstrap b = new ServerBootstrap();
22 | b.group(bossGroup, workerGroup)
23 | .channel(NioServerSocketChannel.class)
24 | .childHandler(new ChannelInitializer() {
25 | @Override
26 | public void initChannel(SocketChannel ch)
27 | throws Exception {
28 | ChannelPipeline pipeline = ch.pipeline();
29 |
30 | // LengthFieldBasedFrameDecoder按行分割消息,取出body
31 | pipeline.addLast(new LengthFieldBasedFrameDecoder(80, 0, 4, 0, 4));
32 | // 再按UTF-8编码转成字符串
33 | pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
34 |
35 | pipeline.addLast(new TcpServerHandler());
36 | }
37 | });
38 | ChannelFuture f = b.bind(8080).sync();
39 | f.channel().closeFuture().sync();
40 | } finally {
41 | workerGroup.shutdownGracefully();
42 | bossGroup.shutdownGracefully();
43 | }
44 | }
45 | }
46 |
47 | class TcpServerHandler extends ChannelInboundHandlerAdapter {
48 |
49 | // 接收到新的数据
50 | @Override
51 | public void channelRead(ChannelHandlerContext ctx, Object msg) {
52 |
53 | String message = (String) msg;
54 | System.out.println("channelRead:" + message);
55 | }
56 |
57 | @Override
58 | public void channelActive(ChannelHandlerContext ctx) {
59 | System.out.println("channelActive");
60 | }
61 |
62 | @Override
63 | public void channelInactive(ChannelHandlerContext ctx) {
64 | System.out.println("channelInactive");
65 | }
66 |
67 | @Override
68 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
69 | cause.printStackTrace();
70 | ctx.close();
71 | }
72 | }
--------------------------------------------------------------------------------
/src/main/java/com/xxg/network/lesson03/TcpClient.java:
--------------------------------------------------------------------------------
1 | package com.xxg.network.lesson03;
2 |
3 | import java.io.DataOutputStream;
4 | import java.io.IOException;
5 | import java.net.Socket;
6 |
7 | /**
8 | * Created by wucao on 17/2/27.
9 | */
10 | public class TcpClient {
11 |
12 | public static void main(String[] args) throws IOException {
13 |
14 | Socket socket = null;
15 | DataOutputStream out = null;
16 |
17 | try {
18 |
19 | socket = new Socket("localhost", 8080);
20 | out = new DataOutputStream(socket.getOutputStream());
21 |
22 | // 请求服务器
23 | String data1 = "牛顿";
24 | byte[] outputBytes1 = data1.getBytes("UTF-8");
25 | out.writeInt(outputBytes1.length); // write header
26 | out.write(outputBytes1); // write body
27 |
28 | String data2 = "爱因斯坦";
29 | byte[] outputBytes2 = data2.getBytes("UTF-8");
30 | out.writeInt(outputBytes2.length); // write header
31 | out.write(outputBytes2); // write body
32 |
33 | out.flush();
34 |
35 | } finally {
36 | // 关闭连接
37 | out.close();
38 | socket.close();
39 | }
40 |
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/com/xxg/network/lesson03/TwistedServer.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 –*-
2 |
3 | from twisted.protocols.basic import Int32StringReceiver
4 | from twisted.internet.protocol import Factory
5 | from twisted.internet import reactor
6 |
7 | class TcpServerHandle(Int32StringReceiver):
8 |
9 | # 新的连接建立
10 | def connectionMade(self):
11 | print 'connectionMade'
12 |
13 | # 连接断开
14 | def connectionLost(self, reason):
15 | print 'connectionLost'
16 |
17 | # 接收到新的数据
18 | def stringReceived(self, data):
19 | print 'stringReceived:' + data
20 |
21 | factory = Factory()
22 | factory.protocol = TcpServerHandle
23 | reactor.listenTCP(8080, factory)
24 | reactor.run()
--------------------------------------------------------------------------------
/src/main/java/com/xxg/network/lesson04/LittleEndian.java:
--------------------------------------------------------------------------------
1 | package com.xxg.network.lesson04;
2 |
3 | /**
4 | * Created by wucao on 17/2/27.
5 | */
6 | public class LittleEndian {
7 |
8 | /**
9 | * 将int转成4字节的小字节序字节数组
10 | */
11 | public static byte[] toLittleEndian(int i) {
12 | byte[] bytes = new byte[4];
13 | bytes[0] = (byte) i;
14 | bytes[1] = (byte) (i >>> 8);
15 | bytes[2] = (byte) (i >>> 16);
16 | bytes[3] = (byte) (i >>> 24);
17 | return bytes;
18 | }
19 |
20 | /**
21 | * 将小字节序的4字节的字节数组转成int
22 | */
23 | public static int getLittleEndianInt(byte[] bytes) {
24 | int b0 = bytes[0] & 0xFF;
25 | int b1 = bytes[1] & 0xFF;
26 | int b2 = bytes[2] & 0xFF;
27 | int b3 = bytes[3] & 0xFF;
28 | return b0 + (b1 << 8) + (b2 << 16) + (b3 << 24);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/com/xxg/network/lesson04/MinaServer.java:
--------------------------------------------------------------------------------
1 | package com.xxg.network.lesson04;
2 |
3 | import org.apache.mina.core.service.IoAcceptor;
4 | import org.apache.mina.core.service.IoHandlerAdapter;
5 | import org.apache.mina.core.session.IoSession;
6 | import org.apache.mina.filter.codec.ProtocolCodecFilter;
7 | import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
8 |
9 | import java.io.IOException;
10 | import java.net.InetSocketAddress;
11 |
12 | /**
13 | * Created by wucao on 17/2/27.
14 | */
15 | public class MinaServer {
16 |
17 | public static void main(String[] args) throws IOException {
18 | IoAcceptor acceptor = new NioSocketAcceptor();
19 |
20 | // 指定编码解码器
21 | acceptor.getFilterChain().addLast("codec",
22 | new ProtocolCodecFilter(new MyMinaEncoder(), new MyMinaDecoder()));
23 |
24 | acceptor.setHandler(new TcpServerHandle());
25 | acceptor.bind(new InetSocketAddress(8080));
26 | }
27 | }
28 |
29 | class TcpServerHandle extends IoHandlerAdapter {
30 |
31 | @Override
32 | public void exceptionCaught(IoSession session, Throwable cause)
33 | throws Exception {
34 | cause.printStackTrace();
35 | }
36 |
37 | // 接收到新的数据
38 | @Override
39 | public void messageReceived(IoSession session, Object message)
40 | throws Exception {
41 |
42 | // MyMinaDecoder将接收到的数据由IoBuffer转为String
43 | String msg = (String) message;
44 | System.out.println("messageReceived:" + msg);
45 |
46 | // MyMinaEncoder将write的字符串添加了一个小字节序Header并转为字节码
47 | session.write("收到");
48 | }
49 | }
--------------------------------------------------------------------------------
/src/main/java/com/xxg/network/lesson04/MyMinaDecoder.java:
--------------------------------------------------------------------------------
1 | package com.xxg.network.lesson04;
2 |
3 | import org.apache.mina.core.buffer.IoBuffer;
4 | import org.apache.mina.core.session.IoSession;
5 | import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
6 | import org.apache.mina.filter.codec.ProtocolDecoderOutput;
7 |
8 | /**
9 | * Created by wucao on 17/2/27.
10 | */
11 | public class MyMinaDecoder extends CumulativeProtocolDecoder {
12 |
13 | @Override
14 | protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
15 |
16 | // 如果没有接收完Header部分(4字节),直接返回false
17 | if(in.remaining() < 4) {
18 | return false;
19 | } else {
20 |
21 | // 标记开始位置,如果一条消息没传输完成则返回到这个位置
22 | in.mark();
23 |
24 | byte[] bytes = new byte[4];
25 | in.get(bytes); // 读取4字节的Header
26 |
27 | int bodyLength = LittleEndian.getLittleEndianInt(bytes); // 按小字节序转int
28 |
29 | // 如果body没有接收完整,直接返回false
30 | if(in.remaining() < bodyLength) {
31 | in.reset(); // IoBuffer position回到原来标记的地方
32 | return false;
33 | } else {
34 | byte[] bodyBytes = new byte[bodyLength];
35 | in.get(bodyBytes);
36 | String body = new String(bodyBytes, "UTF-8");
37 | out.write(body); // 解析出一条消息
38 | return true;
39 | }
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/src/main/java/com/xxg/network/lesson04/MyMinaEncoder.java:
--------------------------------------------------------------------------------
1 | package com.xxg.network.lesson04;
2 |
3 | import org.apache.mina.core.buffer.IoBuffer;
4 | import org.apache.mina.core.session.IoSession;
5 | import org.apache.mina.filter.codec.ProtocolEncoderAdapter;
6 | import org.apache.mina.filter.codec.ProtocolEncoderOutput;
7 |
8 | /**
9 | * Created by wucao on 17/2/27.
10 | */
11 | public class MyMinaEncoder extends ProtocolEncoderAdapter {
12 |
13 | @Override
14 | public void encode(IoSession session, Object message,
15 | ProtocolEncoderOutput out) throws Exception {
16 |
17 | String msg = (String) message;
18 | byte[] bytes = msg.getBytes("UTF-8");
19 | int length = bytes.length;
20 | byte[] header = LittleEndian.toLittleEndian(length); // 按小字节序转成字节数组
21 |
22 | IoBuffer buffer = IoBuffer.allocate(length + 4);
23 | buffer.put(header); // header
24 | buffer.put(bytes); // body
25 | buffer.flip();
26 | out.write(buffer);
27 | }
28 | }
--------------------------------------------------------------------------------
/src/main/java/com/xxg/network/lesson04/MyNettyDecoder.java:
--------------------------------------------------------------------------------
1 | package com.xxg.network.lesson04;
2 |
3 | import io.netty.buffer.ByteBuf;
4 | import io.netty.channel.ChannelHandlerContext;
5 | import io.netty.handler.codec.ByteToMessageDecoder;
6 |
7 | import java.util.List;
8 |
9 | /**
10 | * Created by wucao on 17/2/27.
11 | */
12 | public class MyNettyDecoder extends ByteToMessageDecoder {
13 |
14 | @Override
15 | protected void decode(ChannelHandlerContext ctx, ByteBuf in, List