Incorporating Socket Programming into your Applications

Posted: June 15, 2011 in Android

Incorporating Socket Programming into your Applications

March 27, 2010

Hey everyone,

Haven’t posted in a while. Here’s something new that I came across and thought might be useful. This post is for anyone who has wanted to create an application that could communicate with another phone running your same application.

The idea involves Socket Programming and basically letting one phone be the “server” and the other phone be the “client”. Now, I don’t know if this is standard practice for letting two phones communicate with one another, but it worked for me in a new application that I’ve been working on, and so here it is:

001 public class ServerActivity extends Activity {
002
003     private TextView serverStatus;
004
005     // default ip
006     public static String SERVERIP = "10.0.2.15";
007
008     // designate a port
009     public static final int SERVERPORT = 8080;
010
011     private Handler handler = new Handler();
012
013     private ServerSocket serverSocket;
014
015     @Override
016     protected void onCreate(Bundle savedInstanceState) {
017         super.onCreate(savedInstanceState);
018         setContentView(R.layout.server);
019         serverStatus = (TextView) findViewById(R.id.server_status);
020
021         SERVERIP = getLocalIpAddress();
022
023         Thread fst = new Thread(new ServerThread());
024         fst.start();
025     }
026
027     public class ServerThread implements Runnable {
028
029         public void run() {
030             try {
031                 if (SERVERIP != null) {
032                     handler.post(new Runnable() {
033                         @Override
034                         public void run() {
035                             serverStatus.setText("Listening on IP: " + SERVERIP);
036                         }
037                     });
038                     serverSocket = new ServerSocket(SERVERPORT);
039                     while (true) {
040                         // listen for incoming clients
041                         Socket client = serverSocket.accept();
042                         handler.post(new Runnable() {
043                             @Override
044                             public void run() {
045                                 serverStatus.setText("Connected.");
046                             }
047                         });
048
049                         try {
050                             BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
051                             String line = null;
052                             while ((line = in.readLine()) != null) {
053                                 Log.d("ServerActivity", line);
054                                 handler.post(new Runnable() {
055                                     @Override
056                                     public void run() {
057                                         // do whatever you want to the front end
058                                         // this is where you can be creative
059                                     }
060                                 });
061                             }
062                             break;
063                         } catch (Exception e) {
064                             handler.post(new Runnable() {
065                                 @Override
066                                 public void run() {
067                                     serverStatus.setText("Oops. Connection interrupted. Please reconnect your phones.");
068                                 }
069                             });
070                             e.printStackTrace();
071                         }
072                     }
073                 } else {
074                     handler.post(new Runnable() {
075                         @Override
076                         public void run() {
077                             serverStatus.setText("Couldn't detect internet connection.");
078                         }
079                     });
080                 }
081             } catch (Exception e) {
082                 handler.post(new Runnable() {
083                     @Override
084                     public void run() {
085                         serverStatus.setText("Error");
086                     }
087                 });
088                 e.printStackTrace();
089             }
090         }
091     }
092
093     // gets the ip address of your phone's network
094     private String getLocalIpAddress() {
095         try {
096             for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
097                 NetworkInterface intf = en.nextElement();
098                 for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
099                     InetAddress inetAddress = enumIpAddr.nextElement();
100                     if (!inetAddress.isLoopbackAddress()) { return inetAddress.getHostAddress().toString(); }
101                 }
102             }
103         } catch (SocketException ex) {
104             Log.e("ServerActivity", ex.toString());
105         }
106         return null;
107     }
108
109     @Override
110     protected void onStop() {
111         super.onStop();
112         try {
113              // make sure you close the socket upon exiting
114              serverSocket.close();
115          } catch (IOException e) {
116              e.printStackTrace();
117          }
118     }
119
120 }

Before moving on to the client side of things, let’s just try and digest this together (for those who are familiar to Socket Programming much of this will look familiar – this is simply meant to be an integration of Socket Programming with the Android platform). In our onCreate() method we first retrieve the IP address that the phone designated as the “server” is on. This will work regardless of whether you’re on WIFI or 3G and is required for the client to connect to you. As soon as I get the IP address I kick off the server thread. Notice that it’s important you open and close all of the connections in a thread as the call:

1 Socket client = serverSocket.accept();

is blocking / synchronous / will stop the progression of your code until an incoming client is found. You definitely don’t want to put this on the UI thread as it will completely choke up your application, and so we throw it into a background thread. Now, the thread itself is pretty self explanatory. Notice how all of the serverStatus text updates are wrapped around handlers (this is necessary as you can’t touch views in the UI from a different thread without a handler). Then, once the client is retrieved, we open an inputStream() from the client and use a BufferedReader to retrieve incoming messages from the client.

This is where you can be creative.

You can do pretty much whatever you want at this point. Namely, you could create a mini scripting language (i.e. send messages like “GO BACK”, “TURN LEFT”, “START MUSIC”, “GO TO URL xxx”, etc) and have the server phone respond to those messages, and you could even have the server write messages to the client as well and have the client respond to those messages. Basically, everything before hand was just the annoying technical stuff that is required for the connection between the two phones to get established – once it is established you can send whatever form of data between the two phones as you’d like and this is where you can have fun in your future applications.

The last thing to notice is just that we override onStop() to close the serverSocket. Again, the serverSocket.accept() call is blocking, and so if we don’t close the serverSocket upon stopping the Activity it will actually continue to listen for incoming clients (until your phone kills that thread of course) and this can be problematic as it will block all future attempts to connect to the port number you designated.

Now for the client side of things:

01 public class ClientActivity extends Activity {
02
03     private EditText serverIp;
04
05     private Button connectPhones;
06
07     private String serverIpAddress = "";
08
09     private boolean connected = false;
10
11     private Handler handler = new Handler();
12
13     @Override
14     protected void onCreate(Bundle savedInstanceState) {
15         super.onCreate(savedInstanceState);
16         setContentView(R.layout.client);
17
18         serverIp = (EditText) findViewById(R.id.server_ip);
19         connectPhones = (Button) findViewById(R.id.connect_phones);
20         connectPhones.setOnClickListener(connectListener);
21     }
22
23     private OnClickListener connectListener = new OnClickListener() {
24
25         @Override
26         public void onClick(View v) {
27             if (!connected) {
28                 serverIpAddress = serverIp.getText().toString();
29                 if (!serverIpAddress.equals("")) {
30                     Thread cThread = new Thread(new ClientThread());
31                     cThread.start();
32                 }
33             }
34         }
35     };
36
37     public class ClientThread implements Runnable {
38
39         public void run() {
40             try {
41                 InetAddress serverAddr = InetAddress.getByName(serverIpAddress);
42                 Log.d("ClientActivity", "C: Connecting...");
43                 Socket socket = new Socket(serverAddr, ServerActivity.SERVERPORT);
44                 connected = true;
45                 while (connected) {
46                     try {
47                         Log.d("ClientActivity", "C: Sending command.");
48                         PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket
49                                     .getOutputStream())), true);
50                             // where you issue the commands
51                             out.println("Hey Server!");
52                             Log.d("ClientActivity", "C: Sent.");
53                     } catch (Exception e) {
54                         Log.e("ClientActivity", "S: Error", e);
55                     }
56                 }
57                 socket.close();
58                 Log.d("ClientActivity", "C: Closed.");
59             } catch (Exception e) {
60                 Log.e("ClientActivity", "C: Error", e);
61                 connected = false;
62             }
63         }
64     }
65 }

Overall pretty simple. Just create some kind of EditText field that allows the user to input the correct IP address (which should be showing on the server phone) and then some kind of button that grabs the inputted IP address and tries to kick off a client thread which attempts to connect to that IP address on the specified port. Notice that the port numbers have to be the same in addition to the IP address. Once a connection has been made then everything else is pretty simple – just create an OutputStreamWriter and a BufferedWriter that allows you to send messages to the server. Then once the server receives those messages, it can respond to them in whatever way you want it to!

So yes, basically this code snippet / example is for anyone who wants to write some kind of application that works best when two phones are connected or talking to each other. Again, I’m not sure if this is how you’re supposed to go about it, but after searching for a while and eventually giving up and then finally coming across this Socket Programming idea in one of my classes, it seems like this method at least works!

Reference

http://thinkandroid.wordpress.com/2010/03/27/incorporating-socket-programming-into-your-applications/

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s