基于netty访问WebSocket(java的websocket客户端)(访问远程ws协议)

1. 首先创建mvn项目

2. pom中导入jar包


		<dependency>
            <groupId>io.nettygroupId>
            <artifactId>netty-allartifactId>
            <version>4.1.24.Finalversion>
        dependency>
        <dependency>
            <groupId>net.sf.json-libgroupId>
            <artifactId>json-libartifactId>
            <version>2.4version>
            <classifier>jdk15classifier>
        dependency>
        <dependency>
            <groupId>net.sf.json-libgroupId>
            <artifactId>json-libartifactId>
            <version>2.4version>
        dependency>

3. 创建客户端


package client;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.DefaultHttpHeaders;
import io.netty.handler.codec.http.HttpClientCodec;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory;
import io.netty.handler.codec.http.websocketx.WebSocketVersion;
import utils.WebSocketResult;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URISyntaxException;

//客户端
public class MyClient  {
     
    public static void main(String[] args){
     
        EventLoopGroup group=new NioEventLoopGroup();
        Bootstrap boot=new Bootstrap();
        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
        boolean zhen=true;
        try{
     
            boot.option(ChannelOption.SO_KEEPALIVE,true)
                    .group(group)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer());//引用自己的协议
             //ws协议类型 
          	URI websocketURI = new URI("ws://www.baidu.com:8023/user");
            HttpHeaders httpHeaders = new DefaultHttpHeaders();
            //进行握手
            WebSocketClientHandshaker handshaker = WebSocketClientHandshakerFactory.newHandshaker(websocketURI, WebSocketVersion.V13, (String)null, true,httpHeaders);
            //需要协议的host和port
            Channel channel=boot.connect(websocketURI.getHost(),websocketURI.getPort()).sync().channel();
            WebSocketClientHandler handler = (WebSocketClientHandler)channel.pipeline().get("hookedHandler");
            handler.setHandshaker(handshaker);
            handshaker.handshake(channel);
            //阻塞等待是否握手成功
            handler.handshakeFuture().sync();
            System.out.println("成功!");
            //让线程睡眠1秒,以免数据收回慢
            Thread.sleep(1000);
            try{
     
                while (zhen){
     
                    System.out.print("请输入操作:");
                    String zhi=br.readLine();
                    //发送textwebsocketframe格式的请求
                    //TextWebSocketFrame 可以任意转换
                    TextWebSocketFrame frame = new TextWebSocketFrame(zhi+"\r\n");
                    channel.writeAndFlush(frame);
                }
            }catch(Exception e){
     
                br.close();
            }
        }catch(Exception e){
     
            System.out.println(e.getMessage());
            zhen=false;
             try{
     
                br.close();
            }catch(Exception e){
     
                System.out.println(e.getMessage());
            }
        }finally {
     
        	//优雅关闭
            group.shutdownGracefully();
        }
    }
}

4.创建协议


package client;

import io.netty.channel.ChannelHandler;
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 io.netty.handler.timeout.IdleStateHandler;

import java.util.concurrent.TimeUnit;

public class ChannelInitializer extends io.netty.channel.ChannelInitializer<SocketChannel> {
     
    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
     
        ChannelPipeline p = socketChannel.pipeline();
        p.addLast(new ChannelHandler[]{
     new HttpClientCodec(),new HttpObjectAggregator(1024*1024*10)});
        p.addLast(new IdleStateHandler(0,4,0, TimeUnit.SECONDS));	//心跳
        p.addLast(new PingClient());								//心跳 机制
        p.addLast("hookedHandler", new WebSocketClientHandler());
    }
}

创建header


package client;

import io.netty.channel.*;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.websocketx.*;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.CharsetUtil;
import utils.JsonStringToClass;
import utils.WebSocketResult;

import java.lang.reflect.Method;
//这里的泛型我用的是object,也可以用TextWebSocketFrame
public class WebSocketClientHandler  extends SimpleChannelInboundHandler<Object> {
     
    WebSocketClientHandshaker handshaker;
    ChannelPromise handshakeFuture;
    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;
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
     
        Channel ch = ctx.channel();
        FullHttpResponse response;
        //判断接收的请求是否是牵手
        if (!this.handshaker.isHandshakeComplete()) {
     
            try {
     
                response = (FullHttpResponse) msg;
                //握手协议返回,设置结束握手
                this.handshaker.finishHandshake(ch, response);
                //设置成功
                this.handshakeFuture.setSuccess();
                System.out.println("牵手成功!");
            } catch (WebSocketHandshakeException var7) {
     
                FullHttpResponse res = (FullHttpResponse) msg;
                String errorMsg = String.format("WebSocket客户端连接失败,状态为:%s", res.status());
                this.handshakeFuture.setFailure(new Exception(errorMsg));
            }
        } else if (msg instanceof FullHttpResponse) {
     
            response = (FullHttpResponse) msg;
            //可以吧字符码转为指定类型
            //this.listener.onFail(response.status().code(), response.content().toString(CharsetUtil.UTF_8));
            throw new IllegalStateException("未预料的错误(getStatus=" + response.status() + ", content=" + response.content().toString(CharsetUtil.UTF_8) + ')');
        } else {
     //如果不是牵手
            WebSocketFrame frame = (WebSocketFrame) msg;
            if (frame instanceof TextWebSocketFrame) {
     
                TextWebSocketFrame textFrame = (TextWebSocketFrame) frame;
                //这里我用了一个返回自己的格式的类型和一个json字符串转为对象的方法
                WebSocketResult webresult= (WebSocketResult) new JsonStringToClass().StringJSONToList(textFrame.text(),WebSocketResult.class);
                UseFangfa u=new UseFangfa();
                //如果反射方法有多个参数可以在逗号后面现指定多种类型,然后在反射方法中传入多个参数
                Method method = u.getClass().getMethod(webresult.getAction(),Class.forName("utils.WebSocketResult"),Class.forName("io.netty.channel.Channel"));
                //反射方法
                method.invoke(u,webresult,ch);
//                System.out.println("收到消息:"+textFrame.text());
            } else if (frame instanceof BinaryWebSocketFrame) {
     
                BinaryWebSocketFrame binFrame = (BinaryWebSocketFrame) frame;
                System.out.println("二进制WebSocketFrame");
            } else if (frame instanceof PongWebSocketFrame) {
     
                //返回心跳监测
                //System.out.println("WebSocket客户端接收到pong");
            } else if (frame instanceof CloseWebSocketFrame) {
     
                System.out.println("接收关闭贞");
                //this.listener.onClose(((CloseWebSocketFrame)frame).statusCode(), ((CloseWebSocketFrame)frame).reasonText());
                ch.close();
            }

        }
    }
    /*发生异常直接关闭客户端*/
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
     
        System.out.println("发生异常"+cause.getMessage());
        ctx.close();
    }
}


这里用到的可参考https://blog.csdn.net/weixin_42368893/article/details/99412132


客户端使用ping心跳检测

package client;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.websocketx.PingWebSocketFrame;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;

public class PingClient extends ChannelDuplexHandler {
     
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
     
        if (evt instanceof IdleStateEvent) {
     
            IdleStateEvent event = (IdleStateEvent) evt;

            if (event.state().equals(IdleState.READER_IDLE)) {
     
                System.out.println("------长期未收到服务器反馈数据------");
                //根据具体的情况 在这里也可以重新连接
            } else if (event.state().equals(IdleState.WRITER_IDLE)) {
     
                //System.out.println("------长期未向服务器发送数据 发送心跳------");
                //System.out.println("------发送心跳包------ping\r\n");
//                ctx.writeAndFlush(getSendByteBuf("ping"));
                PingWebSocketFrame p=new PingWebSocketFrame();
                ctx.writeAndFlush(p);

            } else if (event.state().equals(IdleState.ALL_IDLE)) {
     

            }

        }
    }
}

反射的方法类


package client;

import io.netty.channel.Channel;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import utils.WebSocketResult;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class UseFangfa {
     
    public void getdevice(WebSocketResult result, Channel ch){
     
        System.out.println(result.toString());
        System.out.println("getdevice方法");
    }
    //登录
    public void connect(WebSocketResult result, Channel ch) throws Exception {
     
        if(result.getSuccess()){
     
            System.out.println(result.getContent());
            System.out.println("登录成功");
            //下面可以进行ch里发送消息的操作
        }else{
     
            System.out.println("登录失败");
        }
    }
    public void getuserinfo(WebSocketResult result, Channel ch){
     
        System.out.println(result.toString());
        System.out.println("获取用户数据");
    }
    public void getdata(WebSocketResult result){
     
        System.out.println(result.toString());
        System.out.println("获取设备运⾏数据");
    }
}

最后得到

基于netty访问WebSocket(java的websocket客户端)(访问远程ws协议)_第1张图片

你可能感兴趣的:(netty,websocket,websocket,netty,websocket客户端)