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