转载请注明出处:http://blog.csdn.net/llew2011/article/details/72987090
在上篇文章Android 源码系列之<十五>,深入浅出WebSocket,打造自己的即时聊天交互系统<上>中主要讲解了WebSocket协议,然后通过实战方式展示了WebSocket的通信过程,这篇文章我将从源码的角度带领小伙伴们深入理解一下autobahn以及okhttp的Socket通信源码,如果你对上述项目的WebSocket实现比较清楚了,请跳过本文(*^__^*) ……
我们首先从GitHub上clone来下autobahn的源码,运行一下该项目,效果如下:
autobahn给出的demo我稍微做了修改,IP和端口号是我从网上找的一个在线测试地址,当点击Connect按钮后就会链接输入框给定的IP地址和端口号,然后进行链接操作,链接成功后通过Toast弹出服务器端返回的消息,表示Socket链接已经建立,可以进行通信了,然后我们可以在下方的输入框中输入任意内容给服务器,为了弄清楚通信过程,我们通过分析点击Connect按钮看看发生的流程,点击CONNECT按钮会调用start()方法,源码如下:
private void start() {
final String wsuri = "ws://" + mHostname.getText() + ":" + mPort.getText();
mStatusline.setText("Status: Connecting to " + wsuri + " ..");
setButtonDisconnect();
try {
mConnection.connect(wsuri, new WebSocketConnectionHandler() {
@Override
public void onOpen() {
mStatusline.setText("Status: Connected to " + wsuri);
savePrefs();
mSendMessage.setEnabled(true);
mMessage.setEnabled(true);
}
@Override
public void onTextMessage(String payload) {
alert("Got echo: " + payload);
Log.e("---WebSocket---", payload);
}
@Override
public void onClose(int code, String reason) {
alert("Connection lost.");
mStatusline.setText("Status: Ready.");
setButtonConnect();
mSendMessage.setEnabled(false);
mMessage.setEnabled(false);
}
});
} catch (WebSocketException e) {
Log.d(TAG, e.toString());
}
}
start()方法就是进行链接Socket的核心,首先根据输入框输入的IP地址和端口生成一个wsuri地址(该处值为:ws://121.40.165.18:8088),然后设置Connect按钮为不可点击状态,最后通过mConnection的connect()方法进行Socket链接,mConnection的定义如下:
private final WebSocket mConnection = new WebSocketConnection();
mConnection是WebSocket类型,该类是抽象类,它的实现类是WebSocketConnection,那也就是说mConnection调用的connect()方法走的是WebSocketConnection的connect()方法,其源码如下:
public void connect(String wsUri, WebSocket.ConnectionHandler wsHandler) throws WebSocketException {
connect(wsUri, null, wsHandler, new WebSocketOptions(), null);
}
connect()方法又调用了其重载方法connect(),源码如下:
public void connect(String wsUri, String[] wsSubprotocols, WebSocket.ConnectionHandler wsHandler, WebSocketOptions options, List<BasicNameValuePair> headers) throws WebSocketException {
// don't connect if already connected .. user needs to disconnect first
if (isConnected()) {
throw new WebSocketException("already connected");
}
// parse WebSockets URI
try {
mWsUri = new URI(wsUri);
if (!mWsUri.getScheme().equals("ws") && !mWsUri.getScheme().equals("wss")) {
throw new WebSocketException("unsupported scheme for WebSockets URI");
}
mWsScheme = mWsUri.getScheme();
if (mWsUri.getPort() == -1) {
if (mWsScheme.equals("ws")) {
mWsPort = 80;
} else {
mWsPort = 443;
}
} else {
mWsPort = mWsUri.getPort();
}
if (mWsUri.getHost() == null) {
throw new WebSocketException("no host specified in WebSockets URI");
} else {
mWsHost = mWsUri.getHost();
}
if (mWsUri.getRawPath() == null || mWsUri.getRawPath().equals("")) {
mWsPath = "/";
} else {
mWsPath = mWsUri.getRawPath();
}
if (mWsUri.getRawQuery() == null || mWsUri.getRawQuery().equals("")) {
mWsQuery = null;
} else {
mWsQuery = mWsUri.getRawQuery();
}
} catch (URISyntaxException e) {
throw new WebSocketException("invalid WebSockets URI");
}
mWsSubprotocols = wsSubprotocols;
mWsHeaders = headers;
mWsHandler = wsHandler;
// make copy of options!
mOptions = new WebSocketOptions(options);
// set connection active
mActive = true;
// reset value
onCloseCalled = false;
// use async connector on short-lived background thread
new WebSocketConnector().start();
}
该方法首先判断链接是否建立,如果建立则直接抛了一个异常,因为链接一旦建立了就不需要再次建立,然后检测给定的URI协议和端口是否符合规范,如果都符合WebSocket协议规范则启动后台线程WebSocketConnector来进行消息通信,该类源码如下:
/**
* Asynchronous socket connector.
*/
private class WebSocketConnector extends Thread {
publi