Mina、Netty、Twisted一起学(一):实现简单的TCP服务器
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一起学(十一):SSL/TLS
MINA、Netty、Twisted一起学(十二):HTTPS
源码
https://github.com/wucao/mina-netty-twisted
Mina、Netty、Twisted一起学(一):实现简单的TCP服务器的更多相关文章
- Mina、Netty、Twisted一起学(八):HTTP服务器
HTTP协议应该是目前使用最多的应用层协议了,用浏览器打开一个网站就是使用HTTP协议进行数据传输. HTTP协议也是基于TCP协议,所以也有服务器和客户端.HTTP客户端一般是浏览器,当然还有可能是 ...
- Mina、Netty、Twisted一起学(三):TCP消息固定大小的前缀(Header)
在上一篇博文中,有介绍到用换行符分割消息的方法.但是这种方法有个小问题,如果消息中本身就包含换行符,那将会将这条消息分割成两条,结果就不对了. 本文介绍另外一种消息分割方式,即上一篇博文中讲的第2条: ...
- Mina、Netty、Twisted一起学(二):TCP消息边界问题及按行分割消息
在TCP连接开始到结束连接,之间可能会多次传输数据,也就是服务器和客户端之间可能会在连接过程中互相传输多条消息.理想状况是一方每发送一条消息,另一方就立即接收到一条,也就是一次write对应一次rea ...
- Node.js实战14:一个简单的TCP服务器。
本文,将会展示如何用Nodejs内置的net模块开发一个TCP服务器,同时模拟一个客户端,并实现客户端和服务端交互. net模块是nodejs内置的基础网络模块,通过使用net,可以创建一个简单的tc ...
- 【实验 1-1】编写一个简单的 TCP 服务器和 TCP 客户端程序。程序均为控制台程序窗口。
在新建的 C++源文件中编写如下代码. 1.TCP 服务器端#include<winsock2.h> //包含头文件#include<stdio.h>#include<w ...
- python写一些简单的tcp服务器和客户端
代码贴上,做个记录 TcpClient # -*- coding:utf-8 -*- import socket target_host = "127.0.0.1" #服务器端地址 ...
- Mina、Netty、Twisted一起学(十):线程模型
要想开发一个高性能的TCP服务器,熟悉所使用框架的线程模型非常重要.MINA.Netty.Twisted本身都是高性能的网络框架,如果再搭配上高效率的代码,才能实现一个高大上的服务器.但是如果不了解它 ...
- Mina、Netty、Twisted一起学(九):异步IO和回调函数
用过JavaScript或者jQuery的同学都知道,JavaScript特别是jQuery中存在大量的回调函数,例如Ajax.jQuery的动画等. $.get(url, function() { ...
- Mina、Netty、Twisted一起学(七):发布/订阅(Publish/Subscribe)
消息传递有很多种方式,请求/响应(Request/Reply)是最常用的.在前面的博文的例子中,很多都是采用请求/响应的方式,当服务器接收到消息后,会立即write回写一条消息到客户端.HTTP协议也 ...
随机推荐
- 一些新的web性能优化技术
1.IconFont:图标字体,这是近年来新流行的一种以字体代替图片的技术.它可以适应任何分辨率而不会出现图片模糊问题,与图片相比它具有更小的容量,更高的灵活性(像字体一样可以设置图标大小.颜色.透明 ...
- Windows 8.1/Server 2012 R2/Embedded 8.1 with Update 3(MSDN最新版)
微软于12月16日更新了包含Update 3的ISO,此次更新并不会明显改善用户的界面体验,下载后请校验MD5.我整理了中.英文的8.1/服务器版/嵌入式版本/多国语言包. 1,Windows 8.1 ...
- C#:注册机的实现【提供源代码下载】
代码下载 C#软件注册机 软件运行结果 参考文章 http://www.cnblogs.com/hanzhaoxin/archive/2013/01/04/2844191.html
- EWM ODO清理功能
ERP OBD下传到EWM会自动产生拣货任务(通常做法),但如果EWM因库存不足或其它原因无法拣货时一般要差异确认,对ODO行项目进行0确认.但问题是零确认后EWM标准流程是无法回传ERP的. ERP ...
- HTML5手机APP开发入门(1)
HTML5手机APP开发入门(1) 开发框架 Ionicframework V2 + Angular 2 具体内容可以参考一下网站 http://ionicframework.net/ http:// ...
- Android的Activity屏幕切换动画(一)-左右滑动切换
(国内知名Android开发论坛eoe开发者社区推荐:http://www.eoeandroid.com/) Android的Activity屏幕切换动画(一)-左右滑动切换 在Android开发过程 ...
- Activemq消息类型
Activemq消息类型JMS规范中的消息类型包括TextMessage.MapMessage.ObjectMessage.BytesMessage.和StreamMessage等五种.ActiveM ...
- 正则指引-量词demo
class Program { static void Main(string[] args) { string str = "1\"3"; var re1 = Rege ...
- mvc edmx 的config文件
<?xml version="1.0" encoding="utf-8"?> <configuration> <connectio ...
- denyhost防止SSH暴力破解
参考: http://blog.sina.com.cn/s/blog_593af2a70102vjnf.html denyhost 官网: http://denyhosts.sourceforge.n ...