Debugging Client-Server Communication

Especially in mobile development you most likely have some client-server communication going on, which is often the source of a lot of problems and long debugging sessions. To make the debugging easier it is helpful to see what each side sends or receives. There are two UNIX tools that can come in quite handy in such situations:
  • netcat - to listen to all TCP and UDP connections on a specific port
  • cURL - to send 'fake' requests to a server
Both a very powerful tools and you can do a lot of stuff with them (e.g. write your own web server with a shell script). However, in this post we will keep it simple and focus on debugging a HTTP (JSON) communication between a web server and a mobile client (iPhone, Android, but could be pretty much any kind of client).


Listening to incoming requests

We start a listening server with
nc -lk $ip $port 
  • -l: listen
  • -k: forces nc to stay listening for another connection after its current connection is completed.
  • $ip: the IP/interface you want to bind to. Use 0.0.0.0 to bind to all interfaces and IPs.
  • $port: the port you want to bind to. Doesn't really matter which one you use, as long as the client uses the same one to connect to.

In practice it might look like this:
sk@supernova:~/ > nc -lk 0.0.0.0 8080
POST /rpc HTTP/1.1
Accept: application/json
Content-type: application/json
Accept-Encoding: gzip
Host: 192.168.2.3
Content-Length: 152
Connection: Keep-Alive


{"id":3,"jsonrpc":"2.0","method":"sendTestMessage","params":{"clientVersion":"0.11.4-debug","user":"sk@geekmind.net","imei":"32420214181983746","message":"This is a test message :-)"}}
In green the HTTP header and in orange the actual content, in this case a JSON-RPC message. While the header is mostly irrelevant to us, it might in some cases contain useful information to detect the source of the problem. However, more interesting, and in most cases more prone to errors is our own "custom protocol" and its implementation. By evaluating the content section we can now easily compare if there is a difference between what we were expecting to receive and what the client was actually sending out.


Sending "fake" requests to a server

Sometimes the problem may not be in the client's implementation of our communication protocol, but on the server side. The complementary approach to the above example is to send "fake" requests to our server and look at the response we get.

With cURL it is as simply as that:
curl -v -i -X POST -d $data $uri
  • -v: verbose
  • -i: include HTTP headers in the output
  • -X: HTTP request type. Defaults to GET if none given
  • -d: data

Applied it might look like this:
sk@supernova:~/ > curl -v -i -X POST -d '{"id":1,"jsonrpc":"2.0","method":"sendTestMessage","params":{"clientVersion":"0.11.4-debug","user":"sk@geekmind.net","imei":"1111111111111111111"}}' http://android.geekmind.net/rpc
* About to connect() to android.geekmind.net port 80 (#0)
*   Trying 74.125.43.121... connected
* Connected to android.geekmind.net (74.125.43.121) port 80 (#0)
> POST /rpc HTTP/1.1
> User-Agent: curl/7.19.7 (universal-apple-darwin10.0) libcurl/7.19.7 OpenSSL/0.9.8l zlib/1.2.3
> Host: android.geekmind.net
> Accept: */*
> Content-Length: 157
> Content-Type: application/x-www-form-urlencoded
>
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
< Content-Type: text/html; charset=utf-8
Content-Type: text/html; charset=utf-8
< Cache-Control: no-cache
Cache-Control: no-cache
< Expires: Fri, 01 Jan 1990 00:00:00 GMT
Expires: Fri, 01 Jan 1990 00:00:00 GMT
< Date: Fri, 08 Apr 2011 09:19:32 GMT
Date: Fri, 08 Apr 2011 09:19:32 GMT
< Server: Google Frontend
Server: Google Frontend
< Transfer-Encoding: chunked
Transfer-Encoding: chunked
<
* Connection #0 to host android.geekmind.net left intact
* Closing connection #0
{"jsonrpc": "2.0", "id": 1, "error": "1", "message": "ERROR: user and IMEI do not match!"}}  
In red the response we got from the server. In this case we used a real username with a wrong IMEI and tested if the server generates the right response. In our case the server correctly produced an error.

If you're interested in reading more about the actual implementation of client-server communication on mobile devices, check out my blog post Android: Simple HttpClient to send/receive JSON Objects. The code is available on GitHub.

If you want to directly monitor a real connection I suggest that you have a look at tools like Wireshark and tcpdump. Wireshark has a GUI and is fairly easy to understand. It also helps to have a server instance running on your local machine (development server), so you don't need to figure out how to tap into your phones WiFi connection.

No comments:

Post a Comment