基于Java和websocket的在线聊天程序(可群发和选择用户)

最近在开发程序过程中需要用到服务器端推送,查阅资料主要有三种方式:

  第一是使用ajax长轮询;

  第二是使用cmet4j;

  第三是使用websocket。

  关于这三种方式,websocket优点明显,主要包括:

(1)建立在 TCP 协议之上,服务器端的实现比较容易。

(2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。

(3)数据格式比较轻量,性能开销小,通信高效。

(4)可以发送文本,也可以发送二进制数据。

(5)没有同源限制,客户端可以与任意服务器通信。

(6)协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。

websocket的介绍网上有很多,用websocket实现的聊天室也很多,但功能都不完善(也许是我没看懂别人的代码),而且也不容易看懂。对于没有接触过这的来说,因为很多基础概念没弄懂,比如远程端点,websocket的session等。关于websocket有本教材——Java.WebSocket.Programming,国内翻译的感觉不怎么样,简单了解看前面四章就够了,下面是教材:http://www.java1234.com/a/javabook/javabase/2016/0605/6215.html

基于Java和websocket的在线聊天程序(可群发和选择用户)_第1张图片

websocket需要websocket-api.jar这个包,这个包tomcat已经自带,因此不用手动将这个包导入自己的项目;传输数据使用JSON的jar包(6个)需要添加到自己的项目中。

一、服务器代码

package com;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import net.sf.json.*; 

import javax.websocket.*;
import javax.websocket.server.*;


@ServerEndpoint(value = "/chat")
public class EndPoint
{
	//远程endPoint,使用userName作为Key进行绑定
	private static ConcurrentMapclientSet = new ConcurrentHashMap<>(); 
	
	//连接时,获得用户名
	private String user;
	//_websocket会话
	private Session session;


	@OnOpen
	public void start(Session session)
	{
		this.session = session;
		user=this.session.getRequestParameterMap().get("user").get(0);
		
		clientSet.put(user, this);
		
		Listlist =new ArrayList<>( clientSet.keySet());
	    broadcast(list);
	    
	    Message msg=new Message("server","All",String.format("【%s %s】",user, "加入了聊天室!"));
		sendMessage(msg);
	}
	// 当端断开连接时自动激发该方法
	@OnClose
	public void end()
	{
		clientSet.remove(user);
		Message msg=new Message("server","All",String.format("【%s %s】",user, "离开了聊天室!"));
		sendMessage(msg);
		
		Listlist =new ArrayList<>( clientSet.keySet());
	    broadcast(list);
		
	}
	// 每当收到客户端消息时自动激发该方法
	@OnMessage
	public void onMessage(String message)
	{
		JSONObject json = JSONObject.fromObject(message);
	    Message msg = (Message)JSONObject.toBean(json,Message.class);

		sendMessage(msg);
	}
	// 当客户端通信出现错误时,激发该方法
	@OnError
	public void onError(Throwable t) throws Throwable
	{
		System.out.println("WebSocket服务端错误 " + t);
	}
	// 发送消息
	private static void sendMessage(Message msg)
	{
		//如果为all,遍历历用户列表,逐个发送,否则只发送给一个
		if(msg.getTo().equals("All")){
			SetclientKey = clientSet.keySet();
		    for(String k: clientKey){
		    	EndPoint client=clientSet.get(k);
		    	try
				{
					synchronized (client)
					{
						// 发送消息
						client.session.getBasicRemote().sendText(JSONObject.fromObject(msg).toString());
					}
				}
				catch (IOException e)
				{
					clientSet.remove(k);
					try
					{
						client.session.close();
					}
					catch (IOException e1){}
					
					Message msgError=new Message("server","All",String.format("【%s %s】",k, "已经被断开了连接。"));
					sendMessage(msgError);
					
					Listlist =new ArrayList<>( clientSet.keySet());
				    broadcast(list);
				}
		    }
    	}else{
    		EndPoint client=clientSet.get(msg.getTo());
	    	try
			{
				synchronized (client)
				{
					// 发送消息
					client.session.getBasicRemote().sendText(JSONObject.fromObject(msg).toString());
				}
			}
			catch (IOException e)
			{
				clientSet.remove(msg.getTo());
				try
				{
					client.session.close();
				}
				catch (IOException e1){}
				
				Message msgError=new Message("server","All",String.format("【%s %s】",msg.getTo(), "已经被断开了连接。"));
				sendMessage(msgError);
				
				Listlist =new ArrayList<>( clientSet.keySet());
			    broadcast(list);
			}
	    	
	    	EndPoint clientSend=clientSet.get(msg.getFrom());
	    	try
			{
				synchronized (clientSend)
				{
					// 发送消息
					clientSend.session.getBasicRemote().sendText(JSONObject.fromObject(msg).toString());
				}
			}
			catch (IOException e){}
    	}
	}
	
	// 广播用户列表消息,客户端更新
	private static void broadcast(List list)
	{
	    for(String k: list){
	    	try
			{
				synchronized (k)
				{
					// 发送消息
					clientSet.get(k).session.getBasicRemote().sendText(JSONArray.fromObject(list).toString());
				}
			}
	    	catch (IOException e)
			{
				System.out.println("聊天错误,向客户端 "
					+ k + " 发送消息出现错误。");
				clientSet.remove(k);
				try
				{
					clientSet.get(k).session.close();
				}
				catch (IOException e1){}
				Message msgError=new Message("server","All",String.format("【%s %s】",k, "已经被断开了连接。"));
				sendMessage(msgError);
			}
    	}
	}
}

二、客户端代码




	
	
	WebSocket聊天室 
	
	



三、最终效果

基于Java和websocket的在线聊天程序(可群发和选择用户)_第2张图片基于Java和websocket的在线聊天程序(可群发和选择用户)_第3张图片

需要项目文件的可以在我的主页下载。。。

你可能感兴趣的:(websocket)