WebSocket 是一种双向通信协议,在建立连接后,WebSocket服务器和 Browser/Client Agent 都能主动的向对方发送或接收数据,就像 Socket一样。它类似TCP长连接,但是WebSocket使用的是ws和wss两种通信协议,所以这是完全不同于HTTP的一种网络协议,尽管它也是默认使用80和443端口。
WebSocket的连接包括第一步握手和第二步数据交换。在通过WebSocket开始双向通信时,首先需要与服务器建立连接。而用于建立连接的请求是由客户端发起,服务器端将会确认连接对象的源以及协议,并发送连接许可的响应。在发送了响应之后,浏览器会将该连接升级为WebSocket。握手成功之后就建立起长连接,直到服务器或者浏览器某一方主动断开连接。客户端发起连接非常简单,只需要一句Javascript即可实现:
var ws = new WebSocket('ws://www.example.com/bar')
然后就是第二步,浏览器和服务器之间双向数据发送了。Nodejs是即时通信应用很完美的开发语言(此处不是为了引起撕逼),很自然地,Nodejs本身也比较完善地实现了WebSocket相关API。客户端(浏览器)发送消息到服务器最简单的方法就是通过调用socket对象的send()方法,然后Node服务器通过注册message事件进行监听,当然服务器send过来的消息也是通过对客户端message事件进行捕捉,从而实现双向的数据交互。这两者之间交换的数据可以是字符串、ArrayBuffer(二进制数据)或者Blob,所以WebSocket也是可以传输文件的。也可以通过广播事件将消息发送到所有连接到服务器的客户端。
使用框架:Java-WebSocket
Gradle
To use Gradle add the maven central repository to your repositories list :
mavenCentral()
Then you can just add the latest version to your build.
compile "org.java-websocket:Java-WebSocket:1.3.8"
Client Example
import java.net.URI;
import java.net.URISyntaxException;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft;
import org.java_websocket.drafts.Draft_6455;
import org.java_websocket.handshake.ServerHandshake;
public class EmptyClient extends WebSocketClient {
public EmptyClient(URI serverUri, Draft draft) {
super(serverUri, draft);
}
public EmptyClient(URI serverURI) {
super(serverURI);
}
@Override
public void onOpen(ServerHandshake handshakedata) {
send("Hello, it is me. Mario :)");
System.out.println("new connection opened");
}
@Override
public void onClose(int code, String reason, boolean remote) {
System.out.println("closed with exit code " + code + " additional info: " + reason);
}
@Override
public void onMessage(String message) {
System.out.println("received message: " + message);
}
@Override
public void onMessage(ByteBuffer message) {
System.out.println("received ByteBuffer");
}
@Override
public void onError(Exception ex) {
System.err.println("an error occurred:" + ex);
}
public static void main(String[] args) throws URISyntaxException {
WebSocketClient client = new EmptyClient(new URI("ws://localhost:8887"));
client.connect();
}
}
Server Example
import java.net.InetSocketAddress;
import org.java_websocket.WebSocket;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;
public class SimpleServer extends WebSocketServer {
public SimpleServer(InetSocketAddress address) {
super(address);
}
@Override
public void onOpen(WebSocket conn, ClientHandshake handshake) {
conn.send("Welcome to the server!"); //This method sends a message to the new client
broadcast( "new connection: " + handshake.getResourceDescriptor() ); //This method sends a message to all clients connected
System.out.println("new connection to " + conn.getRemoteSocketAddress());
}
@Override
public void onClose(WebSocket conn, int code, String reason, boolean remote) {
System.out.println("closed " + conn.getRemoteSocketAddress() + " with exit code " + code + " additional info: " + reason);
}
@Override
public void onMessage(WebSocket conn, String message) {
System.out.println("received message from " + conn.getRemoteSocketAddress() + ": " + message);
}
@Override
public void onMessage( WebSocket conn, ByteBuffer message ) {
System.out.println("received ByteBuffer from " + conn.getRemoteSocketAddress());
}
@Override
public void onError(WebSocket conn, Exception ex) {
System.err.println("an error occured on connection " + conn.getRemoteSocketAddress() + ":" + ex);
}
@Override
public void onStart() {
System.out.println("server started successfully");
}
public static void main(String[] args) {
String host = "localhost";
int port = 8887;
WebSocketServer server = new SimpleServer(new InetSocketAddress(host, port));
server.run();
}
}
还有一个封装框架挺好:RxWebSocket
how to use
添加依赖:
在项目module下gradle加入:
//本项目
compile 'com.dhh:websocket:1.5.0'
init
//if you want to use your okhttpClient
OkHttpClient yourClient = new OkHttpClient();
RxWebSocketUtil.getInstance().setClient(yourClient);
// show log,default false
RxWebSocketUtil.getInstance().setShowLog(true);
WSS support,其实就是设置okhttp的SSL,请参照okhttp的设置
//wss support
RxWebSocketUtil.getInstance().setSSLSocketFactory(yourSSlSocketFactory,yourX509TrustManager);
RxWebSocketUtil.getInstance().getWebSocket("wss://...");
//or
OkHttpClient client = new OkHttpClient.Builder()
.sslSocketFactory(yourSSlSocketFactory, yourX509TrustManager)
//other config...
.build();
RxWebSocketUtil.getInstance().setClient(client);
open WebSocket
RxWebSocketUtil.getInstance().getWebSocketInfo(url)
.subscribe(new Action1<WebSocketInfo>() {
@Override
public void call(WebSocketInfo webSocketInfo) {
mWebSocket = webSocketInfo.getWebSocket();
Log.d("MainActivity", webSocketInfo.getString());
Log.d("MainActivity", "webSocketInfo.getByteString():" + webSocketInfo.getByteString());
}
});
mWebSocket.send("hello word");
// use WebSocketSubscriber
RxWebSocketUtil.getInstance().getWebSocketInfo("ws://10.7.5.88:8089")
//RxLifecycle : https://github.com/dhhAndroid/RxLifecycle
.compose(RxLifecycle.with(this).<WebSocketInfo>bindOnDestroy())
.subscribe(new WebSocketSubscriber() {
@Override
public void onOpen(@NonNull WebSocket webSocket) {
}
@Override
public void onMessage(@NonNull String text) {
}
@Override
public void onMessage(@NonNull ByteString bytes) {
}
});
// use WebSokcetAction1
RxWebSocketUtil.getInstance().getWebSocketInfo("ws://10.7.5.88:8089")
//RxLifecycle : https://github.com/dhhAndroid/RxLifecycle
.compose(RxLifecycle.with(this).<WebSocketInfo>bindOnDestroy())
.subscribe(new WebSokcetAction1() {
@Override
public void onOpen(@NonNull WebSocket webSocket) {
}
@Override
public void onMessage(@NonNull String text) {
}
@Override
public void onMessage(@NonNull ByteString bytes) {
}
});
//get StringMsg
RxWebSocketUtil.getInstance().getWebSocketString(url)
.subscribe(new Action1<String>() {
@Override
public void call(String s) {
}
});
// get ByteString
RxWebSocketUtil.getInstance().getWebSocketByteString(url)
.subscribe(new Action1<ByteString>() {
@Override
public void call(ByteString byteString) {
}
});
//get WebSocket
RxWebSocketUtil.getInstance().getWebSocket(url)
.subscribe(new Action1<WebSocket>() {
@Override
public void call(WebSocket webSocket) {
}
});
//with timeout
RxWebSocketUtil.getInstance().getWebSocketInfo(url, 10, TimeUnit.SECONDS)
.subscribe(new Action1<WebSocketInfo>() {
@Override
public void call(WebSocketInfo webSocketInfo) {
}
});
// Rxbinding
RxView.clicks(centect)
.flatMap(new Func1<Void, Observable<String>>() {
@Override
public Observable<String> call(Void aVoid) {
return RxWebSocketUtil.getInstance().getWebSocketString(url);
}
})
.subscribe(new Action1<String>() {
@Override
public void call(String s) {
//the s !=null
Log.d("MainActivity", s);
textview.setText(Html.fromHtml(s));
}
});
发送消息
//用WebSocket的引用直接发
mWebSocket.send("hello word");
//url 对应的WebSocket已经打开可以这样send,否则报错
RxWebSocketUtil.getInstance().send(url, "hello");
RxWebSocketUtil.getInstance().send(url, ByteString.EMPTY);
//异步发送,若WebSocket已经打开,直接发送,若没有打开,打开一个WebSocket发送完数据,直接关闭.
RxWebSocketUtil.getInstance().asyncSend(url, "hello");
RxWebSocketUtil.getInstance().asyncSend(url, ByteString.EMPTY);
注销
RxJava的注销方式,就可以取消订阅. 项目里的demo里,简单实现了一个Lifecycle.仅供参考.
Subscription subscription = RxWebSocketUtil.getInstance().getWebSocketString("ws://sdfs").subscribe();
//注销
if(subscription!=null&&!subscription.isUnsubscribed()) {
subscription.unsubscribe();
}