WebSocket實現多人實時聊天
chat.html:
<!DOCTYPE html>
<html>
<head>
<meta name="author" content="Yeeku.H.Lee(CrazyIt.org)" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title> 使用WebSocket通訊 </title>
<script type="text/javascript">
// 建立WebSocket物件
var webSocket = new WebSocket("ws://127.0.0.1:8888/WebSocket/websocket/chat");
var sendMsg = function()
{
var inputElement = document.getElementById('msg');
// 傳送訊息
webSocket.send(inputElement.value);
// 清空單行文字框
inputElement.value = "";
}
var send = function(event)
{
if (event.keyCode == 13)
{
sendMsg();
}
};
webSocket.onopen = function()
{
// 為onmessage事件繫結監聽器,接收訊息
webSocket.onmessage= function(event)
{
var show = document.getElementById('show')
// 接收、並顯示訊息
show.innerHTML += event.data + "<br/>";
show.scrollTop = show.scrollHeight;
}
document.getElementById('msg').onkeydown = send;
document.getElementById('sendBn').onclick = sendMsg;
};
webSocket.onclose = function ()
{
document.getElementById('msg').onkeydown = null;
document.getElementById('sendBn').onclick = null;
Console.log('WebSocket已經被關閉。');
};
</script>
</head>
<body>
<div style="width:600px;height:240px;
overflow-y:auto;border:1px solid #333;" id="show"></div>
<input type="text" size="80" id="msg" name="msg" placeholder="輸入聊天內容"/>
<input type="button" value="傳送" id="sendBn" name="sendBn"/>
</body>
</html>
package lee;
import java.io.IOException;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger;
import javax.websocket.*;
import javax.websocket.server.*;
@ServerEndpoint(value = "/websocket/chat")
public class ChatEntpoint
{
private static final String GUEST_PREFIX = "訪客";
private static final AtomicInteger connectionIds = new AtomicInteger(0);
// 定義一個集合,用於儲存所有接入的WebSocket客戶端
private static final Set<ChatEntpoint> clientSet =
new CopyOnWriteArraySet<>();
// 定義一個成員變數,記錄WebSocket客戶端的聊天暱稱
private final String nickname;
// 定義一個成員變數,記錄與WebSocket之間的會話
private Session session;
public ChatEntpoint()
{
nickname = GUEST_PREFIX + connectionIds.getAndIncrement();
}
// 當客戶端連線進來時自動激發該方法
@OnOpen
public void start(Session session)
{
this.session = session;
// 將WebSocket客戶端會話新增到集合中
clientSet.add(this);
String message = String.format("【%s %s】"
, nickname, "加入了聊天室!");
// 傳送訊息
broadcast(message);
}
// 當客戶端斷開連線時自動激發該方法
@OnClose
public void end()
{
clientSet.remove(this);
String message = String.format("【%s %s】"
, nickname, "離開了聊天室!");
// 傳送訊息
broadcast(message);
}
// 每當收到客戶端訊息時自動激發該方法
@OnMessage
public void incoming(String message)
{
String filteredMessage = String.format("%s: %s"
, nickname, filter(message));
// 傳送訊息
broadcast(filteredMessage);
}
// 當客戶端通訊出現錯誤時,激發該方法
@OnError
public void onError(Throwable t) throws Throwable
{
System.out.println("WebSocket服務端錯誤 " + t);
}
// 實現廣播訊息的工具方法
private static void broadcast(String msg)
{
// 遍歷伺服器關聯的所有客戶端
for (ChatEntpoint client : clientSet)
{
try
{
synchronized (client)
{
// 傳送訊息
client.session.getBasicRemote().sendText(msg);
}
}
catch (IOException e)
{
System.out.println("聊天錯誤,向客戶端 "
+ client + " 傳送訊息出現錯誤。");
clientSet.remove(client);
try
{
client.session.close();
}
catch (IOException e1){}
String message = String.format("【%s %s】",
client.nickname, "已經被斷開了連線。");
broadcast(message);
}
}
}
// 定義一個工具方法,用於對字串中的HTML字元標籤進行轉義
private static String filter(String message)
{
if (message == null)
return null;
char content[] = new char[message.length()];
message.getChars(0, message.length(), content, 0);
StringBuilder result = new StringBuilder(content.length + 50);
for (int i = 0; i < content.length; i++)
{
// 控制對尖括號等特殊字元進行轉義
switch (content[i])
{
case '<':
result.append("<");
break;
case '>':
result.append(">");
break;
case '&':
result.append("&");
break;
case '"':
result.append(""");
break;
default:
result.append(content[i]);
}
}
return (result.toString());
}
}