Vert.x创建TCP服务端及客户端

本文是我在学习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/

---------- 😏本文结束  感谢您的阅读😏 ----------
评论