精华内容
下载资源
问答
  • 经过本人对WebSocket协议的研究和WebSocket服务器的编写,对WebSocket有了深入的了解,在此写个总结供以后研究参考。1.概要WebSocket是最新提出用于实现服务器与浏览器双向通信的一种解决方案,用于取代一些传统的...

    经过本人对WebSocket协议的研究和WebSocket服务器的编写,对WebSocket有了深入的了解,在此写个总结供以后研究参考。

    1.概要

    WebSocket是最新提出用于实现服务器与浏览器双向通信的一种解决方案,用于取代一些传统的数据推送方案(如iframe长连接,ajax轮询等)。该方案由于一直在草案阶段,最新的版本为version 13.该版本出现在RFC6455中。而在safari(包括桌面和移动版本)上则是使用的websocket的 draft-ietf-hybi版。照这个趋势看来,WebSocket早晚会向RFC6455的方向定型。

    在本文中,称RFC6455版的chrome版,safari使用的版本为safari版。

    这两个文件我已经下载下来作为本文附件,可直接参考。chrome版 safari版

    2.握手协议

    HTTP服务器识别WebSocket协议的方式首先是判断HTTP头中的Connection和Upgrade头,如果Connection是Upgrade,且Upgrade头是WebSocket,则可以确定为WebSocket请求,这时候要进行WebSocket的握手处理,两个版本的握手方式不同,最新的Chrome版本通过Sec-WebSocket-Key的设置进行一些计算返回Sec-WebSocket-Accept响应头,而safari版本通过Sec-WebSocket-Key1,Sec-WebSocket-Key2及请求主体三个共同计算响应主体的。下面进行分别讨论。

    chrome版

    Sec-WebSocket-Key是客户端随机生成并进行base64的字符串,它的原始内容是什么服务器不需要关心,服务器需要将这个字符串,与”258EAFA5-E914-47DA-95CA-C5AB0DC85B11″这个字符串进行拼接,然后对这个拼接好的字符串进行sha-1运算,再把sha-1散列得到的20字节进行base64编码即为响应头Sec-WebSocket-Accept的值。

    safari版

    这个版本让人觉得有点意思,有种小学玩数数棍的感觉。下面给个示例请求:

    Sec-WebSocket-Key1: 18x 6]8vM;54 *(5: { U1]8 z [ 8

    Sec-WebSocket-Key2: 1_ tx7X d < nw 334J702) 7]o}` 0

    Tm[K T2u

    首先,我们把Sec-WebSocket-Key1和Sec-WebSocket-Key2中的所有数字从左到右提出来组成一个整数,那么上面的示例可以组成1868545188 和 1733470270两个数。

    接下来我们去数两个串各自的空格数,数出来分别为12和10

    然后将上面的数除以下面的数,可得到155712099 和 173347027

    这两个数是32位的整数,以Big-Endian的方式(低地址存放最高字节)各保存为4个字节,再与请求体中的8个字节拼接,可以得到一个16字节的串.再对这个串进行md5,md5结果的16字节即作为响应体返回给客户端.

    这个示例将返回fQJ,fN/4F4!~K~MH,示例是巧合,实际上返回的内容可以是乱码的.但key中不会出现乱码.

    下面是我已经写好的计算响应值的C函数:

    /**

    * chrome版websocket响应值计算

    */

    void websocket_accept_key(const char* key,int key_len,char* out){

    char tmp[128];

    unsigned char sha[20];

    if(key_len==0) key_len=strlen(key);

    strcpy(tmp,key);

    strcpy(tmp+key_len,"258EAFA5-E914-47DA-95CA-C5AB0DC85B11");

    sha1(tmp,key_len+36,sha);

    base64_encode(sha,20,out);

    }

    /**

    * safari版websocket响应值计算

    */

    void websocket_accept_key_old(const char* key1,int key1Len,const char* key2,int key2Len,char* body,char* out){

    char tmp[16];

    unsigned long long kv1=0;

    unsigned long long kv2=0;

    int c1=0;

    int c2=0;

    int i;

    if(key1Len<=0) key1Len=strlen(key1);

    if(key2Len<=0) key2Len=strlen(key2);

    for(i=0;i

    if(key1[i]>='0' && key1[i]<='9') kv1=kv1*10+(key1[i]-'0');

    else if(key1[i]==' ') c1++;

    }

    for(i=0;i

    if(key2[i]>='0' && key2[i]<='9') kv2=kv2*10+(key2[i]-'0');

    else if(key2[i]==' ') c2++;

    }

    kv1/=c1;

    kv2/=c2;

    for(i=3;i>=0;i--){

    tmp[i]=kv1&0xff;

    tmp[i+4]=kv2&0xff;

    kv1=kv1>>8;

    kv2=kv2>>8;

    }

    for(i=0;i<8;i++){

    tmp[i+8]=body[i];

    }

    md5(tmp,16,out);

    out[16]=0;

    }

    为什么要做这么复杂的握手?这是为了让客户端知道这个服务器是否真的支持websocket,因为这个协议本来很像HTTP协议,如果直接向HTTP服务器发起这样的请求,服务器同样会响应并返回Bad request.

    3.结论

    经过分析可以知道两种方式的握手步骤,对比下来version13版的websocket握手更加简单.目前version13已经正为websocket正式版本,后期的改动应该不会有太多大的变动.

    展开全文
  • 我已经用websockets做过一些小例子,但是我找不到一个好的客户端,它带有头和更复杂的握手。 在不了解所有详细信息的情况下,是否可能连接到未知服务器? 我使用一个编程端点并导入javax.websocket....

    之后,我尝试将客户机连接到服务器,并在onMessage方法中接收消息。

    WebSocketContainer container=ContainerProvider.getWebSocketContainer();Session Session=Container.ConnectToServer(ClientEndpoint.class,buildCEC(),new URI(“wss://async.example.com/socket.io/1/?t=”+System.currentTimeMillis());

    我尝试在buildCec()中插入到服务器连接的头。ClientEndpointConfig config=ClientEndpointConfig.Builder.Create()。Build();配置器conf=config.getConfigurator();`Map> headers = new HashMap>();

    headers.put("Connection", Arrays.asList("keep-alive", "Upgrade"));

    headers.put("Sec-Websocket-Extensions", Arrays.asList("x-webkit-deflate-frame"));

    headers.put("Sec-Websocket-key", Arrays.asList("cx36sHrtuW9HZAaB6kKa/Q=="));

    headers.put("Sec-Websocket-Version", Arrays.asList("13"));

    headers.put("Upgrade", Arrays.asList("websocket"));

    headers.put("User-Agent", Arrays.asList("Mozill..."));

    conf.beforeRequest(headers);

    return config;`

    问题如果我解决了这个问题并收到http升级请求的101个状态码,我的判断是否正确?(我的意思是,接下来我该如何处理这些细节?)

    请不要评判我,我刚开始使用Java的websockets,而且我不太了解javascript,我想用JSR-356在纯Java中做这个客户端。我已经用websockets做过一些小例子,但是我找不到一个好的客户端,它带有头和更复杂的握手。

    在不了解所有详细信息的情况下,是否可能连接到未知服务器?

    我使用一个编程端点并导入javax.websocket.ContainerProvider;用于处理来自JSR356的websocket连接。

    展开全文
  • WebSocket握手期间出错:意外的响应代码:500我在我的网站上使用websocket,但随机发送给我以下错误消息:WebSocket连接到'ws://client.mydomain....WebSocket握手期间出错:意外的响应代码:500这里是我...

    WebSocket握手期间出错:意外的响应代码:500

    我在我的网站上使用websocket,但随机发送给我以下错误消息:

    WebSocket连接到'ws://client.mydomain.com/socket.io/?EIO = 3&transport = websocket&sid = 4Kbec5T_XStAC949AACS'失败:WebSocket握手期间出错:意外的响应代码:500

    这里是我如何连接到websocket在我的应用程序(注意这是一个Angular应用程序)。

    app.factory('clientSocket', ['$sessionStorage', 'socketFactory', function ($sessionStorage, socketFactory) { var connection = ''; $.ajax({ url: 'config.json', async: false, dataType: 'json', success: function (response) { connection = response.app_url; } }); var myIoSocket = io.connect(connection); var clientSocket = socketFactory({ ioSocket: myIoSocket }); clientSocket.forward('someEvent'); clientSocket.on('connect', function () { if ($sessionStorage.activeUser != null) { clientSocket.emit('userData', $sessionStorage.activeUser.user); } }); return clientSocket; }]);

    我不是很确定问题是什么,但基本上连接string看起来像这样:

    http://client.mydomain.com

    谁能告诉我发生了什么事?

    你不能通过在Ajax的成功callback里join其余的代码来尝试吗? 喜欢这个:

    app.factory('clientSocket', ['$sessionStorage', 'socketFactory', function ($sessionStorage, socketFactory) { var connection = ''; $.ajax({ url: 'config.json', async: false, dataType: 'json', success: function (response) { connection = response.app_url; var myIoSocket = io.connect(connection); var clientSocket = socketFactory({ ioSocket: myIoSocket }); clientSocket.forward('someEvent'); clientSocket.on('connect', function () { if ($sessionStorage.activeUser != null) { clientSocket.emit('userData', $sessionStorage.activeUser.user); } }); return clientSocket; } });

    展开全文
  • 方法一:基于HandshakeComplete自定义事件特点:使用简单、校验在握手成功之后、失败信息可以通过Websocket发送回客户端。1.1 从netty源码出发 一般地,我们将netty内置的WebSocketServerPro...

    6934ae44d4eeff7e1606e37d1197f5ee.gif

    在使用Netty开发Websocket服务时,通常需要解析来自客户端请求的URL、Headers等等相关内容,并做相关检查或处理。本文将讨论两种实现方法。

    方法一:基于HandshakeComplete自定义事件

    特点:使用简单、校验在握手成功之后、失败信息可以通过Websocket发送回客户端。

    1.1 从netty源码出发

    一般地,我们将netty内置的WebSocketServerProtocolHandler作为Websocket协议的主要处理器。通过研究其代码我们了解到在本处理器被添加到PiplinehandlerAdded方法将会被调用。此方法经过简单的检查后将WebSocketHandshakeHandler添加到了本处理器之前,用于处理握手相关业务。

    我们都知道Websocket协议在握手时是通过HTTP(S)协议进行的,那么这个WebSocketHandshakeHandler应该就是处理HTTP相关的数据的吧?

    下方代码经过精简,放心阅读?

    package io.netty.handler.codec.http.websocketx;

    public class WebSocketServerProtocolHandler extends WebSocketProtocolHandler {

        @Override
        public void handlerAdded(ChannelHandlerContext ctx) {
            ChannelPipeline cp = ctx.pipeline();
            if (cp.get(WebSocketServerProtocolHandshakeHandler.class) == null) {
                // Add the WebSocketHandshakeHandler before this one.
                cp.addBefore(ctx.name(), WebSocketServerProtocolHandshakeHandler.class.getName(),
                        new WebSocketServerProtocolHandshakeHandler(serverConfig));
            }
            //...
        }
    }

    我们来看看WebSocketServerProtocolHandshakeHandler都做了什么操作。

    channelRead方法会尝试接收一个FullHttpRequest对象,表示来自客户端的HTTP请求,随后服务器将会进行握手相关操作,此处省略了握手大部分代码,感兴趣的同学可以自行阅读。

    可以注意到,在确认握手成功后,channelRead将会调用两次fireUserEventTriggered,此方法将会触发自定义事件。其他(在此处理器之后)的处理器会触发userEventTriggered方法。其中一个方法传入了WebSocketServerProtocolHandler对象,此对象保存了HTTP请求相关信息。那么解决方案逐渐浮出水面,通过监听自定义事件即可实现检查握手的HTTP请求。

    package io.netty.handler.codec.http.websocketx;

    /**
     * Handles the HTTP handshake (the HTTP Upgrade request) for {@link WebSocketServerProtocolHandler}.
     */

    class WebSocketServerProtocolHandshakeHandler extends ChannelInboundHandlerAdapter {
        @Override
        public void channelRead(final ChannelHandlerContext ctx, Object msg) throws Exception {
            final FullHttpRequest req = (FullHttpRequest) msg;
            if (isNotWebSocketPath(req)) {
                ctx.fireChannelRead(msg);
                return;
            }

            try {

                //...
                    
                if (!future.isSuccess()) {
                    
                } else {
                    localHandshakePromise.trySuccess();
                    // Kept for compatibility
                    ctx.fireUserEventTriggered(
                            WebSocketServerProtocolHandler.ServerHandshakeStateEvent.HANDSHAKE_COMPLETE);
                    ctx.fireUserEventTriggered(
                            new WebSocketServerProtocolHandler.HandshakeComplete(
                                    req.uri(), req.headers(), handshaker.selectedSubprotocol()));
                }
            } finally {
                req.release();
            }
        }
    }

    1.2 解决方案

    下面的代码展示了如何监听自定义事件。通过抛出异常可以终止链接,同时可以利用ctx向客户端以Websocket协议返回错误信息。因为此时握手已经完成,所以虽然这种方案简单的过分,但是效率并不高,耗费服务端资源(都握手了又给人家踢了QAQ)。

    private final class ServerHandler extends SimpleChannelInboundHandler<DeviceDataPacket{
        @Override
        public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
            
            if (evt instanceof WebSocketServerProtocolHandler.HandshakeComplete) {
                // 在此处获取URL、Headers等信息并做校验,通过throw异常来中断链接。
            }
            super.userEventTriggered(ctx, evt);
        }
    }

    1.3 ChannelInitializer实现

    附上Channel初始化代码作为参考。

    private final class ServerInitializer extends ChannelInitializer<SocketChannel{

        @Override
        protected void initChannel(SocketChannel ch) {
            ch.pipeline()
                    .addLast("http-codec"new HttpServerCodec())
                    .addLast("chunked-write"new ChunkedWriteHandler())
                    .addLast("http-aggregator"new HttpObjectAggregator(8192))
                    .addLast("log-handler"new LoggingHandler(LogLevel.WARN))
                    .addLast("ws-server-handler"new WebSocketServerProtocolHandler(endpointUri.getPath()))
                    .addLast("server-handler"new ServerHandler());
        }
    }

    方法二:基于新增安全检查处理器

    特点:使用相对复杂、校验在握手成功之前、失败信息可以通过HTTP返回客户端。

    2.1 解决方案

    编写一个入站处理器,接收FullHttpMessage消息,在Websocket处理器之前检测拦截请求信息。下面的例子主要做了四件事情:

    1. 从HTTP请求中提取关心的数据
    2. 安全检查
    3. 将结果和其他数据绑定在Channel
    4. 触发安全检查完毕自定义事件
    public class SecurityServerHandler extends ChannelInboundHandlerAdapter {
        private static final ObjectMapper json = new ObjectMapper();

        public static final AttributeKey SECURITY_CHECK_COMPLETE_ATTRIBUTE_KEY =
                AttributeKey.valueOf("SECURITY_CHECK_COMPLETE_ATTRIBUTE_KEY");@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {if(msg instanceof FullHttpMessage){//extracts device information headers
                HttpHeaders headers = ((FullHttpMessage) msg).headers();
                String uuid = Objects.requireNonNull(headers.get("device-connection-uuid"));
                String devDescJson = Objects.requireNonNull(headers.get("device-description"));//deserialize device description
                DeviceDescription devDesc = json.readValue(devDescJson, DeviceDescriptionWithCertificate.class);//check ......//
                SecurityCheckComplete complete = new SecurityCheckComplete(uuid, devDesc);
                ctx.channel().attr(SECURITY_CHECK_COMPLETE_ATTRIBUTE_KEY).set(complete);
                ctx.fireUserEventTriggered(complete);
            }//other protocolssuper.channelRead(ctx, msg);
        }@Getter@AllArgsConstructorpublic static final class SecurityCheckComplete {private String connectionUUID;private DeviceDescription deviceDescription;
        }
    }

    在业务逻辑处理器中,可以通过组合自定义的安全检查事件和Websocket握手完成事件。例如,在安全检查后进行下一步自定义业务检查,在握手完成后发送自定义内容等等,就看各位同学自由发挥了。

     private final class ServerHandler extends SimpleChannelInboundHandler<DeviceDataPacket{

        public final AttributeKey @Overridepublic void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {if (evt instanceof SecurityCheckComplete){
                log.info("Security check has passed");
                SecurityCheckComplete complete = (SecurityCheckComplete) evt;
                listener.beforeConnect(complete.getConnectionUUID(), complete.getDeviceDescription());
            }else if (evt instanceof WebSocketServerProtocolHandler.HandshakeComplete) {
                log.info("Handshake has completed");
                SecurityCheckComplete complete = ctx.channel().attr(SecurityServerHandler.SECURITY_CHECK_COMPLETE_ATTRIBUTE_KEY).get();
                DeviceDataServer.this.listener.postConnect(complete.getConnectionUUID(),new DeviceConnection(ctx.channel(), complete.getDeviceDescription()));
            }super.userEventTriggered(ctx, evt);
        }
    }

    2.2 ChannelInitializer实现

    附上Channel初始化代码作为参考。

    private final class ServerInitializer extends ChannelInitializer<SocketChannel{

        @Override
        protected void initChannel(SocketChannel ch) {
            ch.pipeline()
                    .addLast("http-codec"new HttpServerCodec())
                    .addLast("chunked-write"new ChunkedWriteHandler())
                    .addLast("http-aggregator"new HttpObjectAggregator(8192))
                    .addLast("log-handler"new LoggingHandler(LogLevel.WARN))
                    .addLast("security-handler"new SecurityServerHandler())
                    .addLast("ws-server-handler"new WebSocketServerProtocolHandler(endpointUri.getPath()))
                    .addLast("packet-codec"new DataPacketCodec())
                    .addLast("server-handler"new ServerHandler());
        }
    }

    总结

    上述两种方式分别在握手完成后和握手之前拦截检查;实现复杂度和性能略有不同,可以通过具体业务需求选择合适的方法。

    Netty增强了责任链模式,使用userEvent传递自定义事件使得各个处理器之间减少耦合,更专注于业务。但是、相比于流动于各个处理器之间的"主线"数据来说,userEvent传递的"支线"数据往往不受关注。通过阅读Netty内置的各种处理器源码,探索其产生的事件,同时在开发过程中加以善用,可以减少冗余代码。另外在开发自定义的业务逻辑时,应该积极利用userEvent传递事件数据,降低各模块之间代码耦合。

    琐碎时间想看一些技术文章,可以去公众号菜单栏翻一翻我分类好的内容,应该对部分童鞋有帮助。同时看的过程中发现问题欢迎留言指出,不胜感谢~。另外,有想多了解哪些方面内容的可以留言(什么时候,哪篇文章下留言都行),附菜单栏截图(PS:很多人不知道公众号菜单栏是什么)

    0ebd04e3773472efe28869efaedef4aa.png

    END

    838e6825a76b3d98247b6ac9328aa600.png

    我知道你 “在看e1c16e18c78387bccfcc85bc1ab48770.gif

    展开全文
  • 2016-02-16 15:23:490You can find the all the code below,started the tomcat server and It's perfectly working.But While making websocket request I'm getting 404 error.This is the error in chrome consol...
  • 最近已经陷于了Socket测试的泥潭中了,之前用Java写了一个Client封装类,本想在经历过本轮测试之后,写一些文档在发出来,没想到测试对象用的是Socket.IO,所以先把一个写好的WebSocket的Client的类发出来,分享一下...
  • websocket握手失败可能的原因之一

    千次阅读 2020-02-15 21:39:36
    server.servlet.context-path=/*** 如果在application.properties中配置了上面的属性,则在连接服务器时应该按照下面的链接进行连接,***是你配置的前缀 ...否则就会出现握手失败的错误。 在MyWeb...
  • 当被提及websocket的时候突然头脑中搭上了这根线。 一、WebSocket是HTML5出的东西(协议),也就是说HTTP协议没有变化,或者说没关系,但HTTP是不支持持久连接的(长连接,循环连接的不算) 首...
  • 之前也有博客介绍过golang中使用websocket,其中介绍了两个第三方库:gorilla/websocketnkovacs/go-socket.ioGo实战–golang中使用WebSocket实时聊天室(gorilla/websocket、nkovacs/go-socket.io)所以,趁着介绍...
  • 我想用C实现一个WebSocket服务器,但是始终不能握手成功,在谷歌浏览器用一个静态网页做调试,以下是C处理请求代码的部分 ``` while (true) { app_sock = accept(listen_sock, (struct sockaddr *)&clientaddr,...
  • <p>I found <a href="http://procbits.com/connecting-to-a-sockjs-server-from-native-html5-websocket" rel="nofollow">this article</a> referring to node.js indicating to add /websocket to my client ...
  • 实现websocket通讯,和广播消息添加依赖<dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.1.Final</version></dependency...
  • <div><h2>DESC <h2>ENV <p>Platform: <p>Node.js Version:v8.4.0 <p>ThinkJS Version:3.1.1</p><p>该提问来源于开源项目:thinkjs/thinkjs</p></div>
  • 但是一部署到生产服务器上,Web端只要一new WebSocket(url),就返回握手失败404。各种方法都试过了,全部无效。 什么改nginx的Upgrade升级啦(这个是必须改的),注释掉WebsocketConfig类中的Bean啦(我压根就没建...
  • <p>"WebSocket connection to failed: Error during WebSocket handshake: Unexpected response code: 200" <p>This is my apache Configuration <pre><code>ServerName 192.168.56.106 ProxyRequests off ...
  • 我写的websocket 使用的是net core 2.2写的,一开始的时候报错说握手失败,直到后来看到别的大神说,初始化websocket的时候一定要在app.UseMvc之前执行,否则会被mvc 拦截,走不了自己实现的websocket请求处理,贴...
  •  b) websocket._exceptions.WebsocketBadStatusException: Handshake status 400  答:Access-Control-Allow-Origin 是HTML5中定义的一种服务器端返回Response header,用来解决资源(比如字体)的跨域权限问题。...
  • WebSocket connection to 'ws://127.0.0.1:8888/' failed: Error during WebSocket handshake: Response must not include 'Sec-WebSocket-Protocol' header if not present in request: chat 这个,在后端握手时...
  • 今天在学习webSocket这一块,需要实现后台不断推数据给前端。先百度例子,考下来本机跑一下,但是一直报错 failed: Error during WebSocket handshake: Unexpected response code:404 这个错误。百度了白天...
  • 但如果是使用springboot的内置容器,则需要多几个步骤: 1、引入依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> 2、...
  • websocket连接失败

    万次阅读 2015-06-26 23:31:21
    websocket连接失败@(markdown) 最近项目里调试websocket相关的nodejs实现的server,刚接触web开发...首先,nodeserver用的socketio,于是写了个页面,用js发起websocket握手,发现一直是longpoll,猜测webserver不支持
  • 方法一:基于HandshakeComplete自定义事件特点:使用简单、校验在握手成功之后、失败信息可以通过Websocket发送回客户端。1.1 从netty源码出发一般地,我们将netty内置的WebSocketServerProtocolH...
  • 方法一:基于HandshakeComplete自定义事件特点:使用简单、校验在握手成功之后、失败信息可以通过Websocket发送回客户端。1.1 从netty源码出发 一般地,我们将netty内置的WebSocketServerPro...
  • WebSocket握手期间出错,响应码:400。 出现原因:可能你的应用程序版本低于nginx。 我的解决方式:告诉nginx在和服务端通信的时候,使用http/1.1,并且Nginx当想要使用WebSocket时由浏览器通过HTTP发起的Upgrade...
  • 最近因为有需要统计实时客流信息的需求,考虑到使用轮询请求开销大,所以想整合websocket使用。 但是却一直报404错误,路径项目,后端websocket代码怎么改都没用,网上说是tomcat问题,需要tomcat8才能支持...
  • 用java实现的websocket 我在不适用其他框架的时候可以正常握手访问 但是最近加在一个适用spring的项目中,一直握手不成功,这是什么原因? 以下是浏览器返回的信息 ``` Request URL:ws://127.0.0.1:8080/spring...
  • WebSocket是HTML5以后带来的一种新的客户端和服务端的双向通信方式,简言之就是客户端...后来WebSocket出来后,改变了这种方式,前后两端只需要建立一次握手,就可以互相发送消息,这样就保证了信息的实时性。搭建群...

空空如也

空空如也

1 2 3
收藏数 58
精华内容 23
关键字:

websocket握手失败