初识websocket

一、定义


websocket.jpg

WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端。
WebSocket协议支持(在受控环境中运行不受信任的代码的)客户端与(选择加入该代码的通信的)远程主机之间进行全双工通信。
二、产生的背景
简单的说,WebSocket协议之前,双工通信是通过不停发送HTTP请求,从服务器拉取更新来实现,这导致了效率低下。WebSocket解决了这个问题
三、解决的问题
1.服务器被迫为每个客户端使用许多不同的底层TCP连接:一个用于向客户端发送信息,其它用于接收每个传入消息。
2.有些协议有很高的开销,每一个客户端和服务器之间都有HTTP头。
3.客户端脚本被迫维护从传出连接到传入连接的映射来追踪回复。
四、实现原理和好处
1、原理:在实现websocket连线过程中,需要通过浏览器发出websocket连线请求,然后服务器发出回应,这个过程通常称为“握手” 。
2、好处
① Header
互相沟通的Header是很小的-大概只有 2 Bytes
②Server Push
服务器的推送,服务器不再被动的接收到浏览器的请求之后才返回数据,而是在有新数据时就主动推送给浏览器。

五、请求响应案例
浏览器请求
GET /webfin/websocket/ HTTP/1.1

Host: localhost
  Upgrade: websocket

Connection: Upgrade
  Sec-WebSocket-Key: xqBt3ImNzJbYqRINxEFlkg==
  Origin: http://服务器地址
  Sec-WebSocket-Version: 13

服务器回应
HTTP/1.1 101 Switching Protocols
  Upgrade: websocket
  Connection: Upgrade
  Sec-WebSocket-Accept: K7DJLdLooIwIG/MOpvWFB3y3FE8=
WebSocket借用http请求进行握手,相比正常的http请求,多了一些内容。
其中,Upgrade: websocket
Connection: Upgrade
表示希望将http协议升级到Websocket协议。
Sec-WebSocket-Key是浏览器随机生成的base64 encode的值,用来询问服务器是否是支持WebSocket。

服务器返回
Upgrade: websocket
Connection: Upgrade
告诉浏览器即将升级的是Websocket协议
Sec-WebSocket-Accept是将请求包“Sec-WebSocket-Key”的值,与”258EAFA5-E914-47DA-95CA-C5AB0DC85B11″这个字符串进行拼接,然后对拼接后的字符串进行sha-1运算,再进行base64编码得到的。用来说明自己是WebSocket助理服务器。

六、个人demo
1.服务端
/*

  • websocket服务端

  • 客户端向服务器端建立websocket的url

  • */
    @ServerEndpoint("/websocket")
    @Component
    public class WebSocketServer {
    //计算当前在线人数
    private static int onlineCount=0;
    //concurrent包的线程安全set,用来存放每个客户端对应的mywebsocket对象,必须
    private static CopyOnWriteArraySet<WebSocketServer>webSocketSet=new CopyOnWriteArraySet<>();
    //与某个客户端的连接会话,需要通过它来给客户端发送数据,必须
    private Session session;

    /*

    • 连接建立成功使用的方法
    • /
      @OnOpen
      public void onOpen(Session session){
      this.session=session;
      webSocketSet.add(this);
      addOnlineCount(); //在线数加1
      System.out.println("有新窗口开始监听,当前在线人数为" + getOnlineCount());
      try {
      sendMessage("连接成功");
      } catch (IOException e) {
      System.out.println("WebSocket IO异常");
      }
      }
      /

      连接关闭调用的方法
      /
      @OnClose
      public void onClose() {
      webSocketSet.remove(this); //从set中删除
      subOnlineCount(); //在线数减1
      System.out.println("有连接关闭!当前在线人数为" + getOnlineCount());
      }
      /
    • 收到客户端消息后调用的方法
    • @param message 客户端发送过来的消息
      /
      @OnMessage
      public void onMessage(String message, Session session) {
      System.out.println("收到客户端的信息:" + message);
      //群发消息
      for (WebSocketServer item : webSocketSet) {
      try {
      item.sendMessage(message);
      } catch (IOException e) {
      e.printStackTrace();
      }
      }
      }
      /
      *
    • @param session
    • @param error
      */
      @OnError
      public void onError(Session session, Throwable error) {
      System.out.println("发生错误");
      error.printStackTrace();
      }

    /**

    • 实现服务器主动推送
      */
      public void sendMessage(String message) throws IOException {
      this.session.getBasicRemote().sendText(message);
      }
/**
 * 群发自定义消息
 */
public static void sendInfo(String message) throws IOException {
    System.out.println("推送消息内容:" + message);
    for (WebSocketServer item : webSocketSet) {
        try {
            item.sendMessage(message);
        } catch (IOException e) {
            continue;
        }
    }
}

public static synchronized int getOnlineCount() {
    return onlineCount;
}

public static synchronized void addOnlineCount() {
    WebSocketServer.onlineCount++;
}

public static synchronized void subOnlineCount() {
    WebSocketServer.onlineCount--;
}

}
2.配置webSocket
/*

  • WEBSOCKET配置类

  • 开启websocket支持

  • */
    @Configuration
    public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter(){
    return new ServerEndpointExporter();
    }
    }
    3.提供接口
    @RestController
    @RequestMapping(value = "/socket")
    public class WebSocketController {
    //推送数据接口
    @RequestMapping("/push")
    public String pushMsg(HttpServletRequest request) {
    String message=request.getParameter("info");
    try {
    WebSocketServer.sendInfo(message);
    } catch (IOException e) {
    e.printStackTrace();
    }
    return "success";
    }
    }
    4.主类
    @SpringBootApplication
    public class WebsocketApplication {

    public static void main(String[] args) {
    SpringApplication.run(WebsocketApplication.class, args);
    }
    }
    5.前端客户端
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>websocket页面</title>
    <style>
    .ta1{
    width: 400px;
    height: 400px;
    overflow-x:hidden;
    background-color: tan
    }
    .ta2{
    width:400px;
    height:200px;
    overflow-x:hidden;
    background-color: aquamarine;
    }
    .one{
    width: 300px;
    height: 30px;
    border-radius: 5px;
    background-color: lightcoral
    }
    .two{
    width: 50px;
    height: 30px;
    background-color: cadetblue;
    border-radius: 5px;
    }
    body{
    text-align: center;
    }
    </style>
    </head>
    <body>
    <h2>WebSocket练习</h2>



    <script>
    function sendone() {
    socket.send(document.getElementById("userMsg").value);
    document.getElementById("userMsg").value=null;
    }
    var socket;
    if (typeof(WebSocket) == "undefined") {
    console.log("您的浏览器不支持WebSocket");
    } else {
    console.log("您的浏览器支持WebSocket");
    //实现化WebSocket对象,指定要连接的服务器地址与端口建立连接
    socket = new WebSocket("ws://localhost:8080/websocket");

      //打开事件
      socket.onopen = function () {
          console.log("Socket已打开");
          //socket.send("这是来自客户端的消息:" + new Date());
      };
    
      //获得消息事件
      socket.onmessage = function (msg) {
          console.log(msg.data);
          alert(msg.data);
          document.getElementById("tao").value=document.getElementById("tao").value+'\n'+msg.data;
      };
    
      //关闭事件
      socket.onclose = function () {
          console.log("Socket已关闭");
      };
    
      //发生了错误事件
      socket.onerror = function () {
          alert("Socket发生了错误");
      }
    

    }
    </script>
    <h3>消息显示区域</h3>
    <div>
    <textarea class="ta1" id="tao">

    </textarea>
    </div>
    <div>
    <input type="text" class="one" placeholder="输入你要发送的信息" value="" id="userMsg">
    <input type="button" class="two" value="发送" onclick="sendone()">
    </div>



    <h3>服务器端广播消息区域</h3>
    <div>
    <textarea class="ta2">

    </textarea>
    </div>
    </body>
    </html>
    6.前端服务器端
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>server页面</title>
    <style>
    textarea{
    width:200px;
    height: 30px;
    background-color: lightcoral;
    overflow-x:hidden;
    }
    .two{
    width: 50px;
    height: 30px;
    background-color: cadetblue;
    border-radius: 5px;
    }
    body{
    text-align: center;
    }
    </style>
    </head>
    <body>
    <h3>服务器推送消息</h3>

<form action="/socket/push" method="post" accept-charset="utf-8" name="loginfrom">
<textarea id="info" name="info"></textarea>
<input type="submit" class="two" value="发送">
</form>

</body

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容