基于websocket协议的即时通讯webapp(摘自本人毕业论文)

即时通讯实现

功能结构图

Spring WebSocket配置

 

本软件的即时通讯技术采用了WebSocket协议,因为从spring4.0的版本才开始支持WebSocket,所以本软件服务端的spring版本是4.2。第一步,先配置配置WebSocket入口,允许访问的域、注册Handler和拦截器,WebSocket的访问权限是允许所有,访问路径是/wsim.do,根据这个入口来与服务端建立tcp连接通道。核心代码如下:

<bean id="websocket" class="com.wzc.im.websocket.IMWebSocketHander" />
    <websocket:handlers allowed-origins="*">
        <websocket:mapping path="/wsim.do" handler="websocket" />
        <websocket:handshake-interceptors>
            <bean class="com.wzc.im.websocket.IMHandshakeInterceptor" />
        </websocket:handshake-interceptors>
    </websocket:handlers>

WebSocket接口的实现

根据WebSocket的API,我们要实现两个接口类HandshakeInterceptor和WebSocketHandler。HandshakeInterceptor的实现类,需实现了他的两个方法beforeHandshake和afterHandshake,这个两个方法是客户端与服务器初次进行握手连接的方法,初次握手连接前,连接用户会传过来其用户id,当握手连接成功会用此id与这个用户的连接进行绑定,作为这个链接的唯一标识。

 

public class IMHandshakeInterceptor implements HandshakeInterceptor {
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse serverHttpResponse,
                                   WebSocketHandler webSocketHandler, Map<String, Object> map){
        if (request instanceof ServletServerHttpRequest) {
        	String imkey=request.getURI().getQuery().split("=")[1];
            if(imkey==null){
            	System.out.println("imkey为空");
            	return false;
            }
            map.put("imkey", imkey);
        }
        return true;
    }

    // 初次握手访问后
    public void afterHandshake(ServerHttpRequest serverHttpRequest, 
    		ServerHttpResponse serverHttpResponse,WebSocketHandler webSocketHandler, Exception e) {
    	
    }
}

 

WebSocketHandler的实现类要分别实现他的afterConnectionEstablished(初次链接成功执行的函数)、handleTransportError(连接出错是执行的函数)、afterConnectionClosed(连接关闭时执行的函数)、supportsPartialMessages、handleMessage(接受到消息的处理函数)。

public class IMWebSocketHander implements WebSocketHandler {
    private Logger logger = Logger.getLogger(IMWebSocketHander.class);
    private Map<String, WebSocketSession> socketsessions = new HashMap<String, WebSocketSession>();
    private Gson gson =new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
    @Autowired
    private IGroupService groupService;
    
    @Autowired
    private IUserService userService;
    
    @Autowired
    private IMessageService messageService;
    // 初次链接成功执行
    public void afterConnectionEstablished(WebSocketSession session ) throws Exception {
        String imkey = (String) session.getAttributes().get("imkey");
        if(socketsessions.containsKey(imkey)){
        	socketsessions.get(imkey).close();
        }
        socketsessions.put(imkey,session);	
        logger.info("链接成功,当前在线人数:"+socketsessions.size());	
    }
    public void handleTransportError(WebSocketSession webSocketSession, Throwable throwable) throws Exception {
        if (webSocketSession.isOpen()) {
            webSocketSession.close();
        }
        socketsessions.remove((String) webSocketSession.getAttributes().get("imkey"));
        logger.info("链接出错,当前在线人数:"+socketsessions.size());
    }

    public void afterConnectionClosed(WebSocketSession webSocketSession, CloseStatus closeStatus) throws Exception {
    	socketsessions.remove((String) webSocketSession.getAttributes().get("imkey"));
    	logger.info("链接关闭,当前在线人数:"+socketsessions.size());
        
    }

    public boolean supportsPartialMessages() { return false;}
   
    // 接受消息处理消息
    public void handleMessage(WebSocketSession webSocketSession, WebSocketMessage<?> webSocketMessage)throws Exception {
    	ImMessage message = gson.fromJson((String) webSocketMessage.getPayload(), ImMessage.class);
    	message.setMid(Imt.getUUID());
    	if(messageService.insert(message)){
    		if(message.getTargettype().equals("1")){//单聊
        		sendMessageToUser(message,message.getTargetid()+"");
        	}else if(message.getTargettype().equals("2")){//群聊
        		sendMessageToGroup(message);
        	}else if(message.getTargettype().equals("3")){//所有在线人
        		sendMessageToAll(message,webSocketSession);
        	}
    	}
    }
    /**
     * 给所有在线人员发消息(通知)
     * @param message
     * @param activeSession
     */
    public void sendMessageToAll(ImMessage msg,WebSocketSession activeSession) {
        for (WebSocketSession user : socketsessions.values()) {
    		try {
                if (user!=activeSession&&user.isOpen()) {
                    user.sendMessage(new TextMessage(gson.toJson(msg)));
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    /**
     * 给指定用户发消息(单聊)
     */
    public void sendMessageToUser(ImMessage msg,String tid) {
    	if(socketsessions.containsKey(tid)&&socketsessions.get(tid).isOpen()){
    		try {
				socketsessions.get(tid).sendMessage(new TextMessage(gson.toJson(msg)));
			} catch (IOException e) {
				System.out.println("消息发送失败"+e);
			}
    	}else{
    		int uid = Integer.parseInt(tid);
    		ImUser user =userService.selectById(uid);
    		String idstr =user.getOfflinelogs();
    		if(idstr!=null&&!idstr.equals("")){
    			user.setOfflinelogs(idstr+","+msg.getMid());
    		}else{
    			user.setOfflinelogs(msg.getMid());
    		}
    		userService.update(user);
    	}
    }
    /**
     * 给指定群组用户发消息(群聊)
     */
    public void sendMessageToGroup(ImMessage msg){
    	String str =groupService.selectById(msg.getTargetid()).getMembers();
    	str = Imt.removeArraychild(str, msg.getFromid()+"");
    	if(str.indexOf(",")>-1){
    		String[] tids =str.split(",");
        	for(String tid:tids){
    			System.out.println(tid+"=="+msg.getFromid());
    			sendMessageToUser(msg,tid);
        	}
    	}
    }
}

通讯数据交互流程

根据本软件需求分析,即时通讯需支持单聊和群聊,因此需自己定义相关的处理函数,其原理是,服务端判断根据客户端传输过来的消息的目标类型如果目标类型为单聊,那么则根据消息的目标id,判断当前连接中是否含有此标识的连接,如果有,服务端将通过这条连接将消息转发给用户,如果不存在该连接,则说明该用户当前为在线,则系统会自动将此条消息存入到目标用户的离线信息数据中,等待用户的下次登陆,然后获取到此条消息,自此完成单聊的实现。然后如果目标类型为群组类型,那么此条消息的目标id即为群组的id,系统会根据此id从数据库的群组表中查找到相应的群组信息,群组信息中包含有该群组的所有成员,然后拿出这些成员的id,分别对每个进行如单聊一般的处理,这样即完成的群聊的实现。通讯流程如图:

 

用户登陆成功后,软件会将当前登录用户的账号(即id)写在请求的路径上去请求开启websock连接。WebSocket连接有四个处理函数分别是onopen(服务器连接成功是执行一次)、onmessage(当接收到服务端发来的消息是执行的函数)、onclose(服务器连接断开时执行的函数)和onerror(与服务器的连接出错时执行的函数),这些函数完成了整个即时通讯模块的成功实现。核心代码如下:

 

var wsurl='ws://'+sip.substring(7,sip.length)+'/wsim.do?id='+user.id;
function openWebSocket(){
	ws = new WebSocket(wsurl);
	ws.onmessage = function(evnt) {receivemsg(evnt.data);};
	ws.onopen  = function(evnt){ mui.toast("服务器连接成功");};
	ws.onclose = function(evnt){ mui.toast("服务器连接断开,正在尝试重新连接...");ws=null;reconnection();}
	ws.onerror = function(evnt){ mui.toast("服务器连接出错,正在尝试重新连接...");
ws=null;reconnection();}
}

 

重要的一点,因为WebSocket的连接是依托当前的HTTML页面的,所以当本页面关闭或刷新,那么连接将会断开,因此需要保证本页面一直存在且不被刷新,因为本软件采用的是mui框架,其打开的页面是一个webview,因此只要不关掉此webview,即便其被隐藏该连接也不会被断开,保证了通道的持续稳定。当接受到从服务端传来的消息时会使用跨页面传值的方式将数据传输到相应的显示页面。

该软件其他模块的使用截图

 


 

 

 


 

 

源码下载链接在文章最上面,资源中有下载地址

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
WebSocket是一种支持双向通信的网络协议,可以在客户端和服务器之间建立实时的、持久的连接。它通过在HTTP协议升级到WebSocket协议的过程中握手来建立连接,并使用类似Socket的API来进行通信。 要实现WebSocket即时通讯,需要以下步骤: 1. 客户端发起WebSocket连接请求:客户端通过发送HTTP请求到服务器来建立WebSocket连接。请求头中需要包含特定的字段来指示升级到WebSocket协议。 2. 服务器接受WebSocket连接请求:服务器接收到客户端的WebSocket连接请求后,会返回特定的响应头,表示成功升级到WebSocket协议。 3. 双向通信:建立WebSocket连接后,客户端和服务器可以通过发送消息来进行实时的双向通信。客户端和服务器都可以主动发送消息,并且对方可以通过事件监听来接收消息。 4. 关闭连接:当通信完成或者需要关闭连接时,客户端或服务器可以发送关闭帧来结束WebSocket连接。 对于客户端来说,可以使用浏览器提供的JavaScript WebSocket API来实现WebSocket的功能。具体步骤如下: 1. 创建WebSocket对象:在JavaScript中创建一个WebSocket对象,指定要连接的服务器地址。 2. 监听事件:通过监听WebSocket对象的事件来接收服务器发送的消息。常用的事件有onopen(连接建立)、onmessage(收到消息)、onclose(连接关闭)和onerror(连接错误)。 3. 发送消息:使用WebSocket对象的send()方法来向服务器发送消息。 对于服务器端来说,可以使用各种编程语言提供的WebSocket库来实现WebSocket的功能。具体步骤如下: 1. 接受连接:服务器端需要监听客户端发起的连接请求,并接受连接。 2. 响应升级请求:服务器端需要返回特定的响应头来表示成功升级到WebSocket协议。 3. 处理消息:服务器端可以通过监听接收到的消息来处理客户端发送的消息,并根据需求进行相应的操作。 4. 发送消息:服务器端可以使用相应的方法来向客户端发送消息。 以上就是使用WebSocket实现即时通讯的基本步骤,具体实现方式会根据具体的编程语言和框架而有所不同。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值