Wednesday, February 11, 2015

libuv intro : UDP Server based on libuv

This tutorial is about how to write a UDP Server in C that is based on asynchronous I/O. I would be introducing libuv briefly, explaining those concepts that are mainly required to write the UDP server. The detailed introduction and API documentation is available on the internet.

Event Driven Programming: In a event driven programming, a user register a set of events(in which he is interested in ) and callbacks to those events. In our case, libuv is responsible for gathering events from the operating system and monitoring them. Some of the examples of event loop are file is ready for writing, timer timed out, socket has data ready to be read, etc. When the registered events occur the callbacks invoked by the user are invoked.
Libuv uses asynchronous, non-blocking style to deal with events and callback. Not getting into the details or advantages of it, you can find plenty of articles and blog on it.

#include <stdio.h>
#include <stdlib.h>
#include <uv.h>
int main() {
uv_loop_t *loop;
loop = malloc(sizeof(uv_loop_t));
//Initializes the given uv_loop_t structure
uv_loop_init(loop);
//runs the event loop
uv_run(loop, UV_RUN_DEFAULT);
uv_loop_close(loop);
free(loop);
return 0;
}
view raw sample_1.c hosted with ❤ by GitHub
Networking: 
#include <uv.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_DATA_SIZE 512
void sigint_handler(uv_signal_t *handle, int signum) {
printf("sigint_handler() : recvd CTRL+C shutting down\n");
uv_stop(uv_default_loop()); //stops the event loop
}
void alloc_recv_buf(uv_handle_t *receive_handle, size_t suggested_size,
uv_buf_t *buf) {
buf->base = (char*) malloc(sizeof(char)*MAX_DATA_SIZE);
buf->len = MAX_DATA_SIZE;
}
void udp_receive_callback(uv_udp_t *handle, ssize_t nread, const uv_buf_t *buf,
struct sockaddr *addr, unsigned flags) {
printf("udp_receive_callback() : start \n");
char string[MAX_DATA_SIZE];
strncpy(string, buf->base, nread);
string[nread]='\0';
printf("Recvd : size:%d\tdata:%s\n", nread, string);
free(buf->base);
printf("udp_receive_callback() : end\n");
}
int main(int argc, char** argv){
uv_signal_t sigint; //signal handle type
uv_udp_t udp_handle; //UDP handle type
struct sockaddr_in server_addr;
uv_loop_t *loop; //loop data type
loop = uv_default_loop(); //Returns the initialized default loop
uv_signal_init(loop, &sigint);//Initialize the handle
//Start the handle with the given callback, watching for the given signal.
uv_signal_start(&sigint, sigint_handler, SIGINT);
//Convert a string containing an IPv4 addresses to a binary structure
uv_ip4_addr("0.0.0.0", 9000, &server_addr);
printf("main() : uv_sgnal_init() & uv_signal_start() : OK\n");
uv_udp_init(loop, &udp_handle); //Initialize a new UDP handle
//Bind the UDP handle to an IP address and port.
uv_udp_bind(&udp_handle, (struct sockaddr *)&server_addr, 0);
printf("main() : uv_udp_init() & uv_udp_bind() : OK\n");
//Prepare for receiving data.
uv_udp_recv_start(&udp_handle, alloc_recv_buf, udp_receive_callback);
//runs the event loop.
uv_run(loop, UV_RUN_DEFAULT);
return 0;
}
view raw udp_server.c hosted with ❤ by GitHub

Hope you find this useful.