webScoket

服务端代码

package com.masiinc.iscp.websocket;

import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

/**
 *
 * @author <a href="mailTo:wangbo@masiinc.com">MASIINC</a>
 * @time 2017-8-31 9:02:20
 * @version 1.0
 * @since JDK1.7
 */
//URI注解,无需在web.xml中配置。
@ServerEndpoint("/websocket")
public class SocketServer
{

    //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
    private static int onlineCount = 0;
    private Session session;
    //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识
    private static CopyOnWriteArraySet<SocketServer> webSocketSet = new CopyOnWriteArraySet<SocketServer>();

    /**
     * 推送消息接口 外部可以进行调用
     *
     * @param sendMsg
     * @throws IOException
     */
    public void sendMsg(String sendMsg) throws IOException
    {
        System.out.println("要返回给客户端了" + ";" + sendMsg);
        this.session.getBasicRemote().sendText("我是服务端返回给客户端的" + sendMsg);
    }

    /**
     * 连接建立成功调用的方法
     *
     * @param session 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据
     */
    @OnOpen
    public void onOpen(Session session)
    {
        this.session = session;
        System.out.println("连接成功,握手握手成功" + session + "onOpen.....");
        webSocketSet.add(this);     //加入set中
        addOnlineCount();           //在线数加1
        System.out.println("有新连接加入!当前在线人数为" + getOnlineCount());
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose()
    {
        System.out.println(this.toString() + ";有一连接关闭");
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param info
     */
    @OnMessage
    public void onMessage(String info) throws IOException
    {
        System.out.println("来自客户端的消息:" + info);
        sendMsg(info);
    }

    /**
     * 发生错误时调用
     *
     * @param error
     */
    @OnError
    public void onError(Throwable error)
    {
        System.out.println(this.toString() + ";发生错误");
    }

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

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

    public static synchronized void subOnlineCount()
    {
        SocketServer.onlineCount--;
    }
}
client代码连接的

package com.masiinc.iscp.websocket;

import cn.com.ebsi.platform.common.util.Utility;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.websocket.ContainerProvider;
import javax.websocket.DeploymentException;
import javax.websocket.Session;
import javax.websocket.WebSocketContainer;

/**
 * Websocket 入口类
 *
 * @author <a href="mailTo:wangbo@masiinc.com">MASIINC</a>
 * @time 2017年7月17日 11:53:15
 * @version 1.0
 * @since jdk 1.7.0
 */
public class WebSocketUtil
{

    private static final Logger LOG = Logger.getLogger(WebSocketUtil.class.getName());
    private String openApiDomain; // websocket 地址
    private String hospitalCode; // 医院代码
    private String iae036; // 医院所属
    private WebSocketContainer container;
    private Session session;
    private String url;

    /**
     * 构造方法
     * <pre>
     *  1、创建与医点云的websocket连接
     * </pre>
     *
     * @param openApiDomain websocket 地址
     * @param hospitalCode 医院代码
     */
    public WebSocketUtil(String openApiDomain, String hospitalCode)
    {
        this.openApiDomain = openApiDomain;
        this.hospitalCode = hospitalCode;
        try
        {
            // 获取WebSocket连接器,其中具体实现可以参照websocket-api.jar的源码,Class.forName("org.apache.tomcat.websocket.WsWebSocketContainer");
            container = ContainerProvider.getWebSocketContainer();
            url = openApiDomain.concat("?").concat(hospitalCode); // URL+参数
            session = container.connectToServer(WebSocketHandle.class, new URI(url));
        } catch (URISyntaxException | DeploymentException | IOException ex)
        {
            LOG.log(Level.SEVERE, "WebSocket连接初始化失败!", ex);
        } finally
        {
            reconnect(); // 定时检测重新连接
        }

    }

    private void reconnect()
    {
        // 每隔3分钟和服务器通信一下,确定服务器是否正常
        Runnable runnable = new Runnable()
        {
            @Override
            public void run()
            {
                try
                {
                    if (Utility.isNull(session) || !session.isOpen() || Utility.isNull(session.getBasicRemote()))
                    {
                        try
                        {
                            session = container.connectToServer(WebSocketHandle.class, new URI(url));
                            session.getUserProperties().put("IAE036",iae036); // 医院属地
                        } catch (URISyntaxException | DeploymentException | IOException ex)
                        {
                            LOG.log(Level.SEVERE, null, ex);
                        }
                    }
                    session.getBasicRemote().sendText(hospitalCode); // 心跳 保持连接
                } catch (IOException ex)
                {
                    Logger.getLogger(WebSocketUtil.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        };
        ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
        // 第二个参数为首次执行的延时时间,第三个参数为定时执行的间隔时间
//        service.scheduleAtFixedRate(runnable, 0, 3, TimeUnit.MINUTES);
        service.scheduleAtFixedRate(runnable, 0, 10, TimeUnit.SECONDS);
    }

    public String getOpenApiDomain()
    {
        return openApiDomain;
    }

    public void setOpenApiDomain(String openApiDomain)
    {
        this.openApiDomain = openApiDomain;
    }

    public String getHospitalCode()
    {
        return hospitalCode;
    }

    public void setHospitalCode(String hospitalCode)
    {
        this.hospitalCode = hospitalCode;
    }
client端做返回的

package com.masiinc.iscp.websocket;

import java.util.logging.Level;
import java.util.logging.Logger;
import javax.websocket.ClientEndpoint;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;

/**
 * WebSocket 处理对象
 *
 * @author <a href="mailTo:wangbo@masiinc.com">MASIINC</a>
 * @time 2017年7月17日 12:07:30
 * @version 1.0
 * @since jdk 1.7.0
 */
@ClientEndpoint
public class WebSocketHandle
{

    private static final Logger LOG = Logger.getLogger(WebSocketHandle.class.getName());
    private Session session;

    @OnOpen
    public void onOpen(Session session)
    {
        this.session = session;
        LOG.log(Level.SEVERE, "WebSocket对象处理 onOpen", "服务器已连接!");
        System.out.println("我是客户");
    }

    @OnMessage
    public void onMessage(String message)
    {
        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>" + message);
    }

    @OnError
    public void onError(Throwable e)
    {
        LOG.log(Level.SEVERE, "onError", e);
    }

}
测试main方法

package com.masiinc.iscp.test;

import com.masiinc.iscp.websocket.WebSocketUtil;

/**
 *
 * @author <a href="mailTo:wangbo@masiinc.com">MASIINC</a>
 * @time 2017-8-31 10:49:30
 * @version 1.0
 * @since JDK1.7
 */
public class Test1
{

    public static void main(String[] args)
    {
        WebSocketUtil ws = new WebSocketUtil("ws://127.0.0.1:8080/webSocketServer/websocket", "123321");//id 端口号  项目名  @ServerEndpoint("/websocket")  
    }

}
注意jar包,没有jar包会在 container = ContainerProvider.getWebSocketContainer();句报错

需要jar包tyrus-standalone-client-1.9.jar

推荐一个jar包库,需要可进行下载!http://maven-repository.com/

测试先去WebSocketUtil里连接,连接跳到WebSocketHandle的 @OnOpen  里,然后连接到SocketServer的  @OnOpen  里。


      



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
传统的HTTP协议是无状态的,每次请求(request)都要由客户端(如 浏览器)主动发起,服务端进行处理后返回response结果,而服务端很难主动向客户端发送数据;这种客户端是主动方,服务端是被动方的传统Web模式 对于信息变化不频繁的Web应用来说造成的麻烦较小,而对于涉及实时信息的Web应用却带来了很大的不便,如带有即时通信、实时数据、订阅推送等功能的应 用。在WebSocket规范提出之前,开发人员若要实现这些实时性较强的功能,经常会使用折衷的解决方法:轮询(polling)和Comet技术。其实后者本质上也是一种轮询,只不过有所改进。 轮询是最原始的实现实时Web应用的解决方案。轮询技术要求客户端以设定的时间间隔周期性地向服务端发送请求,频繁地查询是否有新的数据改动。明显地,这种方法会导致过多不必要的请求,浪费流量和服务器资源。 Comet技术又可以分为长轮询和流技术。长轮询改进了上述的轮询技术,减小了无用的请求。它会为某些数据设定过期时间,当数据过期后才会向服务端发送请求;这种机制适合数据的改动不是特别频繁的情况。流技术通常是指客户端使用一个隐藏的窗口与服务端建立一个HTTP长连接,服务端会不断更新连接状态以保持HTTP长连接存活;这样的话,服务端就可以通过这条长连接主动将数据发送给客户端;流技术在大并发环境下,可能会考验到服务端的性能。 这两种技术都是基于请求-应答模式,都不算是真正意义上的实时技术;它们的每一次请求、应答,都浪费了一定流量在相同的头部信息上,并且开发复杂度也较大。 伴随着HTML5推出的WebSocket,真正实现了Web的实时通信,使B/S模式具备了C/S模式的实时通信能力。WebSocket的工作流程是这 样的:浏览器通过JavaScript向服务端发出建立WebSocket连接的请求,在WebSocket连接建立成功后,客户端和服务端就可以通过 TCP连接传输数据。因为WebSocket连接本质上是TCP连接,不需要每次传输都带上重复的头部数据,所以它的数据传输量比轮询和Comet技术小 了很多。本文不详细地介绍WebSocket规范,主要介绍下WebSocket在Java Web中的实现。 环境:jdk1.8.0_111,apache-tomcat-8.0.51
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值