Introduction to Socket Programming in Android Jules White Bradley Dept. of Electrical and Computer Engineering Virginia Tech julesw@vt.edu What is a Socket? • A socket is a software endpoint that can plug into or be plugged into to create a bi-directional communication link between software processes • A socket is a common interface for performing network communication • Underneath the hood, Android’s HTTP client library is using sockets to send and receive data Socket Socket Java Sockets • In Java, a ServerSocket can receive new connections from a client • A client connects to a remote ServerSocket through a standard Socket instance • When the server receives the connection, it talks to the client using a standard socket Socket Server Socket InputStreams in Java • An InputStream is a stream of incoming byte data • An InputStream can be obtained from a Socket by using the getInputStream() method • In order to read from a stream, you must create a byte buffer to read in data • Each call to read on an InputStream fills your buffer with data and returns the number of bytes read InputStream in = somesocket.getInputStream(); byte[] buffer = new byte[1024]; int bytesread = 0; while( (bytesread = in.read(buffer,0,buffer.length)) != -1){ //the buffer has been filled, do something with the data } OutputStreams in Java • An OutputStream is a stream of outgoing byte data • An OutputStream can be obtained from a Socket by using the getOutputStream() method • You can write data to a stream by passing in a byte buffer of data • You should use the flush() method if you want to make sure that the data you have written has been output to disk or sent to the other end of the socket OutputStream out = somesocket.getOutputStream(); out.write(“Hello Socket”.getBytes()); out.flush(); byte[] buffer = new byte[1024]; //fill the buffer out.write(buffer,0,buffer.length); out.close(); A Simple Socket-based Server • Example: public class ExampleServerSocket{ public void start() throws Exception { //Create a ServerSocket on port 9090 ServerSocket serversock = new ServerSocket(9090); while(running){ Socket client = serversock.accept(); OutputStream out = client.getOutputStream(); InputStream in = client.getInputStream(); //read and write some data from the streams out.close(); in.close(); client.close(); } } } A Simple Socket-based Client • Example: public class ExampleSocketClient{ public void start() throws Exception { Socket server = Socket( “127.0.0.1”, //the host or IP address to connect to 9090 //the port to connect to on that host ); OutputStream out = server.getOutputStream(); InputStream in = server.getInputStream(); out.write(“foo”.getBytes()); out.flush(); //VERY IMPORTANT // read some stuff…. in.close(); out.close(); server.close(); } } Threading in Android • Socket and streaming network operations may take a significant amount of time • You cannot block the GUI thread for too long in Android • In order to connect as a client or receive connections, you must spawn threads to handle the communication • To spawn a Thread in Java, create a class that implements runnable and construct a new Thread object with it public class LongRunningWork implements Runnable { public void run(){ //do long running stuff here } public void threadMe(){ Thread t = new Thread(this); t.start(); } } What Should You Thread? • For the client, you need to thread the instantiation of the Socket and all read/write operations to it when it is connected • For the server, you need to have multiple threads • Some thread needs to call accept() • Some thread needs to manage reading/writing data for each client after a socket is returned from accept • The threading architecture is very important • Possible threading approaches: • Thread per connection • Eager spawning / thread pools • Half-sync / Half-async • Leader / Followers Synchronizing the GUI Thread with Others • Once approach that we have learned is to use a Handler to coordinate the exchange of work between the GUI and other threads • Another approach is to use the Android AsyncTask class • Android automatically manages the creation of Threads for AsyncTasks • An AsyncTask has three key methods that each run in a different thread context: • doInBackground() – runs in a NON-GUI thread • onProgressUpdate() – runs in the GUI thread • onPostExecute() – runs in the GUI thread • You create a subclass of AsyncTask and Android automatically runs each of your implementations of these methods in the correct thread context The AsyncTask Template Parameters • The types specified in the template parameters correspond to the parameter type of the doInBackground method, the type for the parameter to onProgressUpdate, and the type that is returned by doInBackground public class HttpTask extends AsyncTask<String, Integer, Long> { ….. protected Long doInBackground(String... params) { //this runs in a background thread from the pool …. publishProgress(some_new_progress_value); …. return new Long(0); } protected void onProgressUpdate(Integer... progress) { //this runs in the UI thread //this is where you notify any callbacks that require incremental progress } protected void onPostExecute(Long result) { //this runs in the UI thread //this is where you would invoke your callback to the entity that created the request } } AsyncTask Example public class HttpTask extends AsyncTask<String, Float, String> { ….. protected Long doInBackground(String... params) { Socket socket = new Socket(some_host,some_port); InputStream in = socket.getInputStream(); byte[] buff = new byte[1024]; float expectedsize = 12341234; int read = 0; float totalread = 0; while( (in.read(buff,0,buff.length)) != -1){ totalread += read; publishProgress(totalread/expectedsize); } return “It worked!”; } protected void onProgressUpdate(Float... progress) { //this runs in the UI thread //this is where you notify any callbacks that require incremental progress someProgressBar_.setValue(progress * 100); } protected void onPostExecute(String result) { //this runs in the UI thread //this is where you would invoke your callback to the entity that created the request someTextView.setText(result); } }