TCP Client using Vertx, Kotlin and Gradle build

Vertx Kotlin Gradle

As part of my hobby project to control RaspberryPi using Google Home Mini and/or Alexa, I wanted to write a very simple TCP client that keeps a connection open to one of my custom written server in cloud (I will write another blog post to cover the server side on a later date). The requirement of the client is to send a shared secret upon connecting and then keep waiting for message from server. Vert.x, Kotlin and Gradle allow rapid development of such project. The generated jar can be executed on Raspberry Pi. These steps outline the project setup and related source code to showcase a Vert.x and Kotlin project with Gradle.

Project Directory Structure

From command line (or via Windows Explorer, whatever you prefer to use) create a directory for project,for instance vertx-net-client. Since we are using Kotlin, we will place all Kotlin files in src/main/kotlin folder. The src/main/resources folder will contain our logging configuration related files.

cd vertx-net-client
mkdir -p src/main/kotlin
mkdir -p src/main/resources

Project Files

We need to add following files in the project

  • .gitignore If you want to check your project into git, you may consider adding following .gitignore file at root of your project
  • logback.xml This example is using slf4j and logback for logging. If you decide to use it in your project, you may also add following logback.xml file in src/main/resources. Modify it as per your requirements. This example will log on console.

Gradle Setup

We will use Gradle build system for this project. If you don’t already have Gradle available on your system, download and unzip gradle in a directory of your choice ($GRADLE_HOME is used here to represent this directory). This gradle distribution will be used as a starting point to create Gradle wrapper scripts for our project. These scripts will allow our project to download and use correct version of gradle distribution automatically without messing up system. Really useful when building your project on CI tool or on any other developer's machine.

Run following command in project's directory

$GRADLE_HOME/bin/gradle wrapper

The above commands will generate following files and directories.

gradle/  gradlew  gradlew.bat

Gradle build file build.gradle

Create (and/or copy and modify) following build.gradle in your project's root directory. Our example gradle build file is using vertx-gradle-plugin.

In the project directory, run following command to download local gradle distribution:

./gradlew

(or .\gradlew.bat if in Windows)

At this stage we should have following file structure. This is also a good time to commit changes if you are working with git.

  • .gitignore
  • build.gradle
  • gradle/wrapper/gradle-wrapper.jar
  • gradle/wrapper/gradle-wrapper.properties
  • gradlew
  • gradlew.bat
  • src/main/resources/logback.xml

Now that our project structure is ready, time to add the meat of the project. You may use any IDE of your choice. My preference is IntelliJ IDEA.

Create a new package under src/main/kotlin. The package name should be adapted from the following section of build.gradle

vertx {
    mainVerticle = "info.usmans.blog.vertx.NetClientVerticle"
}

From the above example, the package name is info.usmans.blog.vertx

Add a new Kotlin Class/file in src/main/kotlin/info/usmans/blog/vertx as NetClientVerticle.kt

The contents of this class is as follows

Explaining the Code

The fun main(args: Array<String>) is not strictly required, it quickly allows running the Vert.x verticle from within IDE. You will also notice a small hack in the method for setting system property vertx.disableDnsResolver which is to avoid a Netty bug that I observed when running on Windows machine and remote server is down. Of course, since we are using vertx-gradle-plugin, we can also use gradle vertxRun to run our verticle. In this case the main method will not get called.

The override fun start() method calls fireReconnectTimer which in turn calls reconnect method. reconnect method contains the connection logic to server as well as it calls fireReconnectTimer if it is unable to connect to server or disconnects from server. In reconnect method the socket.handler gets called when server send message to client.

socket.handler({ data ->
                        logger.info("Data received: ${data}")
                        //TODO: Do the work here ...
               })

Distributing the project

To create redistributable jar, use ./gradlew shadowJar command. Or if using IntelliJ: from Gradle projects, Tasks, shadow, shadowJar (right click run). This command will generate ./build/libs/vertx-net-client-fat.jar.

Executing the client

The client jar can be executed using following command:

 java -DserverHost=127.0.0.1 -DserverPort=8888 -DconnectMessage="hello" -jar vertx-net-client-full.jar

If you wish to use SLF4J for Vert.x internal logging, you need to pass system property vertx.logger-delegate-factory-class-name with value of io.vertx.core.logging.SLF4JLogDelegateFactory. The final command would look like:

java -DserverHost=127.0.0.1 -DserverPort=8888 -DconnectMessage="hello" -Dvertx.logger-delegate-factory-class-name="io.vertx.core.logging.SLF4JLogDelegateFactory" -jar vertx-net-client-full.jar

You can configure Vert.x logging levels in logback.xml file if required.

Conclusion

This post describes how easy it is to create a simple TCP client using Vert.x, Kotlin and Gradle build system. Hopefully the techniques shown here will serve as a starting point for your next DIY project.