Incorporating Socket Programming into your Applications

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

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:

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
public class ServerActivity extends Activity {
 
     private TextView serverStatus;
 
     // DEFAULT IP
     public static String SERVERIP = "10.0.2.15" ;
 
     // DESIGNATE A PORT
     public static final int SERVERPORT = 8080 ;
 
     private Handler handler = new Handler();
 
     private ServerSocket serverSocket;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super .onCreate(savedInstanceState);
         setContentView(R.layout.server);
         serverStatus = (TextView) findViewById(R.id.server_status);
 
         SERVERIP = getLocalIpAddress();
 
         Thread fst = new Thread( new ServerThread());
         fst.start();
     }
 
     public class ServerThread implements Runnable {
 
         public void run() {
             try {
                 if (SERVERIP != null ) {
                     handler.post( new Runnable() {
                         @Override
                         public void run() {
                             serverStatus.setText( "Listening on IP: " + SERVERIP);
                         }
                     });
                     serverSocket = new ServerSocket(SERVERPORT);
                     while ( true ) {
                         // LISTEN FOR INCOMING CLIENTS
                         Socket client = serverSocket.accept();
                         handler.post( new Runnable() {
                             @Override
                             public void run() {
                                 serverStatus.setText( "Connected." );
                             }
                         });
 
                         try {
                             BufferedReader in = new BufferedReader( new InputStreamReader(client.getInputStream()));
                             String line = null ;
                             while ((line = in.readLine()) != null ) {
                                 Log.d( "ServerActivity" , line);
                                 handler.post( new Runnable() {
                                     @Override
                                     public void run() {
                                         // DO WHATEVER YOU WANT TO THE FRONT END
                                         // THIS IS WHERE YOU CAN BE CREATIVE
                                     }
                                 });
                             }
                             break ;
                         } catch (Exception e) {
                             handler.post( new Runnable() {
                                 @Override
                                 public void run() {
                                     serverStatus.setText( "Oops. Connection interrupted. Please reconnect your phones." );
                                 }
                             });
                             e.printStackTrace();
                         }
                     }
                 } else {
                     handler.post( new Runnable() {
                         @Override
                         public void run() {
                             serverStatus.setText( "Couldn't detect internet connection." );
                         }
                     });
                 }
             } catch (Exception e) {
                 handler.post( new Runnable() {
                     @Override
                     public void run() {
                         serverStatus.setText( "Error" );
                     }
                 });
                 e.printStackTrace();
             }
         }
     }
 
     // GETS THE IP ADDRESS OF YOUR PHONE'S NETWORK
     private String getLocalIpAddress() {
         try {
             for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
                 NetworkInterface intf = en.nextElement();
                 for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
                     InetAddress inetAddress = enumIpAddr.nextElement();
                     if (!inetAddress.isLoopbackAddress()) { return inetAddress.getHostAddress().toString(); }
                 }
             }
         } catch (SocketException ex) {
             Log.e( "ServerActivity" , ex.toString());
         }
         return null ;
     }
 
     @Override
     protected void onStop() {
         super .onStop();
         try {
              // MAKE SURE YOU CLOSE THE SOCKET UPON EXITING
              serverSocket.close();
          } catch (IOException e) {
              e.printStackTrace();
          }
     }
 
}

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:

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
public class ClientActivity extends Activity {
 
     private EditText serverIp;
 
     private Button connectPhones;
 
     private String serverIpAddress = "" ;
 
     private boolean connected = false ;
 
     private Handler handler = new Handler();
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super .onCreate(savedInstanceState);
         setContentView(R.layout.client);
 
         serverIp = (EditText) findViewById(R.id.server_ip);
         connectPhones = (Button) findViewById(R.id.connect_phones);
         connectPhones.setOnClickListener(connectListener);
     }
 
     private OnClickListener connectListener = new OnClickListener() {
 
         @Override
         public void onClick(View v) {
             if (!connected) {
                 serverIpAddress = serverIp.getText().toString();
                 if (!serverIpAddress.equals( "" )) {
                     Thread cThread = new Thread( new ClientThread());
                     cThread.start();
                 }
             }
         }
     };
 
     public class ClientThread implements Runnable {
 
         public void run() {
             try {
                 InetAddress serverAddr = InetAddress.getByName(serverIpAddress);
                 Log.d( "ClientActivity" , "C: Connecting..." );
                 Socket socket = new Socket(serverAddr, ServerActivity.SERVERPORT);
                 connected = true ;
                 while (connected) {
                     try {
                         Log.d( "ClientActivity" , "C: Sending command." );
                         PrintWriter out = new PrintWriter( new BufferedWriter( new OutputStreamWriter(socket
                                     .getOutputStream())), true );
                             // WHERE YOU ISSUE THE COMMANDS
                             out.println( "Hey Server!" );
                             Log.d( "ClientActivity" , "C: Sent." );
                     } catch (Exception e) {
                         Log.e( "ClientActivity" , "S: Error" , e);
                     }
                 }
                 socket.close();
                 Log.d( "ClientActivity" , "C: Closed." );
             } catch (Exception e) {
                 Log.e( "ClientActivity" , "C: Error" , e);
                 connected = false ;
             }
         }
     }
}

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!

So yes, happy coding everyone and hope this was interesting/helpful.

- jwei


你可能感兴趣的:(Incorporating Socket Programming into your Applications)