本文是我在学习Vert.x过程中的一些笔记,作为记录。
因为是初学,对Vert.x的理解还不够透彻,如有错误之处我们可以在评论中一起讨论呦。
环境准备
- JDK8+
- Maven
- IDE
- Vert.x 3.6.3
我们通常用到的最多的应该是Http服务,创建一个Http服务端似乎web开发中常有的事情。但是如果有一个需要Tcp服务的场景,这时候我们会想到Socket编程,基于Socket实现一个Tcp服务的过程是及其考验编程水平的,需要手动处理网络和线程问题。于是乎我们又想到了Netty,用Netty来实现Tcp服务似乎也不错啊,他简化了传统的Nio操作,但是如果没有接触过Netty则需要从头学习,学习成本较高。其实我们可以使用Vertx来创建Tcp服务,因为Vert.x本来就是基于Netty的,而且通过Vertx创建Tcp服务非常方便。
vertx中创建Tcp服务端
默认的创建方式如下:
NetServer netServer = vertx.createNetServer();
默认创建的Tcp服务端实际上是初始化了一个默认的NetServerOptions实例,Tcp服务端会随机选择一个本地未被占用的端口进行监听
当然我们也可以通过配置自定义属性来创建:
NetServer netServer = vertx.createNetServer(new NetServerOptions().setPort(9981));
//可以获取监听的端口
netServer.actualPort();
当创建Tcp服务端监听某一端口时我们注册一个处理器,当创建成功并开始监听时触发:
1 2 3 4 5 6 7 8
| //监听指定主机和端口,并且在监听开始时触发通知 vertx.createNetServer().listen(9983, "localhost", res -> { if (res.succeeded()) { System.out.println("Tcp服务端启动成功"); } else { System.err.println("Tcp服务端启动失败"); } });
|
当服务端创建成功后,有客户端请求进来,会触发相应的处理器,可以通过connectHandler
方法绑定处理器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| //绑定处理器,当有请求进入时触发 NetServer netServer = vertx.createNetServer().connectHandler(netSocket -> { //得到NetSocket实例 netSocket.handler(buffer -> { //读取数据 System.out.println("读取到数据:" + buffer.toString() + " 长度为: " + buffer.length()); }); netSocket.write(Buffer.buffer("数据已接收......"), ar -> { if (ar.succeeded()) { System.out.println("写入数据成功!"); } else { System.err.println("写入数据失败!"); } }); netSocket.closeHandler(ar -> { System.out.println("客户端退出连接"); }); }).listen(9984, "localhost");
|
Tcp客户端创建
客户端的创建方式与服务端类似,也有默认的创建方法和自定义的属性配置
1 2 3 4 5
| //默认客户端创建 NetClient netClient1 = vertx.createNetClient();
//自定义属性创建 NetClient netClient2 = vertx.createNetClient(new NetClientOptions().setConnectTimeout(10000));
|
创建Tcp客户端需要使用connect
方法连接到服务端后,才可以进行数据的收发
1 2 3 4 5 6 7 8
| NetClient client = vertx.createNetClient(new NetClientOptions().setConnectTimeout(10000)); client.connect(9984, "localhost", res -> { if (res.succeeded()) { System.out.println("连接成功!"); } else { System.out.println("连接失败: " + res.cause().getMessage()); } });
|
关闭Tcp连接
当请求结束时,可以调用close关闭服务端或者客户端
1 2 3 4 5 6 7 8 9 10 11 12
| //1.直接关闭 netServer.close();
//2.关闭结果打印通知 netServer.close(res -> { if (res.succeeded()) { System.out.println("关闭成功!"); } else { System.err.println("关闭失败!"); } });
|
项目创建
在IDEA中创建一个Maven工程,pom文件引入Vertx-core的依赖
1 2 3 4 5 6
| <dependency> <groupId>io.vertx</groupId> <artifactId>vertx-core</artifactId> <version>3.6.3</version> </dependency>
|
创建NetServerDemo.java文件,创建并部署Tcp服务端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| package com.zhengql.www;
import io.vertx.core.AbstractVerticle; import io.vertx.core.Vertx; import io.vertx.core.buffer.Buffer; import io.vertx.core.net.NetServer; import io.vertx.core.net.NetServerOptions;
/** * 描述: tcp * * @author zhengql * @date 2019/4/2 14:57 */ public class NetServerDemo extends AbstractVerticle {
public static void main(String[] args) { Vertx.vertx().deployVerticle(new NetServerDemo()); }
@Override public void start() throws Exception {
//绑定处理器,当有请求进入时触发 NetServer netServer = vertx.createNetServer().connectHandler(netSocket -> { //得到NetSocket实例 netSocket.handler(buffer -> { //读取数据 System.out.println("读取到数据:" + buffer.toString() + " 长度为: " + buffer.length()); });
netSocket.write(Buffer.buffer("数据已接收......"), ar -> { if (ar.succeeded()) { System.out.println("写入数据成功!"); } else { System.err.println("写入数据失败!"); } }); netSocket.closeHandler(ar -> { System.out.println("客户端退出连接"); }); }).listen(9984, "localhost", res -> { if (res.succeeded()) { System.out.println("Tcp服务端启动成功"); } else { System.err.println("Tcp服务端启动失败"); } }); } }
|
创建NetClientDemo.java文件,创建并部署Tcp客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| package com.zhengql.www;
import io.vertx.core.AbstractVerticle; import io.vertx.core.Vertx; import io.vertx.core.buffer.Buffer; import io.vertx.core.net.NetClient; import io.vertx.core.net.NetClientOptions; import io.vertx.core.net.NetSocket;
/** * 描述: * Tcp客户端 * * @author zhengql * @date 2019/4/2 15:39 */ public class NetClientDemo extends AbstractVerticle { public static void main(String[] args) { Vertx.vertx().deployVerticle(new NetClientDemo()); }
@Override public void start() throws Exception {
//创建连接到指定主机和端口的客户端,并绑定创建结果的处理器 NetClient netClient3 = vertx.createNetClient(new NetClientOptions().setConnectTimeout(10000)) .connect(9984, "localhost", res -> { if (res.succeeded()) { System.out.println("连接成功!"); NetSocket socket = res.result(); //向服务器写入数据 socket.write(Buffer.buffer("发送数据......"), ar -> { if (ar.succeeded()) { System.out.println("数据发送成功!"); } else { System.err.println("数据发送失败!"); } });
//读取服务端返回的数据 socket.handler(buffer -> { System.out.println("读取到数据:" + buffer.toString() + " 长度为: " + buffer.length()); }); socket.closeHandler(ar -> { System.out.println("客户端断开连接"); }); } else { System.out.println("连接失败!: " + res.cause().getMessage()); } }); } }
|
到此,服务端和客户端的代码已经编写完成
启动NetServerDemo,可以看到控制台中的日志打印如下:
在启动NetClientDemo,控制台打印如下:
客户端启动成功后,此时服务端的日志如下:
上面的代码创建了一个Tcp服务端和Tcp客户端,服务端监听本地的9984
端口,客户端与本地的9984端口的Tcp服务端建立连接后发送数据,
当接收到客户端的请求时打印其传来的消息“发送数据......”
,并回复“数据已接收......”
至此,一个基于Vert.x的Tcp服务端、客户端创建demo就完成了,是不是比Socket编程要简单很多呢?
资料参考
https://vertx.io/docs/
https://vertx.io/docs/vertx-core/java/