How build your own TCP Server/Client interface with Android – Part 1

 

http://blog.laptopmag.com/wpress/wp-content/uploads/2013/08/android-server-how-to-sf.jpg

There are many providers of back-end services for mobile applications. Many I have both grown to love and hate. I’ve heard nothing but great things about Mongo DB and those who have scaled their app’s incredibly well. Similarly, I’ve begun using Parse as a means for cross platform back-end operations as well as ease-of-use with fast development times being a concern. However, shouldn’t we as programmers want to understand how such complex services work? After all, without such services we would have to build each server we need for back-end info and then a corresponding client to handle that specific data. For learning purposes, understanding a cloud based back-end of applications is essential in knowledge of networking and how to better improve such facilities. Plus, after you get one running, you feel like a god.

Building both a client and a server take an extensive amount of time if you’re unsure as to what you’re doing. Instead of just spitting code at you, I’m going to write more on the process of how a Server/Client works and show necessary code to reinforce any concept. Lets begin with the library we’re using called Java.NIO . At the link provide, you can find reference to any of the classes I mention here. You’ll need to build two classes: a Server class and a Client class. Both should be runnable and will incorporate the same basic data handling idea. Hence, I will be mainly writing in terms of the client you would add to the application you’re working on for android in this tutorial. If you understand the concept, implementing a server side will follow suit, apart from the app logic itself.

To begin, create a Client as a runnable.

 

public class TutClient implements Runnable {
  SocketChannel socketChannel = null;
  Selector selector = null;
  ByteBuffer buffer = ByteBuffer.allocate(1024);
public TutClient(){
}

@Override
public void run() {
  clientInit()
}
}

 

Each Client will need both a SocketChannel and a Selector for that Channel. Channels can be thought of – though are not the same – as a stream in c++. You can have many different types of Channels such as FileChannels, PipeChannels, etc. Since we’ll be communicating across the web with sockets, we’ll be using the SocketChannel. For the server side, remember it’s vary similar, but one of the biggest differences is the type of Channel is actually a ServerSocketChannel. Each channel can be used to interact with data coming from various channels. Selectors are channel type independent, usually one could be used for multiple channels when reassigned. Since in our client we only have one Channel for the Socket we connect too, this doesn’t matter too much. Lastly, we have the Buffer. Since we’re sending different types of data across the channel, the only reasonable and efficient way of doing this would be as byte arrays. On the other end, or the server side, they can be converted to whatever they’re actual form is. We store these Bytes in a Buffer since the amount of data sent could change rapidly and we might not know what we’re getting! So make sure to allocate a buffer you think will withstand most of your data!

private void clientInit(){

  try{
    socketChannel = SocketChannel.open();
    socketChannel.configureBlocking(false);
    try{
      socketChannel.specficconnect(new InetSocketAddress("192.168.0.18", 1998)); // InetSocketAddres(Host, Port);
    
    } catch (ConnectionPendingException e){
      e.printStackTrace();
    }

    selector = Selector.open();

    socketChannel.register(selector, SelectionKey.OP_CONNECT);

    // servers.add(socketChannel.socket());   // added as a means to save socket info NOT REQUIRED
 
  }catch(IOException e){
    Log.i(TAG, "Client Failed To Establish with Host");
    e.printStackTrace();
  }

}

 

Here’s where you establish your connection to the server you’ve created. By running the SocketChannel.open() and setting it equal to the socketChannel you’ve create, you’re establishing a unconnected channel awaiting a connection. Additionally, you’re specifying in the next line that you’d like the IO to be non-blocking meaning the client can handle more than one request at a time. This is extremely important as many – if not all – client/servers use non blocking IO.
Next, you’ll want to actually connect! The cool part about this is it doesn’t have to be a server you’ve created. If you want, you can connect to “google.com” and if you know what you’re looking for in terms of requests, you can send it data and retrieve your search results! Clients don’t have to connect to a server you create, they are just meant to handle data received from a server. After attempting the connection, you need to open the selector for binding to a specific Channel. After that’s complete, you can register the selector with the socketChannel and set it’s selection key to OP_CONNECT.

Each Server/Client has a series of keys that help both the server and client respond to specific requests. They are as follows: OP_CONNECT, OP_ACCEPT, OP_READ, OP_WRITE

Here, we set the socketChannel to OP_CONNECT so the Server knows you’d like to establish a connection when receives the request.

Now that we’ve established a connection, we need to handle the data flow in the main run() loop.

	@Override
	public void run() {
		init_Connection();
		
		while(true){
        	
			try {
				selector.select();
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
        	
			Iterator i = selector.selectedKeys().iterator();
			
			while(i.hasNext()){
				SelectionKey key = (SelectionKey) i.next();
				i.remove();
				
				if(key.isConnectable()){
                                    prepareConnection(key);
				} else if(key.isReadable()){
			            // Handle if readable
				} else if(key.isWritable()){
				    // Handle if writable	
				}
			}
		}
	}

 

This will run until the application you’ve placed the client in ends, such that the while continues while true is a real thing… At the beginning of the loop, we select a set of keys from the selector. Because this channel is non blocking, it could have loaded many keys into the selector by now. Remember each key contains the OP’s listed above and have specific information in regards to the server and the operation itself. If we are reading data from the server, the OP is OP_READ and it will hit the key.isReadable() block, if it’s set to OP_WRITE and we’ve sent our client something to send to the Server the clients key will be OP_WRITE. There will actually be a specific function within the client that handles sending bytes to the server, we would place it within that key.isWritable() block and it would execute only when we call it.

After we’ve set up our connection, we need to complete the connection over the channel. We did the first have by connecting the Channel and registering the selector, but how do we know we connected?

	private void prep_connection(SelectionKey key){
		try {
			if(socketChannel.finishConnect()){
				key.interestOps(SelectionKey.OP_READ);
				System.out.println("Connected!");
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			key.cancel();
			Log.d("Client", e.getCause().toString());
		}
	}

If the socketChannel connects and receives the confirmation back from the server, the connection establishment will finish. This actually gets the results from the SocketChannel.connect() method we called earlier. Since our channel is in non-blocking IO mode, if the connection has yet to be established by this time, it will automatically return false and potentially will hit that exception block. It would only hit the exception if the channel itself is already closed in which case it should cancel the key that’s been passed. This will null the any further operations and since the client won’t be connected to anything, the clients purpose will have ended.

All we need left in terms of code is handling both the reads and the writes. However, it’s simply too much to cover in one part of a tutorial. In the next tutorial we’ll write the function placed inside the key. blocks and connect to google.com to see if we can get some information. Until then, try connecting to a website of your choice and see if it sends you anything. If you place a simple acknowledgment output statement in the key.isReadable() block, you’ll know they are sending you something though you won’t be able to read it just yet!

References:

1.) http://developer.android.com/reference/java/nio/channels/package-summary.html

2.) http://rox-xmlrpc.sourceforge.net/niotut/

3.) https://docs.oracle.com/javase/7/docs/api/java/nio/channels/SocketChannel.html

4.) http://tutorials.jenkov.com/java-nio/index.html

5.) http://www.onjava.com/pub/a/onjava/2002/09/04/nio.html?page=2