MINA、Netty、Twisted为什么放在一起学习?首先,不妨先分别看一下它们官方网站对其的介绍:

MINA:

Apache MINA is a network application framework which helps users develop high performance and high scalability network applications easily. It provides an abstract event-driven asynchronous API over various transports such as TCP/IP and UDP/IP via Java NIO.

Netty:

Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients.

Twisted:

Twisted is an event-driven networking engine written in Python and licensed under the open source MIT license.

(Twisted官网的文案不专业啊,居然不写asynchronous)

从上面简短的介绍中,就可以发现它们的共同特点:event-driven以及asynchronous。它们都是事件驱动、异步的网络编程框架。由此可见,它们之间的共同点还是很明显的。所以我这里将这三个框架放在一起,实现相同的功能,不但可以用少量的精力学三样东西,而且还可以对它们之间进行各方面的对比。

其中MINA和Netty是基于Java语言的,而Twisted是Python语言的。不过语言不是重点,重点的是理念。

使用传统的BIO(Blocking IO/阻塞IO)进行网络编程时,进行网络IO读写时都会阻塞当前线程,如果实现一个TCP服务器,都需要对每个客户端连接开启一个线程,而很多线程可能都在傻傻的阻塞住等待读写数据,系统资源消耗大。

而NIO(Non-Blocking IO/非阻塞IO)或AIO(Asynchronous IO/异步IO)则是通过IO多路复用技术实现,不需要为每个连接创建一个线程,其底层实现是通过操作系统的一些特性如select、poll、epoll、iocp等。这三个网络框架都是基于此实现。

下面分别用这三个框架实现一个最简单的TCP服务器。当接收到客户端发过来的字符串后,向客户端回写一个字符串作为响应。

Mina:

public class TcpServer {  

    public static void main(String[] args) throws IOException {
IoAcceptor acceptor = new NioSocketAcceptor();
acceptor.setHandler(new TcpServerHandle());
acceptor.bind(new InetSocketAddress(8080));
} } class TcpServerHandle extends IoHandlerAdapter { @Override
public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
cause.printStackTrace();
} // 接收到新的数据
@Override
public void messageReceived(IoSession session, Object message) throws Exception { // 接收客户端的数据
IoBuffer ioBuffer = (IoBuffer) message;
byte[] byteArray = new byte[ioBuffer.limit()];
ioBuffer.get(byteArray, 0, ioBuffer.limit());
System.out.println("messageReceived:" + new String(byteArray, "UTF-8")); // 发送到客户端
byte[] responseByteArray = "你好".getBytes("UTF-8");
IoBuffer responseIoBuffer = IoBuffer.allocate(responseByteArray.length);
responseIoBuffer.put(responseByteArray);
responseIoBuffer.flip();
session.write(responseIoBuffer);
} @Override
public void sessionCreated(IoSession session) throws Exception {
System.out.println("sessionCreated");
} @Override
public void sessionClosed(IoSession session) throws Exception {
System.out.println("sessionClosed");
}
}

Netty:

public class TcpServer {  

    public static void main(String[] args) throws InterruptedException {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch)
throws Exception {
ch.pipeline().addLast(new TcpServerHandler());
}
});
ChannelFuture f = b.bind(8080).sync();
f.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
} } class TcpServerHandler extends ChannelInboundHandlerAdapter { // 接收到新的数据
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws UnsupportedEncodingException {
try {
// 接收客户端的数据
ByteBuf in = (ByteBuf) msg;
System.out.println("channelRead:" + in.toString(CharsetUtil.UTF_8)); // 发送到客户端
byte[] responseByteArray = "你好".getBytes("UTF-8");
ByteBuf out = ctx.alloc().buffer(responseByteArray.length);
out.writeBytes(responseByteArray);
ctx.writeAndFlush(out); } finally {
ReferenceCountUtil.release(msg);
}
} @Override
public void channelActive(ChannelHandlerContext ctx) {
System.out.println("channelActive");
} @Override
public void channelInactive(ChannelHandlerContext ctx){
System.out.println("channelInactive");
} @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}

Twisted:

# -*- coding:utf-8 –*-  

from twisted.internet.protocol import Protocol
from twisted.internet.protocol import Factory
from twisted.internet import reactor class TcpServerHandle(Protocol): # 新的连接建立
def connectionMade(self):
print 'connectionMade' # 连接断开
def connectionLost(self, reason):
print 'connectionLost' # 接收到新数据
def dataReceived(self, data):
print 'dataReceived', data
self.transport.write('你好') factory = Factory()
factory.protocol = TcpServerHandle
reactor.listenTCP(8080, factory)
reactor.run()

上面的代码可以看出,这三个框架实现的TCP服务器,在连接建立、接收到客户端传来的数据、连接关闭时,都会触发某个事件。例如接收到客户端传来的数据时,MINA会触发事件调用messageReceived,Netty会调用channelRead,Twisted会调用dataReceived。编写代码时,只需要继承一个类并重写响应的方法即可。这就是event-driven事件驱动。

下面是Java写的一个TCP客户端用作测试,客户端没有使用这三个框架,也没有使用NIO,只是一个普通的BIO的TCP客户端。

TCP在建立连接到关闭连接的过程中,可以多次进行发送和接收数据。下面的客户端发送了两个字符串到服务器并两次获取服务器回应的数据,之间通过Thread.sleep(5000)间隔5秒。

public class TcpClient {  

    public static void main(String[] args) throws IOException, InterruptedException {  

        Socket socket = null;
OutputStream out = null;
InputStream in = null; try{ socket = new Socket("localhost", 8080);
out = socket.getOutputStream();
in = socket.getInputStream(); // 请求服务器
out.write("第一次请求".getBytes("UTF-8"));
out.flush(); // 获取服务器响应,输出
byte[] byteArray = new byte[1024];
int length = in.read(byteArray);
System.out.println(new String(byteArray, 0, length, "UTF-8")); Thread.sleep(5000); // 再次请求服务器
out.write("第二次请求".getBytes("UTF-8"));
out.flush(); // 再次获取服务器响应,输出
byteArray = new byte[1024];
length = in.read(byteArray);
System.out.println(new String(byteArray, 0, length, "UTF-8")); } finally {
// 关闭连接
in.close();
out.close();
socket.close();
}
}
}

用客户端分别测试上面三个TCP服务器:

MINA服务器输出结果:

sessionCreated
messageReceived:第一次请求
messageReceived:第二次请求
sessionClosed

Netty服务器输出结果:

channelActive
channelRead:第一次请求
channelRead:第二次请求
channelInactive

Twisted服务器输出结果:

connectionMade
dataReceived: 第一次请求
dataReceived: 第二次请求
connectionLost

MINA、Netty、Twisted一起学系列

MINA、Netty、Twisted一起学(一):实现简单的TCP服务器

MINA、Netty、Twisted一起学(二):TCP消息边界问题及按行分割消息

MINA、Netty、Twisted一起学(三):TCP消息固定大小的前缀(Header)

MINA、Netty、Twisted一起学(四):定制自己的协议

MINA、Netty、Twisted一起学(五):整合protobuf

MINA、Netty、Twisted一起学(六):session

MINA、Netty、Twisted一起学(七):发布/订阅(Publish/Subscribe)

MINA、Netty、Twisted一起学(八):HTTP服务器

MINA、Netty、Twisted一起学(九):异步IO和回调函数

MINA、Netty、Twisted一起学(十):线程模型

MINA、Netty、Twisted一起学(十一):SSL/TLS

MINA、Netty、Twisted一起学(十二):HTTPS

源码

https://github.com/wucao/mina-netty-twisted

Mina、Netty、Twisted一起学(一):实现简单的TCP服务器的更多相关文章

  1. Mina、Netty、Twisted一起学(八):HTTP服务器

    HTTP协议应该是目前使用最多的应用层协议了,用浏览器打开一个网站就是使用HTTP协议进行数据传输. HTTP协议也是基于TCP协议,所以也有服务器和客户端.HTTP客户端一般是浏览器,当然还有可能是 ...

  2. Mina、Netty、Twisted一起学(三):TCP消息固定大小的前缀(Header)

    在上一篇博文中,有介绍到用换行符分割消息的方法.但是这种方法有个小问题,如果消息中本身就包含换行符,那将会将这条消息分割成两条,结果就不对了. 本文介绍另外一种消息分割方式,即上一篇博文中讲的第2条: ...

  3. Mina、Netty、Twisted一起学(二):TCP消息边界问题及按行分割消息

    在TCP连接开始到结束连接,之间可能会多次传输数据,也就是服务器和客户端之间可能会在连接过程中互相传输多条消息.理想状况是一方每发送一条消息,另一方就立即接收到一条,也就是一次write对应一次rea ...

  4. Node.js实战14:一个简单的TCP服务器。

    本文,将会展示如何用Nodejs内置的net模块开发一个TCP服务器,同时模拟一个客户端,并实现客户端和服务端交互. net模块是nodejs内置的基础网络模块,通过使用net,可以创建一个简单的tc ...

  5. 【实验 1-1】编写一个简单的 TCP 服务器和 TCP 客户端程序。程序均为控制台程序窗口。

    在新建的 C++源文件中编写如下代码. 1.TCP 服务器端#include<winsock2.h> //包含头文件#include<stdio.h>#include<w ...

  6. python写一些简单的tcp服务器和客户端

    代码贴上,做个记录 TcpClient # -*- coding:utf-8 -*- import socket target_host = "127.0.0.1" #服务器端地址 ...

  7. Mina、Netty、Twisted一起学(十):线程模型

    要想开发一个高性能的TCP服务器,熟悉所使用框架的线程模型非常重要.MINA.Netty.Twisted本身都是高性能的网络框架,如果再搭配上高效率的代码,才能实现一个高大上的服务器.但是如果不了解它 ...

  8. Mina、Netty、Twisted一起学(九):异步IO和回调函数

    用过JavaScript或者jQuery的同学都知道,JavaScript特别是jQuery中存在大量的回调函数,例如Ajax.jQuery的动画等. $.get(url, function() { ...

  9. Mina、Netty、Twisted一起学(七):发布/订阅(Publish/Subscribe)

    消息传递有很多种方式,请求/响应(Request/Reply)是最常用的.在前面的博文的例子中,很多都是采用请求/响应的方式,当服务器接收到消息后,会立即write回写一条消息到客户端.HTTP协议也 ...

随机推荐

  1. IIS7显示ASP的详细错误信息到浏览器

    服务端环境:Windows2008 + IIS7 客户端浏览器设置:取消“显示友好的HTTP错误信息” IIS7设置(GUI): 1. 网站->ASP->调试属性->将错误发送到浏览 ...

  2. 创建一个Windows的NTP Server

    搭建一个VMware vRealize Suite的时候遇见了不少时间同步的问题, 实验室里网络与外界隔绝, 不能使用公网的NTP服务器, 所以使用文中的方法自己搭建了一个. 蛮好用的. Creati ...

  3. python coroutine测试

    目的:实现一个类似于asyn await的用法,来方便的编写callback相关函数 from __future__ import print_functionimport timeimport th ...

  4. J2EE Web开发入门—通过action是以传统方式返回JSON数据

    关键字:maven.m2eclipse.JSON.Struts2.Log4j2.tomcat.jdk7.Config Browser Plugin Created by Bob 20131031 l ...

  5. gpg的一些常用操作

    (1)列出keys # gpg --list-keys /root/.gnupg/pubring.gpg ------------------------ pub   2048R/98681A63 2 ...

  6. halcon学习之产品检测

    Rinspect_gasket_local_deformable.hdev   检测垫圈局部变形   *这个例子演示了如何利用局部变形匹配(local deformable matching)来寻找出 ...

  7. android之AlertDialog 点击其它区域自己主动消失

    遇到一个问题记录下来,在开发中使用了AlertDialog,想点击屏幕其它区域的时候让这个dialog消失,一開始不做不论什么设置,在小米手机能够正常显示,可是在三星中却有问题.后来发现少了一个属性: ...

  8. C# Like参数化 小记

    strBuilder.Append(" and b.name like '%' + @name + '%'"); parameters.Add(new SqlParameter(& ...

  9. 未能正确加载“Microsoft.VisualStudio.Editor.Implementation.EditorPackage”包。

    最近在升级 Visual Studio 2015 Update 3 的过程中,等了很长时间都没一点进展,于是就强行终止了升级程序,但VS也因此出了问题. 后来经过修复,不行,卸载再重装,仍然提示这个错 ...

  10. 操作系统性能分析与优化V1.0

    操作系统性能分析与优化V1.0 : http://www.docin.com/p-759561760.html