TCP client and server
Overview
This simple tutorial demonstrates how Mongoose Library can be used to implement TCP clients and servers, even over TLS.
- We create a client and a server.
- The client connects to the server and after a brief interval sends some text.
- The server echoes that text back and the client disconnects.
This dialog will be encrypted if the code is compiled with support for TLS.
Initialization and main loop
In the main()
function we first initialize an event manager:
To support TLS, we initialize the client and server context. For more information, check the TLS tutorial
Then we create a timer to handle reconnections, start our server, and start the event loop.
We pass the timer creation function a pointer to the event manager, as we will need it later to create the client connection.For information on using timers, check the timers tutorial.
Starting the server at the main function
- The server connection is created by listening on a port; by calling mg_listen() and passing it a pointer to the URL, and a pointer to the event handler function, with an optional argument.
We do that in the
main()
function
Server event handler
The server event handler function is called by the event manager every time there is an event to be handled, here we will use:
MG_EV_ERROR
: There was an error, an error reason is passed as achar *
pointer in parameterev_data
; check the error handling tutorial for more information.MG_EV_OPEN
: The connection has been created, or initialized after a closure. Here we will also check for theis_listening
flag to detect the creation call and log itMG_EV_ACCEPT
: The server accepted a connection from a client. If the code has been compiled with TLS support, we initialize TLS by calling mg_tls_init(). This is only required here because we are serving our own protocol over TCP; the HTTP server, for example, does not need this step.MG_EV_READ
: There is outstanding data, received from the socket. We will log it and echo it back by calling mg_send() with a pointer to the data and the number of bytes to be sent. We indicate Mongoose that we have consumed that data (so it can clear its buffers) by setting the received data length to zero:r->len = 0
MG_EV_CLOSE
: The connection has closed
Starting the client at a timer event handler
The timer event handler implements the reconnection logic. It creates a client connection c_res.c
if it is NULL. This pattern should be used for any type of client connection that must be kept alive and is explained in the error handling tutorial.
- The client connection is created by calling mg_connect() and passing it a pointer to the URL, and a pointer to the event handler function, with an optional argument. In our case, we'll be passing it a structure providing a place where to hold the connection handler and an integer for internal use.
- When the client will finish, it will close the connection and set
c_res.c
to NULL, so the next timer event handler run will detect this and restart the connection.
Client event handler
The client event handler function is called by the event manager every time there is an event to be handled, here we will use:
MG_EV_ERROR
: There was an error, an error reason is passed as achar *
pointer in parameterev_data
; check the error handling tutorial for more information.MG_EV_OPEN
: The connection has been createdMG_EV_CONNECT
: The client has connected to a server. If the code has been compiled with TLS support, we initialize TLS by calling mg_tls_init(). This is only required here because we are using our own protocol over TCP; HTTP and MQTT clients, for example, do not need this step. We also set our variablei
to a value different than 0 so we know we have to do something later.MG_EV_READ
: There is outstanding data, received from the socket. We will just log it. We indicate Mongoose that we have consumed that data (so it can clear its buffers) by setting the received data length to zero:r->len = 0
MG_EV_CLOSE
: The connection has closedMG_EV_POLL
: The event manager is polling us at its timeout interval. We'll take advantage of this call to do something. For example, we'll count polls to roughly wait for 5 seconds and send some data, then wait another 5 seconds and close the connection. We signal the event manager we want to drain and close the connection by setting theis_draining
flag.
Build and run
Follow the Build Tools tutorial to setup your development environment.
Start a terminal in the project directory; if you've not already done so, clone the Mongoose Library repo
git clone https://github.com/cesanta/mongoose
Build and run the example:
cd mongoose/examples/tcp make clean all
Observe the log
74787e5 2 main.c:53:sfn SERVER is listening 7478849 2 main.c:19:cfn CLIENT has been initialized 747884a 2 main.c:86:timer_fn CLIENT is connecting 747884a 2 main.c:21:cfn CLIENT connected 747885d 2 main.c:55:sfn SERVER accepted a connection 7479ab1 2 main.c:40:cfn CLIENT sent data 7479ab1 2 main.c:66:sfn SERVER got data: Hi, there 7479ab1 2 main.c:29:cfn CLIENT got data: Hi, there 747acb2 2 main.c:31:cfn CLIENT disconnected 747acb3 2 main.c:69:sfn SERVER disconnected
Build with TLS support
Check the "How to build" section of the TLS tutorial for specific information on building options for your OS
For more information on developing TLS clients and servers, check the TLS tutorial