1. 程式人生 > >WebSocket簡單聊天

WebSocket簡單聊天

剛學習了WebSocket ,寫了一個簡單的聊天功能,在這裡記錄一下;想學習的也可以參考。

WebSocket協議是基於TCP的一種新的網路協議。它實現了瀏覽器與伺服器全雙工(full-duplex)通訊——允許伺服器主動傳送資訊給客戶端。

首先給出程式碼,執行一下看看效果:
(介面有些醜,忽略這些細節,之後再進行美化;)
index.jsp 這是登入頁面,獲取聊天時的暱稱;

<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>登入</title> </head> <style> .container{ width: 400px; height
: 600px
; background: navajowhite; margin: 0 auto; text-align: center; }
.pic{ margin: 0 auto; width:100px; height: 100px; border-radius: 50px; background:gray; } #name{ width: 200px; height: 50px; margin-top: 200
px
; }
button{ text-decoration: none; background: darkcyan; width: 200px; height: 50px; }
</style> <script type="text/javascript" src="jquery/jquery-2.2.4.min.js" ></script> <body> <header>聊天</header> <div class="container"> <form action="/UserServlet" method="post" id="login"> <div class="pic"> </div> <div class="login"> <div class="name"> <input type="text" name="nick" id="name"/> </div> <div> <!-- <a href="javascript:goChat()">登入</a>--> <button class="but" onclick="goChat()">登入</button> </div> </div> </form> </div> </body> <script type="text/javascript"> function goChat(){ $("#login").submit(); } </script> </html>

chatroom.jsp 這是聊天的頁面,能看到所有使用者傳送的訊息:

<%--
  Created by IntelliJ IDEA.
  User: Administrator
  Date: 2017/10/11 0011
  Time: 18:43
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<style type="text/css">
    .container{
        width: 400px;
        height: 600px;
        background: navajowhite;
        margin: 0 auto;
        text-align: center;
    }
    .message{
        width:400px;
        height: 400px;
        position: absolute;
        top:100px;
        background: indianred;

    }
    li{
        margin: 0;
        background: khaki;
        width: 300px;
        height: 20px;
        list-style:none;

    }
    .msg{
        position: absolute;
        width:400px;
        height: 50px;
        top:550px;
        background: indianred;
    }
    input[name = "msg"]{
        width: 200px;
        height: 40px;
    }
    button{
        width: 90px;
        height: 47px;
    }
</style>
<script type="text/javascript" src="jquery/jquery-2.2.4.min.js" ></script>
<body>
<div class="container">

    <div class="message">
        <ul class="list">

        </ul>
    </div>
    <% String nick = (String)request.getAttribute("nick");%>
    <div class="msg">
        <input type="text" name="msg" id="msg" value="" /><button class="send" value="">傳送</button>
    </div>

</div>

</body>

<script type="text/javascript">
    var ws = null;
    if(WebSocket){
        ws = new WebSocket("ws://localhost:8080/chat");
    }else{
        alert("瀏覽器不支援");
    }
    ws.onopen = function(){
        ws.send("使用者<%=nick%>加入聊天室");
    }

    ws.onmessage = function(event){
        showMessage(event.data);
    }

    function showMessage(msg){
        var message = $(".list");
        var html = message.html();
        html += "<li>"+msg+"</li>";
        message.html(html);
        message.scrollTop(message[0].scrollHeight);

    }

    $(".send").click(function () {
        var msg = $(this).siblings("input").val();
        ws.send("<%=nick%>說:"+msg);
        $(this).siblings("input").val("");
    })

</script>



</html>

UserServlet 用於轉發使用者名稱,之後可以用框架實現:

package com.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/UserServlet")
public class UserServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        String nick = request.getParameter("nick");
        request.setAttribute("nick",nick);
        request.getRequestDispatcher("/chatroom.jsp").forward(request,response);


    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request,response);
    }
}

ChatServer 聊天的伺服器 用於接收發送訊息

package com.websocket;


import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;

@ServerEndpoint("/chat")
public class ChatServer {

    private Session session;
//    private static Map<String,ChatServer> map = new HashMap(String,ChatServer);
    private static CopyOnWriteArraySet<ChatServer> servers = new CopyOnWriteArraySet<ChatServer>();

    @OnOpen
    public void onOpen(Session session){
        this.session = session;
        servers.add(this);
        System.out.println("建立連線"+session.getId());

    }
    @OnMessage
    public void onMessage(String msg){
//        try {
//            this.session.getBasicRemote().sendText(msg);
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
        System.out.println("接受資訊:"+msg);
        //向所有的使用者傳送訊息
        try{
            for (ChatServer server:servers){

                server.session.getBasicRemote().sendText(msg);

            }
        }catch (IOException e){
            e.printStackTrace();
        }
    }

    @OnError
    public void onError(Throwable error){
        System.out.println("錯誤:");
        error.printStackTrace();
    }
    @OnClose
    public void onClose(){
        servers.remove(this);
    }

}

簡單說明一下執行的過程:

在登入介面,輸入使用者名稱,登入, 會通過表單提交的UserServlet,UserServlet再轉發到chatroom.jsp
在載入的時候,建立了一個websocket物件
ws = new WebSocket(“ws://localhost:8080/chat”);
就是這句, 這裡我有一個疑惑,在IDEA中要直接寫ChatServer的路徑, 在Eclipse 要加上專案名;這個問題糾結了好久,還是沒有答案;
找到ChatServer,如果連線成功了 ,就會執行 onopen方法 ,控制檯輸出對應的資料,
同樣,jsp中的 ws.onopen的方法也會執行; ws.send(“使用者<%=nick%>加入聊天室”); 這句就是向服務端傳送了訊息, 再服務端通過 onMessage 接收資料,控制檯輸出; 這樣就可以簡單的傳送訊息;
不過這樣只能是自己看到訊息 ,需要對每一個線上的使用者都發送訊息
private static CopyOnWriteArraySet servers = new CopyOnWriteArraySet(); 用來儲存每個使用者的 websocket ;

servers.add(this); 使用者連線時,向set中新增一個websocket

try{
for (ChatServer server:servers){
server.session.getBasicRemote().sendText(msg);
}
}catch (IOException e){
e.printStackTrace();
}

通過遍歷servers中的websocket,向每一使用者傳送訊息,
這樣, 簡單的聊天 就實現了;