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

1. 首先创建mvn项目

2. pom中导入jar包


		<dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.24.Final</version>
        </dependency>
        <dependency>
            <groupId>net.sf.json-lib</groupId>
            <artifactId>json-lib</artifactId>
            <version>2.4</version>
            <classifier>jdk15</classifier>
        </dependency>
        <dependency>
            <groupId>net.sf.json-lib</groupId>
            <artifactId>json-lib</artifactId>
            <version>2.4</version>
        </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("获取设备运⾏数据");
    }
}

最后得到

在这里插入图片描述

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值