对于Java开发人员,想要实现一个http服务,非常简单,写个servlet,打成war包,放到tomcat下就能运行。但如果要实现一个tcp服务就没那么简单了,因为tcp是传输层协议,并不像http那样,有类似tomcat的中间件给我们封装底层的网络协议,封装线程的交互。要实现一个tcp服务,只能自己动手处理网络和线程问题,这是非常考验编程功底的事情,而且如果团队人员素质不高,项目周期要求较短的情况下,是很难开发一个稳定的tcp服务的。
很多朋友可能会有疑惑,http协议挺好用的啊,为什么要用tcp服务?要知道,http是在tcp协议的基础上封装的应用层协议。这也就意味着http协议的性能一定是比tcp要低的多的(从上图可以看到,除了请求数据外有大量的头信息等)。另外http协议自身的特性,http是一个半双工且无状态的协议,因此很多的场景http协议是无法满足的。举一个最简单的例子,我们都用过打车软件,我们发个打车的请求,很多的司机端都能够快速的接收到。如果使用http协议是实现不了的(当然可以使用websocket,这里不具体讨论),即使是通过类似于ajax轮询的手段实现,性能也都会非常低,并且实时性不好,对服务器压力大等问题,这个时候tcp协议就出场了。
再考虑另外一个场景,考驾照的时候,教练车上都有一个打卡的机器(暂且称为终端机),那么打卡的机器需要和远程的服务器连接,实时传输学员练车的动态数据,如果使用http协议,不仅仅对于终端机编程(一般采用C语言,http是在tcp之上封装的协议,所以如果使用http协议会比较繁琐)要求较高,而且http协议会有很多无用的数据(http是一种通用的协议,为了实现通用,因此http头信息有很多是不用的,且http协议是一个纯文本的协议,相比较采用二进制协议,报文会比较大),浪费带宽。所以一般类似于嵌入式设备和应用服务数据交互也都会使用tcp协议。
有朋友可能会提到使用netty也可以实现tcp服务啊,当然,netty相比较使用传统的bio或者使用原生nio都要简单的多,而且解决了粘包拆包的问题,也封装了线程模型。确实,使用netty开发tcp服务器是目前很多企业的选择,但netty入门也相对比较复杂,学习成本较高。这里给大家推荐一个异步框架,Vertx,它的底层是基于netty的,使用Vertx开发tcp服务,非常的简单。
vertx开发tcp服务非常的简单,整体可以分为以下几个步骤
下面简单贴下代码,完整代码可以见GitHub,地址为:https://github.com/happy-fly/vertx
1. 在maven中引入依赖(写博客的时候,最新版本为3.6.0,写测试案例的时候最新版是3.5.4):
io.vertx
vertx-core
3.6.0
2.核心代码
// 创建TCP服务器
NetServer server = vertx.createNetServer();
// 处理连接请求
server.connectHandler(socket -> {
socket.handler(buffer -> {
// 在这里应该解析报文,封装为协议对象,并找到响应的处理类,得到处理结果,并响应
System.out.println("接收到的数据为:" + buffer.toString());
// 按照协议响应给客户端
socket.write(Buffer.buffer("Server Received"));
});
// 监听客户端的退出连接
socket.closeHandler(close -> {
System.out.println("客户端退出连接");
});
});
// 监听端口
server.listen(5555, res -> {
if (res.succeeded()) {
System.out.println("服务器启动成功");
}
});
这里的逻辑非常简单,就是输出接收到客户端请求的数据,然后告诉客户端,Server Received。
下面是客户端核心代码:
// 创建一个TCP客户端
NetClient client = vertx.createNetClient();
// 连接服务器
client.connect(5555, "localhost", conn -> {
if (conn.succeeded()) {
NetSocket s = conn.result();
// 向服务器写数据
s.write(Buffer.buffer("hello"));
// 读取服务器的响应数据
s.handler(buffer -> {
System.out.println(buffer.toString());
});
} else {
System.out.println("连接服务器异常");
}
});
客户端的实现也很简单,向服务端发送消息:hello,等待服务端的响应。
这里实现的比较简单,真实业务场景远比此要复杂的多,根据应用场景我们一般需要定义自己的协议,服务端在接收到客户端请求的时候需要根据自己定义的协议进行拆包,并封装为请求对象,然后调用具体的代码进行业务逻辑处理,待处理完毕需要将处理器处理的结果进行封包,发送给客户端。对于客户端的实现也是同样,接收到服务端的请求之后,根据协议进行拆包,处理完毕再把响应消息封包之后发给服务器。
关于Vertx创建tcp服务就完成了,是不是比起来使用bio,nio,netty都要简单的多。
Vert.x系列文章:
(一)Vert.x 简明介绍 https://blog.csdn.net/king_kgh/article/details/80772657
(二)Vert.x创建简单的HTTP服务 https://blog.csdn.net/king_kgh/article/details/80804078
(三)Vert.x Web开发之路由 https://blog.csdn.net/king_kgh/article/details/80848571
(四)Vert.x TCP服务实现 https://blog.csdn.net/king_kgh/article/details/84870775
(五)Vert.x数据库访问 https://blog.csdn.net/king_kgh/article/details/84894599
(六)Vert.x认证和授权 https://blog.csdn.net/king_kgh/article/details/85218454
(七)Vert.x事件总线(Event Bus)与远程服务调用 https://blog.csdn.net/king_kgh/article/details/86993812
Vert.x 案例代码:https://github.com/happy-fly
笔者就职于一家互联网支付公司,公司的核心项目使用的是Vert.x技术体系。记得笔者刚进入公司,接触Vert.x的时候,找遍了大大小小的网站,发现市面上关于Vert.x的文档除了官方文档外,几乎找不到其他资料。当时就励志要出一个专栏来写写Vert.x,以此帮助在Vert.x上采坑的朋友。因为笔者能力有限,文章中难免会有错误和疏漏,如果您对文章有意见或者好的建议,可以直接留言或者发送邮件到[email protected]。如果您也对Vert.感兴趣,可以加入到我们,共同学习Vert.x,并推进国内开发者对Vert.x的认知。