Android Client-Server Using Sockets – Server Implementation
In this Android Client-Server Using Sockets post series we will be focusing on server side implementation. We have covered Client side implementation in our previous post “Android Client-Server Using Sockets – Client Implementation” Android has very vast set of libraries so that users can implement innovative ideas with provided libraries. It is very easy to create server in android using these inbuilt library.
Implementation Details
In this tutorial we will be using java Sockets to achieve our server-client communication. One side there will be a server which will bind to specified port on device and will be available to client using IP address and port combination. Client will also use some random port for connection. Once connection is established from client side then server will replay to client with “Hello from Server, you are #%d” %d will be a number which will increment with each connection.
Note : This tutorial is based on Android Studio 2.2, Java 1.6 and Android 6.0.
Server Implementation
Implementing Server.java
This class contain all the implementation of server. In this class we will create object of “ServerSocket” in a separate thread. accept() function in ServerSocket waits for an incoming request and blocks until the connection is opened. This method returns a socket object representing the just opened connection. IP address and port number of client can be obtained from this socket.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
private class SocketServerThread extends Thread { int count = 0; @Override public void run() { try { // create ServerSocket using specified port serverSocket = new ServerSocket(socketServerPORT); while (true) { // block the call until connection is created and return // Socket object Socket socket = serverSocket.accept(); count++; message += "#" + count + " from " + socket.getInetAddress() + ":" + socket.getPort() + "\n"; activity.runOnUiThread(new Runnable() { @Override public void run() { activity.msg.setText(message); } }); SocketServerReplyThread socketServerReplyThread = new SocketServerReplyThread(socket, count); socketServerReplyThread.run(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } |
Next we will create object of “SocketServerReplyThread” which extends thread and we pass socket and count to the constructor. Next obtain OutputStream from Socket using getOutputStream() function. A PrintStream is now created using OutputStream object as the new print stream does not automatically flush its contents to the target stream when a newline is encountered. After that we print() replay on PrintStream and Stream is closed. Huhh so much of theory.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
private class SocketServerReplyThread extends Thread { private Socket hostThreadSocket; int cnt; SocketServerReplyThread(Socket socket, int c) { hostThreadSocket = socket; cnt = c; } @Override public void run() { OutputStream outputStream; String msgReply = "Hello from Server, you are #" + cnt; try { outputStream = hostThreadSocket.getOutputStream(); PrintStream printStream = new PrintStream(outputStream); printStream.print(msgReply); printStream.close(); message += "replayed: " + msgReply + "\n"; activity.runOnUiThread(new Runnable() { @Override public void run() { activity.msg.setText(message); } }); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); message += "Something wrong! " + e.toString() + "\n"; } activity.runOnUiThread(new Runnable() { @Override public void run() { activity.msg.setText(message); } }); } } |
At last we will need a method to get IP address of our server.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
public String getIpAddress() { String ip = ""; try { Enumeration<NetworkInterface> enumNetworkInterfaces = NetworkInterface .getNetworkInterfaces(); while (enumNetworkInterfaces.hasMoreElements()) { NetworkInterface networkInterface = enumNetworkInterfaces .nextElement(); Enumeration<InetAddress> enumInetAddress = networkInterface .getInetAddresses(); while (enumInetAddress.hasMoreElements()) { InetAddress inetAddress = enumInetAddress .nextElement(); if (inetAddress.isSiteLocalAddress()) { ip += "Server running at : " + inetAddress.getHostAddress(); } } } } catch (SocketException e) { // TODO Auto-generated catch block e.printStackTrace(); ip += "Something Wrong! " + e.toString() + "\n"; } return ip; } |
Full implementation of Server.java class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
package com.androidsrc.server; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketException; import java.util.Enumeration; public class Server { MainActivity activity; ServerSocket serverSocket; String message = ""; static final int socketServerPORT = 8080; public Server(MainActivity activity) { this.activity = activity; Thread socketServerThread = new Thread(new SocketServerThread()); socketServerThread.start(); } public int getPort() { return socketServerPORT; } public void onDestroy() { if (serverSocket != null) { try { serverSocket.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } private class SocketServerThread extends Thread { int count = 0; @Override public void run() { try { // create ServerSocket using specified port serverSocket = new ServerSocket(socketServerPORT); while (true) { // block the call until connection is created and return // Socket object Socket socket = serverSocket.accept(); count++; message += "#" + count + " from " + socket.getInetAddress() + ":" + socket.getPort() + "\n"; activity.runOnUiThread(new Runnable() { @Override public void run() { activity.msg.setText(message); } }); SocketServerReplyThread socketServerReplyThread = new SocketServerReplyThread(socket, count); socketServerReplyThread.run(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } private class SocketServerReplyThread extends Thread { private Socket hostThreadSocket; int cnt; SocketServerReplyThread(Socket socket, int c) { hostThreadSocket = socket; cnt = c; } @Override public void run() { OutputStream outputStream; String msgReply = "Hello from Server, you are #" + cnt; try { outputStream = hostThreadSocket.getOutputStream(); PrintStream printStream = new PrintStream(outputStream); printStream.print(msgReply); printStream.close(); message += "replayed: " + msgReply + "\n"; activity.runOnUiThread(new Runnable() { @Override public void run() { activity.msg.setText(message); } }); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); message += "Something wrong! " + e.toString() + "\n"; } activity.runOnUiThread(new Runnable() { @Override public void run() { activity.msg.setText(message); } }); } } public String getIpAddress() { String ip = ""; try { Enumeration<NetworkInterface> enumNetworkInterfaces = NetworkInterface .getNetworkInterfaces(); while (enumNetworkInterfaces.hasMoreElements()) { NetworkInterface networkInterface = enumNetworkInterfaces .nextElement(); Enumeration<InetAddress> enumInetAddress = networkInterface .getInetAddresses(); while (enumInetAddress.hasMoreElements()) { InetAddress inetAddress = enumInetAddress .nextElement(); if (inetAddress.isSiteLocalAddress()) { ip += "Server running at : " + inetAddress.getHostAddress(); } } } } catch (SocketException e) { // TODO Auto-generated catch block e.printStackTrace(); ip += "Something Wrong! " + e.toString() + "\n"; } return ip; } } |
Implementation of MainActivity.java class
The usage of server class is very simple. Just create a object of Server class and pass MainActivity instance in constructor and you are done. Here is what MainActivity.java looks like.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
package com.androidsrc.server; import android.os.Bundle; import android.app.Activity; import android.widget.TextView; public class MainActivity extends Activity { Server server; TextView infoip, msg; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); infoip = (TextView) findViewById(R.id.infoip); msg = (TextView) findViewById(R.id.msg); server = new Server(this); infoip.setText(server.getIpAddress() + ":" + server.getPort()); } @Override protected void onDestroy() { super.onDestroy(); server.onDestroy(); } } |
Other supporting components
Implementation of activity_main.xml file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginBottom="20dp" android:layout_marginTop="20dp" android:autoLink="web" android:text="http://androidsrc.net/" android:textStyle="bold"/> <TextView android:id="@+id/infoip" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" /> <ScrollView android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:id="@+id/msg" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </ScrollView> </LinearLayout> |
AndroidManifest.xml
We will need permission INTERNET to create Sockets. Don’t forget to include that permission in your manifest.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.androidsrc.server" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="19"/> <uses-permission android:name="android.permission.INTERNET"/> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme"> <activity android:name=".MainActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> </application> </manifest><br> |
Testing the application
To test this application install it on android device and install client on other device. Both device should be connected to same wifi network. Now just add IP address and port to client and click connect. Server will replay with a message to client. Thanks
Thanks. How to make the server always listening?
You can simply run a loop to keep receiving from client until ‘exit’ is received