Friday, November 9, 2012

java.lang.IllegalStateException while configuring Oracle NoSQL


“Big Data” is the well know terminology in today's IT industry. Many people are working in this area. It inspired me to do some experiments with Big Data and I started exploring Oracle NoSQL. Though its much simpler to install and use Oracle NoSQL, I face many challenges. One of them is here.

I came across below exception while configuring KV Store on my system.
Oracle NoSQL DB 11gR2.1.2.123 java.lang.IllegalStateException: unexpected exception creating environment java.lang.IllegalStateException: unexpected exception creating environment
 at oracle.kv.impl.admin.Admin.openEnv(Admin.java:407)
 at oracle.kv.impl.admin.Admin.renewRepEnv(Admin.java:335)
 at oracle.kv.impl.admin.Admin.(Admin.java:230)
 at oracle.kv.impl.admin.AdminService.configure(AdminService.java:252)
 at oracle.kv.impl.admin.CommandServiceImpl$33.execute(CommandServiceImpl.java:629)
 at oracle.kv.impl.fault.ProcessFaultHandler.execute(ProcessFaultHandler.java:142)
 at oracle.kv.impl.admin.CommandServiceImpl.configure(CommandServiceImpl.java:624)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 at java.lang.reflect.Method.invoke(Method.java:616)
 at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:322)
 at sun.rmi.transport.Transport$1.run(Transport.java:177)
 at java.security.AccessController.doPrivileged(Native Method)
 at sun.rmi.transport.Transport.serviceCall(Transport.java:173)
 at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:553)
 at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:808)
 at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:667)
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
 at java.lang.Thread.run(Thread.java:679)
Caused by: java.lang.ExceptionInInitializerError
 at com.sleepycat.je.rep.elections.Elections.(Elections.java:193)
 at com.sleepycat.je.rep.impl.node.RepNode.startup(RepNode.java:711)
 at com.sleepycat.je.rep.impl.node.RepNode.joinGroup(RepNode.java:1542)
 at com.sleepycat.je.rep.impl.RepImpl.joinGroup(RepImpl.java:459)
 at com.sleepycat.je.rep.ReplicatedEnvironment.joinGroup(ReplicatedEnvironment.java:414)
 at com.sleepycat.je.rep.ReplicatedEnvironment.(ReplicatedEnvironment.java:467)
 at com.sleepycat.je.rep.ReplicatedEnvironment.(ReplicatedEnvironment.java:332)
 at com.sleepycat.je.rep.ReplicatedEnvironment.(ReplicatedEnvironment.java:396)
 at oracle.kv.impl.admin.Admin.openEnv(Admin.java:380)
 ... 20 more
Caused by: com.sleepycat.je.EnvironmentFailureException: (JE 5.0.36) java.net.UnknownHostException: macmini-opensuse: macmini-opensuse UNEXPECTED_EXCEPTION: Unexpected internal Exception, may have side effects.
 at com.sleepycat.je.EnvironmentFailureException.unexpectedException(EnvironmentFailureException.java:286)
 at com.sleepycat.je.rep.elections.TimebasedProposalGenerator.(TimebasedProposalGenerator.java:107)
 ... 29 more
Caused by: java.net.UnknownHostException: macmini-opensuse: macmini-opensuse
 at java.net.InetAddress.getLocalHost(InetAddress.java:1426)
 at com.sleepycat.je.rep.elections.TimebasedProposalGenerator.(TimebasedProposalGenerator.java:62)
 ... 29 more
The problem is created due to not getting correct IP and host name binding. You will find the IP and host name binding in /etc/hosts file. The following steps helped me to solve the issue.

Get Host Name

Identify the host name of your system by using hostname command.
 $ hostname

Get IP address

Get IP address of your system using ifconfig command.
 $ ifconfig

Correct IP and host binding

Comment loopback addresses in your /etc/hosts file. It starts with '127.0.'. and add new line 'ipaddress hostname localhost'
#127.0.0.1 localhost
#127.0.1.1 localhost
192.168.50.50 localhost my-desktop
It solved my problem.

Friday, June 15, 2012

Rake: wrong number of arguments (3 for 2)

Rake is a simple ruby build program similar to make. There are many versions of Rake are available. If you are using Rake-0.9.x you might come to the error, “wrong number of arguments (1 for 0) (ArgumentError)”. While the same piece of code runs without error on Rake-0.8.x.

Here you will find the two methods to deal with this problem. The first one is simple, remove 0.9.x version and install 0.8.x version the latest one is in this series is 0.8.7.

$ gem uninstall rake –v 0.9.x
$ gem install rake –v 0.8.7

The second method is to use rake command with version number.
$ rake _0.8.7_

Monday, April 9, 2012

Hive ODBC Driver on Ubuntu

The Apache Hive is used for managing large datasets residing in distributed storage. It provides the SQL like query language (HiveQL) to interact with datasets. It also provides shell utility which can be used to run Hive queries. But if you need to use the HiveQL from other application/software, some short of driver is required.

The Hive ODBC Driver is a software library that implements the Open Database Connectivity (ODBC) Ahttp://www.blogger.com/img/blank.gifPI standard for the Hive database management systemhttp://www.blogger.com/img/blank.gif, http://www.blogger.com/img/blank.gifenabling ODBC compliant applications to interact seamlessly (ideally) with Hive through a standard interface.

To know how to install and use the driver, I have gone through https://cwiki.apache.org/Hive/hiveodbc.html. I followed the given steps using latest version of Hadoop, Hive and Thrift. But I could not get success to compile the code. After that I have gone through lot many internet pages and finally compiled the code.
http://www.blogger.com/img/blank.gif
The article describes the steps/method which I have used to compile the code.

I have experimented following steps on Ubuntu-10.10.

Install Apache Hadoop

Please refer http://hadoop.apache.org/common/docs/r0.20.2/quickstart.html to download and install the Apache Hadoop on Ubuntu.

Install Apache Hive

Please follow the instruction given on https://cwiki.apache.org/Hive/adminmanual-installation.html to download and install Apache Hive.

Install Thrift-0.5.0

1. Install required tools
$ sudo apt-get install libboost-dev libevent-dev python-dev automake pkg-config libtool flex bison
$ sudo apt-get install php5-dev
$ sudo apt-get install ant
$ sudo apt-get install openjdk-6-jdk
$ sudo apt-get install bjam
$ sudo apt-get install libboost-all-dev
2. Download Thrift-0.5.0
Get the source code for Thrift-0.5.0 from http://archive.apache.org/dist/incubator/thrift/0.5.0-incubating/thrift-0.5.0.tar.gz
3. Install Thrift
Make and install thrift after tar extraction with the following commands:
#Configure and build thrift compiler and libraries
$ cd thrift-0.5.0
$ ./configure –without-csharp –without-ruby –prefix=<thrift_install_path>
$ make
# Install thrift
$ make install
# Configure, build, and install fb303
$ cd contrib/fb303
$ ./bootstrap.sh
$ ./configure –with-thriftpath=<thrift_install_path> –prefix <thrift_install_path>
$ make && make install

Note: Solve compilation errors by including missing include files

Build and test Hive Client

Build the Hive client by running the following command from HIVE_HOME
$ ant compile-cpp -Dthrift.home=<THRIFT_HOME>

Execute the Hive client tests by running the following command from HIVE_HOME/odbc/
$ ant test -Dthrift.home=<THRIFT_HOME>

To install the Hive client libraries onto your machine, run the following command from HIVE_HOME/odbc/
$ sudo ant install -Dthrift.home=<THRIFT_HOME>

If you encounter any issue please refer “Hive Client Build/Setup” section on https://cwiki.apache.org/Hive/hiveodbc.html

Build Unix ODBC Wrapper

In the unixODBC root directory, run the following command:
$ ./configure –enable-gui=no –prefix=<unixODBC_INSTALL_DIR>

Compile the unixODBC API wrapper with the following:
$ make

Run the following from the unixODBC root directory:
$ sudo make install

If you encounter any issue please refer “unixODBC API Wrapper Build/Setup” section on https://cwiki.apache.org/Hive/hiveodbc.html

After compilation, the driver will be located at <UnixODBC_BUILD_DIR>/Drivers/hive/.libs/libodbchive.so.1.0.0.

You can manually install the unixODBC API wrapper by doing the following:
$ cp <UnixODBC_BUILD_DIR>/Drivers/hive/.libs/libodbchive.so.1.0.0 <SYSTEM_INSTALL_DIR>
$ cd <SYSTEM_INSTALL_DIR>
$ ln -s libodbchive.so.1.0.0 libodbchive.so
$ ldconfig

Connecting Driver to the Driver Manager

1. Export LD_LIBRARY_PATH and LD_PRELOAD with proper libraries
LD_LIBRARY_PATH should contain a list of directories having library file libodbchive.so, libhiveclient.so and libthrift.so. Generally all of these files are there in /usr/local/lib/
Use this command to export LD_LIBRARY_PATH:
$ export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH

After that run this command:
$ export LD_PRELOAD=/usr/local/lib/libodbchive.so
2. Connecting Driver to the Driver Manager

Connect the Driver to a Driver Manager as describe in “Connecting the Driver to a Driver Manager” section of https://cwiki.apache.org/Hive/hiveodbc.html.
3. Testing with ISQL
You will be able to interactively test the driver with isql by using following command:
$ isql -v Hive

Thursday, December 9, 2010

Create Ajax based CRUD using Rails 3

Ajax is well know for handling asynchronous request and Rails is for fast web development. Here I am going to create an application using Rails 3.0.1 which uses Ajax calls for CRUD operations.

1. Create the project


Crate the project address_book. Here I am using sqlite3 to store entries in address book
rails new address_book -d sqlite3

Change directory
cd address_book

Generate scaffold for address book’s Entry.
rails g scaffold Entry name:string address:text phone:string email:string

Now the skeleton for Entry has been created. Use ‘rake’ command to create necessary tables.
rake db:migrate

2. Change entries controller


As we are creating Ajax based CRUD, the application should respond to ‘.js’ format.
respond_to do |format|
format.html
format.js
end

Also we need to modify actions to handle CRUD Ajax requests. Modified entries controller(app/controllers/entries_controller.rb) looks like:
class EntriesController < ApplicationController
def index
@entry = Entry.new
@entries = Entry.all

respond_to do |format|
format.html
format.js
end
end

def show
@entry = Entry.find(params[:id])

respond_to do |format|
format.html
format.js
end
end

def new
@entry = Entry.new

respond_to do |format|
format.html
format.js
end
end

def edit
@entry = Entry.find(params[:id])
respond_to do |format|
format.html
format.js
end
end

def create
@entry = Entry.new(params[:entry])

respond_to do |format|
if @entry.save
format.html { redirect_to(@entry) }
format.js
else
format.html { render :action => "new" }
end
end
end

def update
@entry = Entry.find(params[:id])

respond_to do |format|
if @entry.update_attributes(params[:entry])
format.html { redirect_to(@entry) }
format.js
else
format.html { render :action => "edit" }
end
end
end

def destroy
@entry = Entry.find(params[:id])
@entry.destroy

respond_to do |format|
format.html { redirect_to(entries_url) }
format.js
end
end
end

3. Change Entry model


Define attributes in Entry model to access fields of entries table. Also put some validations on its fields.

Here is the modified Entry model(app/models/entry.rb)
class Entry < ActiveRecord::Base
attr_accessible :name, :address, :phone, :email
validates_presence_of :name, :phone, :email
end

4. Change in views


Now we modify index page(app/views/entries/index.html.erb) to show Entry form.
<h1>Listing entries</h1>

<table id="entries">
<tr>
<th>Name</th>
<th>Address</th>
<th>Phone</th>
<th>Email</th>
<th></th>
<th></th>
<th></th>
</tr>

<% @entries.each do |entry| %>
<%= render entry %>
<% end %>
</table>

<br />

<h2>Entry form</h2>
<div id="form">
<%= render :partial => "form" %>
</div>

In entries's index page you can see that we used id 'entries' with listing table, it is used to manipulate DOM object using jQuery.

Change form partial(app/views/entries/_form.html.erb) to generate remote POST request.
<%= form_for(@entry, :remote => true) do |f| %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :address %><br />
<%= f.text_area :address, :rows => 3 %>
</div>
<div class="field">
<%= f.label :phone %><br />
<%= f.text_field :phone %>
</div>
<div class="field">
<%= f.label :email %><br />
<%= f.text_field :email %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>

Create Entry partial(app/views/entries/_entry.html.erb) to list address book’s Entry.
Before going ahead, we should take care of two things: one is to update index page after receiving response of the Ajax request, and another is to send Ajax request to edit and destroy Entry.

Here we are updating index page by manipulating DOM object using jQuery. But, to manipulate DOM object, each row should be uniquely identified. So, we define unique 'id' attribute with each row.

To send Ajax request for editing and deleting Entry, use ':remote => true' parameter with Edit and Destroy link.

<tr id="<%= dom_id entry %>">
<td><%= entry.name %></td>
<td><%= entry.address %></td>
<td><%= entry.phone %></td>
<td><%= entry.email %></td>
<td><%= link_to 'Show', entry %></td>
<td><%= link_to 'Edit', edit_entry_path(entry), :remote => true %></td>
<td><%= link_to 'Destroy', entry, :confirm => 'Are you sure?', :method => :delete, :remote => true %></td>
</tr>

Now, write javascript templates to update index page.

Create app/views/entries/create.js.erb template to update the list on adding new Entry and clear the form.
$('<%= escape_javascript(render(:partial => @entry))%>').appendTo('#entries');
$("#new_entry")[0].reset();

Create app/views/entries/edit.js.erb template to set values into the form.
$("#form > form").replaceWith("<%= escape_javascript(render(:partial => "form"))%>")

Create app/views/entries/update.js.erb template to update the list with updated Entry, create new Entry and clear the form.
$("#<%= dom_id(@entry) %>").replaceWith("<%= escape_javascript(render(:partial => @entry)) %>");
<% @entry = Entry.new # reset for new form %>
$(".edit_entry").replaceWith("<%= escape_javascript(render(:partial => "form"))%>")
$(".new_entry")[0].reset();

Create app/views/entries/destroy.js.erb template to delete Entry from the list.
$('#<%= dom_id @entry %>').remove();

Modify application layout (app/views/layouts/application.html.erb) to include ‘rails’ and ‘application’ javascript.
<!DOCTYPE html>
<html>
<head>
<title>AddressBook</title>
<%= stylesheet_link_tag :all %>
<%= javascript_include_tag :defaults %>
<%= csrf_meta_tag %>
</head>
<body>

<%= yield %>

<%= javascript_include_tag "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" %>
<%= javascript_include_tag "rails" %>
<%= javascript_include_tag "application" %>

</body>
</html>

5. Replace ‘rails.js’



Replace rails javascript(public/javascripts/rails.js) with JQuery.
jQuery(function ($) {
var csrf_token = $('meta[name=csrf-token]').attr('content'),
csrf_param = $('meta[name=csrf-param]').attr('content');

$.fn.extend({
/**
* Triggers a custom event on an element and returns the event result
* this is used to get around not being able to ensure callbacks are placed
* at the end of the chain.
*
* TODO: deprecate with jQuery 1.4.2 release, in favor of subscribing to our
* own events and placing ourselves at the end of the chain.
*/
triggerAndReturn: function (name, data) {
var event = new $.Event(name);
this.trigger(event, data);

return event.result !== false;
},

/**
* Handles execution of remote calls firing overridable events along the way
*/
callRemote: function () {
var el = this,
data = el.is('form') ? el.serializeArray() : [],
method = el.attr('method') || el.attr('data-method') || 'GET',
url = el.attr('action') || el.attr('href');

if (url === undefined) {
throw "No URL specified for remote call (action or href must be present).";
} else {
if (el.triggerAndReturn('ajax:before')) {
$.ajax({
url: url,
data: data,
dataType: 'script',
type: method.toUpperCase(),
beforeSend: function (xhr) {
el.trigger('ajax:loading', xhr);
},
success: function (data, status, xhr) {
el.trigger('ajax:success', [data, status, xhr]);
},
complete: function (xhr) {
el.trigger('ajax:complete', xhr);
},
error: function (xhr, status, error) {
el.trigger('ajax:failure', [xhr, status, error]);
}
});
}

el.trigger('ajax:after');
}
}
});

/**
* confirmation handler
*/
$('a[data-confirm],input[data-confirm]').live('click', function () {
var el = $(this);
if (el.triggerAndReturn('confirm')) {
if (!confirm(el.attr('data-confirm'))) {
return false;
}
}
});


/**
* remote handlers
*/
$('form[data-remote]').live('submit', function (e) {
$(this).callRemote();
e.preventDefault();
});

$('a[data-remote],input[data-remote]').live('click', function (e) {
$(this).callRemote();
e.preventDefault();
});

$('a[data-method]:not([data-remote])').live('click', function (e){
var link = $(this),
href = link.attr('href'),
method = link.attr('data-method'),
form = $('<form method="post" action="'+href+'"></form>'),
metadata_input = '<input name="_method" value="'+method+'" type="hidden" />';

if (csrf_param != null && csrf_token != null) {
metadata_input += '<input name="'+csrf_param+'" value="'+csrf_token+'" type="hidden" />';
}

form.hide()
.append(metadata_input)
.appendTo('body');

e.preventDefault();
form.submit();
});

/**
* disable-with handlers
*/
var disable_with_input_selector = 'input[data-disable-with]';
var disable_with_form_selector = 'form[data-remote]:has(' + disable_with_input_selector + ')';

$(disable_with_form_selector).live('ajax:before', function () {
$(this).find(disable_with_input_selector).each(function () {
var input = $(this);
input.data('enable-with', input.val())
.attr('value', input.attr('data-disable-with'))
.attr('disabled', 'disabled');
});
});

$(disable_with_form_selector).live('ajax:after', function () {
$(this).find(disable_with_input_selector).each(function () {
var input = $(this);
input.removeAttr('disabled')
.val(input.data('enable-with'));
});
});
});

6. Set index page


To set entries index page as the application’s index page, set root entry into config/routes.rb file.
AddressBook::Application.routes.draw do
resources :entries
root :to => "entries#index"

Remove static index page from public folder.
rm public/index.html

Now your application is ready to run.

Tuesday, October 12, 2010

Uninstall all Ruby gems

Some time you may need to uninstall all the installed Ruby gems. Uninstalling individual gems is tedious job. Here you will find how to uninstall all the installed Ruby gems using single command.

First, we need a list of installed gems. Its easier to get list of installed gems by using the command:

gem list --no-version

The command to uninstall all the matching version of gems without any confirmation of dependencies and executables is:

gem uninstall -aIx GEM_NAME

Now, we use xargs command to uninstall all the installed gems:

gem list --no-version | xargs gem uninstall -aIx

If your system requires sudo privilege to uninstall gems use:

gem list –no-version | sudo xargs gem uninstall -aIxM

Thursday, September 23, 2010

Create TCP Echo Server using Libev

Libev provides APIs to write asynchronous socket programming. This article describes how to write a simple TCP echo server using libev.

Lets start to write simple asynchronous TCP echo server with the help of libev. The server accepts client connections, reads messages from connections and echo the same message back.

Steps to write TCP echo server:
  1. Create a server socket and bind to socket address
  2. Listen on server socket
  3. Create watcher to accept connection
  4. Write connection accept callback function
  5. Create and initialize watcher to read message from client
  6. Write callback function to read message
  7. Start event loop

1. Create a server socket and bind to socket address

First step is to create TCP internet socket and bind it to some port.
sd = socket(PF_INET, SOCK_STREAM, 0);

bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT_NO);
addr.sin_addr.s_addr = INADDR_ANY;

bind(sd, (struct sockaddr*) &addr, sizeof(addr));

2. Listen on server socket

To accept client connection, you need to start listing on server socket. Here we are using backlog of size 2.
listen(sd, 2);

3. Create watcher to accept connection

Now we accept client connection using 'accept' API. Before that, we create a watcher to keep watch on accept call. Initialize the watcher using server socket and connection accept callback function.
ev_io_init(&w_accept, accept_cb, sd, EV_READ);
ev_io_start(loop, &w_accept);

4. Write connection accept callback function

Write appropriate callback function to accept client connection.
void accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)
{
...
client_sd = accept(watcher->fd, (struct sockaddr *)&client_addr, &client_len);
...
}

5. Create and initialize watcher to read message from client

A new client socket is created on accepting the connection. To read messages from client, create a new watcher. Initialize it with client socket and read callback function.

w_client = (struct ev_io*) malloc (sizeof(struct ev_io));
...
ev_io_init(w_client, read_cb, client_sd, EV_READ);
ev_io_start(loop, w_client);

6. Write callback function to read message

Write appropriate read callback function to receive message from client and echo the same message back.
void read_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)
{
...
read = recv(watcher->fd, buffer, BUFFER_SIZE, 0);
send(watcher->fd, buffer, read, 0);
...
}

7. Start event loop

Final step is to run infinite event loop to wait for events.

while (1)
{
ev_loop(loop, 0);
}

Now we have done with server code.

Here is the complete code for the server.

#include <stdio.h>
#include <netinet/in.h>
#include <ev.h>

#define PORT_NO 3033
#define BUFFER_SIZE 1024

int total_clients = 0; // Total number of connected clients

void accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents);
void read_cb(struct ev_loop *loop, struct ev_io *watcher, int revents);

int main()
{
struct ev_loop *loop = ev_default_loop(0);
int sd;
struct sockaddr_in addr;
int addr_len = sizeof(addr);
struct ev_io w_accept;

// Create server socket
if( (sd = socket(PF_INET, SOCK_STREAM, 0)) < 0 )
{
perror("socket error");
return -1;
}

bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT_NO);
addr.sin_addr.s_addr = INADDR_ANY;

// Bind socket to address
if (bind(sd, (struct sockaddr*) &addr, sizeof(addr)) != 0)
{
perror("bind error");
}

// Start listing on the socket
if (listen(sd, 2) < 0)
{
perror("listen error");
return -1;
}

// Initialize and start a watcher to accepts client requests
ev_io_init(&w_accept, accept_cb, sd, EV_READ);
ev_io_start(loop, &w_accept);

// Start infinite loop
while (1)
{
ev_loop(loop, 0);
}

return 0;
}

/* Accept client requests */
void accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)
{
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
int client_sd;
struct ev_io *w_client = (struct ev_io*) malloc (sizeof(struct ev_io));

if(EV_ERROR & revents)
{
perror("got invalid event");
return;
}

// Accept client request
client_sd = accept(watcher->fd, (struct sockaddr *)&client_addr, &client_len);

if (client_sd < 0)
{
perror("accept error");
return;
}

total_clients ++; // Increment total_clients count
printf("Successfully connected with client.\n");
printf("%d client(s) connected.\n", total_clients);

// Initialize and start watcher to read client requests
ev_io_init(w_client, read_cb, client_sd, EV_READ);
ev_io_start(loop, w_client);
}

/* Read client message */
void read_cb(struct ev_loop *loop, struct ev_io *watcher, int revents){
char buffer[BUFFER_SIZE];
ssize_t read;

if(EV_ERROR & revents)
{
perror("got invalid event");
return;
}

// Receive message from client socket
read = recv(watcher->fd, buffer, BUFFER_SIZE, 0);

if(read < 0)
{
perror("read error");
return;
}

if(read == 0)
{
// Stop and free watchet if client socket is closing
ev_io_stop(loop,watcher);
free(watcher);
perror("peer might closing");
total_clients --; // Decrement total_clients count
printf("%d client(s) connected.\n", total_clients);
return;
}
else
{
printf("message:%s\n",buffer);
}

// Send message bach to the client
send(watcher->fd, buffer, read, 0);
bzero(buffer, read);
}


Below is the complete code for basic client which connect to server and, send and receive message. You can also write your own client.
#include <stdio.h>
#include <netinet/in.h>

#define PORT_NO 3033
#define BUFFER_SIZE 1024

int main()
{
int sd;
struct sockaddr_in addr;
int addr_len = sizeof(addr);
char buffer[BUFFER_SIZE] = "";

// Create client socket
if( (sd = socket(PF_INET, SOCK_STREAM, 0)) < 0 )
{
perror("socket error");
return -1;
}

bzero(&addr, sizeof(addr));

addr.sin_family = AF_INET;
addr.sin_port = htons(PORT_NO);
addr.sin_addr.s_addr = htonl(INADDR_ANY);

// Connect to server socket
if(connect(sd, (struct sockaddr *)&addr, sizeof addr) < 0)
{
perror("Connect error");
return -1;
}

while (strcmp(buffer, "q") != 0)
{
// Read input from user and send message to the server
gets(buffer);
send(sd, buffer, strlen(buffer), 0);

// Receive message from the server
recv(sd, buffer, BUFFER_SIZE, 0);
printf("message: %s\n", buffer);
}

return 0;
}