netty websocket client
网上更多的基于netty的websocket服务端的实现,客户端更多的是html,本文介绍自己实现websocket的client,并返回异步返回结果的数据,方便业务逻辑调用。
io.netty
netty-all
4.1.35.Final
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpClientCodec;
import io.netty.handler.codec.http.HttpObjectAggregator;
import java.util.concurrent.CountDownLatch;
public class ClientInitializer extends ChannelInitializer {
private CountDownLatch latch;
public ClientInitializer(CountDownLatch latch) {
this.latch = latch;
}
private WebSocketClientHandler handler;
@Override
protected void initChannel(SocketChannel sc) throws Exception {
handler = new WebSocketClientHandler(latch);
ChannelPipeline p = sc.pipeline();
p.addLast(new ChannelHandler[]{new HttpClientCodec(),
new HttpObjectAggregator(1024*1024*10)});
p.addLast("websocketHandler", handler);
}
public String getServerResult(){
return handler.getResult();
}
public void resetLathc(CountDownLatch latch) {
handler.resetLatch(latch);
}
public void setHandler(WebSocketClientHandler handler){
this.handler = handler;
}
import io.netty.channel.*;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketHandshakeException;
import io.netty.util.CharsetUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.CountDownLatch;
public class WebSocketClientHandler extends SimpleChannelInboundHandler {
private static final Logger logger = LoggerFactory.getLogger(WebSocketClientHandler.class);
WebSocketClientHandshaker handshaker;
ChannelPromise handshakeFuture;
private CountDownLatch lathc;
private String result;
public WebSocketClientHandler(CountDownLatch lathc) {
this.lathc = lathc;
}
public void handlerAdded(ChannelHandlerContext ctx) {
this.handshakeFuture = ctx.newPromise();
}
public WebSocketClientHandshaker getHandshaker() {
return handshaker;
}
public void setHandshaker(WebSocketClientHandshaker handshaker) {
this.handshaker = handshaker;
}
public ChannelPromise getHandshakeFuture() {
return handshakeFuture;
}
public void setHandshakeFuture(ChannelPromise handshakeFuture) {
this.handshakeFuture = handshakeFuture;
}
public ChannelFuture handshakeFuture() {
return this.handshakeFuture;
}
protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("channelRead0 " + this.handshaker.isHandshakeComplete());
Channel ch = ctx.channel();
FullHttpResponse response;
if (!this.handshaker.isHandshakeComplete()) {
try {
response = (FullHttpResponse) msg;
//握手协议返回,设置结束握手
this.handshaker.finishHandshake(ch, response);
//设置成功
this.handshakeFuture.setSuccess();
logger.info("WebSocket Client connected! response headers[sec-websocket-extensions]:{}" + response.headers());
} catch (WebSocketHandshakeException var7) {
FullHttpResponse res = (FullHttpResponse) msg;
String errorMsg = String.format("WebSocket Client failed to connect,status:%s,reason:%s", res.status(), res.content().toString(CharsetUtil.UTF_8));
this.handshakeFuture.setFailure(new Exception(errorMsg));
}
} else if (msg instanceof FullHttpResponse) {
response = (FullHttpResponse) msg;
throw new IllegalStateException("Unexpected FullHttpResponse (getStatus=" + response.status() + ", content=" + response.content().toString(CharsetUtil.UTF_8) + ')');
} else {
WebSocketFrame frame = (WebSocketFrame) msg;
if (frame instanceof TextWebSocketFrame) {
TextWebSocketFrame textFrame = (TextWebSocketFrame) frame;
//this.listener.onMessage(textFrame.text());
logger.info("text msg is " + textFrame.text());
result = textFrame.text();
lathc.countDown();// 消息接收后释放同步锁,lathc是从Client加一传回来的
}
}
}
public void resetLatch(CountDownLatch lathc) {
this.lathc = lathc;
}
public String getResult() {
return result;
}
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.Callable;
public class WebSocketCallable implements Callable {
private static final Logger logger = LoggerFactory.getLogger(WebSocketCallable.class);
private String content;
private Channel channel;
private WebSocketCallable(){
}
public WebSocketCallable(Channel channel, String content){
this.channel = channel;
this.content = content;
}
@Override
public String call() throws Exception {
TextWebSocketFrame frame = new TextWebSocketFrame(content);
channel.writeAndFlush(frame).addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture channelFuture) throws Exception {
if(channelFuture.isSuccess()){
logger.info("callback is success");
}else if (channelFuture.channel() == null){
logger.info("callback is failed" + channelFuture.cause().getMessage());
return;
}
}
});
return null;
}
private static final Logger logger = LoggerFactory.getLogger(WebSocketClient.class);
private static ExecutorService executor = Executors.newCachedThreadPool();
private static String uri ;
private static CountDownLatch latch;
private static ClientInitializer clientInitializer;
private WebSocketClient(){
}
public WebSocketClient(String uri){
this.uri = uri;
latch = new CountDownLatch(0);
clientInitializer = new ClientInitializer(latch);
}
private static class SingletonHolder {
static final WebSocketClient instance = new WebSocketClient();
}
public static WebSocketClient getInstance(){
return SingletonHolder.instance;
}
public static String pushMsg(String content) throws URISyntaxException, InterruptedException {
EventLoopGroup group=new NioEventLoopGroup();
Bootstrap boot=new Bootstrap();
boot.option(ChannelOption.SO_KEEPALIVE,true)
.option(ChannelOption.TCP_NODELAY,true)
.option(ChannelOption.SO_BACKLOG,1024*1024*10)
.group(group)
.handler(new LoggingHandler(LogLevel.INFO))
.channel(NioSocketChannel.class)
.handler(new ClientInitializer(latch));
URI websocketURI = new URI(uri);
HttpHeaders httpHeaders = new DefaultHttpHeaders();
//进行握手
WebSocketClientHandshaker handshaker = WebSocketClientHandshakerFactory.newHandshaker(websocketURI, WebSocketVersion.V13, (String)null, true,httpHeaders);
logger.info("connect to server....");
final Channel channel=boot.connect(websocketURI.getHost(),websocketURI.getPort()).sync().channel();
WebSocketClientHandler handler = (WebSocketClientHandler)channel.pipeline().get("websocketHandler");
handler.setHandshaker(handshaker);
handshaker.handshake(channel);
//阻塞等待是否握手成功
handler.handshakeFuture().sync();
return sendMsg(channel,handler,content);
}
public static String sendMsg(Channel channel,WebSocketClientHandler handler,String content) throws InterruptedException {
logger.info("send msg:" + content);
//发起线程发送消息
executor.submit(new WebSocketCallable(channel, content));
latch = new CountDownLatch(1);
clientInitializer.setHandler(handler);
clientInitializer.resetLathc(latch);
//等待,当websocket服务端返回数据时唤醒屏障,并返回结果
latch.await();
return clientInitializer.getServerResult();
}
public static void main(String[] args) throws URISyntaxException, InterruptedException {
String result = "";
WebSocketClient webSocketClient = new WebSocketClient("ws://localhost:8088");
result =webSocketClient.pushMsg("hello websocket"); // 返回结果
System.out.println("¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥"+ result);
}