- 浏览: 484480 次
文章分类
最新评论
WEBSOKET服务器搭建
简单介绍一下tomcat的webSocketAPI使用:
在这里啰嗦几句:【
很多朋友听说webSocket不知道是什么。知道是什么不知道怎么用,知道怎么用不知道具体实现。其实我当初也是这样。
实际上webSocket可以简单的理解为用浏览器与服务器简历socket连接,但是用了一个特殊的协议,偶收协议,它与http协议发送的报头不一样。
websocket需要服务器和浏览器支持,浏览器不支持,也就无法使用这个技术。服务器可以自己实现协议连接,但是我们不准备自己实现(其实看需求,至少对我来说不需要),当然目前javaEE官方不支持这个实现,没有规范(据说jsr356准备支持,期待来年【2013】javaEE7吧)
目前实现的java服务端第三方webSocketAPI不算少,比如jetty就是一种(多的我也举例不了,我只知道,没研究过有多少实现。)tomcat也自带了实现API
webSocket想要手动实现比较麻烦,可以看下tomcat实现过程,大致都一样。
总之一句话,webSocket是一种客户端与服务端连接socket的技术,实现即时消息,取代comet但是并没广泛只用,因为大多需要浏览器的支持,相对comet有很多优点,此处不举例说明。可以自己google一下。
】
tomcat7.027如何实现webSocket程序:
总的来说,实现webSocket的servlet要继承WebSocketServlet这个类。这个类是tomcat自己包装的servlet。
所有的入口都在protected StreamInbound createWebSocketInbound(String subProtocol) {}这个方法。也就是说,我们实现这个方法,就可以实现握手协议了。
注意看这个方法。要求返回StreamInbound类型。这个类型我们需要继承自己实现。打开源码观看这个类
有如下方法
- /**
- *Intendedtobeoverriddenbysub-classesthatwishtobenotified
- *whentheoutboundconnectionisestablished.Thedefaultimplementation
- *isaNO-OP.
- *
- *@paramoutboundTheoutboundWebSocketconnection.
- */
- protectedvoidonOpen(WsOutboundoutbound){
- //NO-OP
- }
- /**
- *Intendedtobeoverriddenbysub-classesthatwishtobenotified
- *whentheoutboundconnectionisclosed.Thedefaultimplementation
- *isaNO-OP.
- *
- *@paramstatusThestatuscodeoftheclosereason.
- */
- protectedvoidonClose(intstatus){
- //NO-OP
- }
- /**
- *ThismethodiscalledwhenthereisabinaryWebSocketmessageavailable
- *toprocess.Themessageispresentedviaastreamandmaybeformedfrom
- *oneormoreframes.Thenumberofframesusedtotransmitthemessageis
- *notmadevisibletotheapplication.
- *
- *@paramisTheWebSocketmessage
- *
- *@throwsIOExceptionIfaproblemoccursprocessingthemessage.Any
- *exceptionwilltriggertheclosingoftheWebSocket
- *connection.
- */
- protectedabstractvoidonBinaryData(InputStreamis)throwsIOException;
- /**
- *ThismethodiscalledwhenthereisatextualWebSocketmessageavailable
- *toprocess.Themessageispresentedviaareaderandmaybeformedfrom
- *oneormoreframes.Thenumberofframesusedtotransmitthemessageis
- *notmadevisibletotheapplication.
- *
- *@paramrTheWebSocketmessage
- *
- *@throwsIOExceptionIfaproblemoccursprocessingthemessage.Any
- *exceptionwilltriggertheclosingoftheWebSocket
- *connection.
- */
- protectedabstractvoidonTextData(Readerr)throwsIOException;
上面的方法都是要我们自己实现的。tomcat没有给我们实现。
仔细看都是onXxx格式,类似事件监听。其实也差不多。只是tomcat在得到消息或者链接发生变化的时候会去调用这些方法,实现方法“自动”触发。
仔细看源码还有很多函数可以使用,这里不一一介绍。感兴趣可以打开源码看看。
其实仔细看官方的例子,chat那个例子也能得到这个结论(tomcat的webSocket例子需要tomcat7.027才带有)
我们定义一个servlet
- @WebServlet(urlPatterns={"/chatWebSocket"})
- publicclassChatWebSocketServletextendsWebSocketServlet{
- privatestaticfinallongserialVersionUID=1L;
- OnLineUsertheUser;
- @Override
- protectedvoiddoGet(HttpServletRequestreq,HttpServletResponseresp)
- throwsServletException,IOException{
- theUser=(OnLineUser)req.getSession().getAttribute("loginUser");
- super.doGet(req,resp);
- }
- @Override
- protectedStreamInboundcreateWebSocketInbound(StringsubProtocol){
- returnnewChatMessageInbound(theUser);
- }
- }
doget不用说,是连接的开始,然后取出登录的用户,这个是为了管理连接使用的,你在看这个例子的时候不需要doget方法和theUser声明,只要有createWebSocketInbound方法就行。上面说了。这个方法是webSocket的入口。其实也是WebSocketServlet这个类写好的doget,我们看WebSocketServlet的doget是如何写的
- @Override
- protectedvoiddoGet(HttpServletRequestreq,HttpServletResponseresp)
- throwsServletException,IOException{
- //Informationrequiredtosendtheserverhandshakemessage
- Stringkey;
- StringsubProtocol=null;
- List<String>extensions=Collections.emptyList();
- if(!headerContainsToken(req,"upgrade","websocket")){
- resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
- return;
- }
- if(!headerContainsToken(req,"connection","upgrade")){
- resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
- return;
- }
- if(!headerContainsToken(req,"sec-websocket-version","13")){
- resp.setStatus(426);
- resp.setHeader("Sec-WebSocket-Version","13");
- return;
- }
- key=req.getHeader("Sec-WebSocket-Key");
- if(key==null){
- resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
- return;
- }
- Stringorigin=req.getHeader("Origin");
- if(!verifyOrigin(origin)){
- resp.sendError(HttpServletResponse.SC_FORBIDDEN);
- return;
- }
- List<String>subProtocols=getTokensFromHeader(req,
- "Sec-WebSocket-Protocol-Client");
- if(!subProtocols.isEmpty()){
- subProtocol=selectSubProtocol(subProtocols);
- }
- //TODOReadclienthandshake-Sec-WebSocket-Extensions
- //TODOExtensionsrequiretheabilitytospecifysomething(APITBD)
- //thatcanbepassedtotheTomcatinternalsandprocessextension
- //datapresentwhentheframeisfragmented.
- //Ifwegotthisfar,allisgood.Accepttheconnection.
- resp.setHeader("upgrade","websocket");
- resp.setHeader("connection","upgrade");
- resp.setHeader("Sec-WebSocket-Accept",getWebSocketAccept(key));
- if(subProtocol!=null){
- resp.setHeader("Sec-WebSocket-Protocol",subProtocol);
- }
- if(!extensions.isEmpty()){
- //TODO
- }
- //SmallhackuntiltheServletAPIprovidesawaytodothis.
- StreamInboundinbound=createWebSocketInbound(subProtocol);
- ((RequestFacade)req).doUpgrade(inbound);
- }
注意倒数第三行,调用了createWebSocketInbound方法,我们重写这个方法。
- @Override
- protectedStreamInboundcreateWebSocketInbound(StringsubProtocol){
- returnnewChatMessageInbound(theUser);
- }
上面的ChatMessageInbound是我自己定义的继承类。
- publicfinalclassChatMessageInboundextendsMessageInbound{
- publicChatMessageInbound(OnLineUsertheUser){
- this.theUser=theUser;
- }
- @Override
- protectedvoidonOpen(WsOutboundoutbound){
- //添加链接到容器
- ChatMessageInboundtheBound=this;
- ChatContainer.addInbound(theBound.theUser,theBound);
- //向每个在线用户发送消息
- ChatContainer.eachAllBound(newContainerCallBack(){
- @Override
- publicvoideachCallBack(ChatMessageInboundtheBound,OnLineUsertheUser){
- ListUserMsglistUserMsg=newListUserMsg(ChatContainer.getUserList());
- WriteTookit.writeToBound(theBound,listUserMsg.toMsg());
- }
- });
- }
- @Override
- protectedvoidonClose(intstatus){
- ChatContainer.removeInbound(theUser);
- }
- @Override
- protectedvoidonBinaryMessage(ByteBuffermessage)throwsIOException{
- }
- @Override
- protectedvoidonTextMessage(CharBuffermessage)throwsIOException{
- //CHAT_MODEL.setMessage(message.toString());
- //ChatContainer.eachAllBound(newContainerCallBack(){
- //@Override
- //publicvoideachCallBack(ChatMessageInboundtheBound,OnLineUsertheUser){
- //WriteTookit.writeToBound(theBound,CHAT_MODEL.getSayMsg());
- //}
- //});
- }
- //变量区域
- privateOnLineUsertheUser;
- }
这里只是简单实现了一下,注释部分只是处理这个方法的部分,那里是一个容器,存档所有在线用户。并且提供遍历插入以及删除等方法,在自己实现的时候完全不需要这么写。
下面是容器代码
- publicfinalclassChatContainer{
- /**
- *保存服务器连接的用户的容器
- */
- privatestaticfinalMap<OnLineUser,ChatMessageInbound>CHAT_MAP=newHashMap<OnLineUser,ChatMessageInbound>();
- /**
- *取出用户的连接
- */
- publicstaticChatMessageInboundgetInbound(OnLineUsertheUser){
- returnCHAT_MAP.get(theUser);
- }
- /**
- *放入一个连接
- */
- publicstaticvoidaddInbound(OnLineUsertheUser,
- ChatMessageInboundoutbound){
- CHAT_MAP.put(theUser,outbound);
- System.out.println(CHAT_MAP.size());
- }
- /**
- *移除一个连接
- *
- *@paramtheUser
- *@return
- */
- publicstaticChatMessageInboundremoveInbound(OnLineUsertheUser){
- returnCHAT_MAP.remove(theUser);
- }
- /**
- *遍历所有连接
- */
- publicstaticvoideachAllBound(ContainerCallBackcallBackInter){
- Iterator<OnLineUser>keyIter=CHAT_MAP.keySet().iterator();
- while(keyIter.hasNext()){
- OnLineUsertheUser=keyIter.next();
- callBackInter.eachCallBack(CHAT_MAP.get(theUser),theUser);
- }
- }
- /**
- *回调函数的接口
- *
- *@authorWangZhenChong
- */
- publicinterfaceContainerCallBack{
- voideachCallBack(ChatMessageInboundtheBound,OnLineUsertheUser);
- }
- }
我定义了一种数据交约定,使用json 字符串,MsgType表示消息类型,类似windows的消息机制
- /**
- *前台和后台交互的信息类型常量
- *
- *@authorWangZhenChong
- *
- */
- publicfinalclassMsgTypeConstants{
- publicstaticshortGET_USER_LIST=1;//在线所有用户信息交互
- publicstaticshortSEND_ONE_TO_ONE=2;//对一个用户发送消息
- publicstaticshortSEND_ONE_TO_ALL=3;//对所有用户发送消息
- publicstaticshortSEND_SERVER_MSG=4;//发送系统消息
- }
余下的msgContent就是消息内容,比如列出现在用户这个内容就是[...,...,...,...]发送消息就是消息模型的内容。
这样解决单通道多操作的方法。
下面列出前台js核心内容。
使用jquery
- $(document).ready(function(){
- $("#connBtn").bind('click',function(){
- $.ajax({
- url:"/tomcatWebSocket/Login#?asdasdasd",
- type:"POST",
- processData:false,
- data:$.param({
- username:document.getElementById("usernameField").value
- }),
- success:function(msg,status){
- initChat();
- initUserList();
- $("#sendBtn").removeAttr("disabled");
- $("#connBtn").attr("disabled","disabled");
- $("#usernameField").attr("disabled","disabled");
- },
- error:function(jqXHR,textStatus,errorThrown){
- alert("服务器内部错误");
- }
- });
- });
- varChat={};
- Chat.socket=null;
- functioninitChat(){
- varwsURL='ws://'+window.location.host
- +'/tomcatWebSocket/chatWebSocket';
- if('WebSocket'inwindow){
- Chat.socket=newWebSocket(wsURL);
- }elseif('MozWebSocket'inwindow){
- Chat.socket=newMozWebSocket(wsURL);
- }else{
- alert("浏览器不支持");
- returnfalse;
- }
- Chat.socket.onopen=function(){
- };
- Chat.socket.onclose=function(){
- Chat.writeToConsole("断开连接了");
- initChat();
- };
- Chat.socket.onmessage=function(message){
- if(typeofmessage.data=="string"){//如果发送的是字符串信息.
- varmsgObj=eval("("+message.data+")");
- switch(msgObj.MsgType){
- caseMsgTypeConstants.GET_USER_LIST://所有用户信息
- Chat.preUserList(msgObj.userList);
- break;
- caseMsgTypeConstants.SEND_ONE_TO_ALL:
- Chat.writeToConsole(msgObj.msgContext);
- break;
- default:
- alert("未知错误,请刷新页面");
- }
- }
- };
- Chat.sendMessage=function(){
- Chat.socket.send(ueditor.getContentTxt());
- };
- }
- Chat.writeToConsole=function(message){
- <spanstyle="white-space:pre;"></span>//往控制台打印得到的聊天消息
- };
- /**
- *处理刷新用户信息的方法。
- */
- Chat.preUserList=function(userList){
- //用户信息列表
- };
这些代码只是参考内容,实际上不可能拷贝下来直接运行,
相关推荐
netty搭建tcp自定义协议websocket服务器, 支持ssl demo. 适用于netty初学者, netty搭建自定义协议, websocket服务器, 聊天室, 一个端口集成多协议,包括ssl协议
WebSocket整体搭建以及demo 以及整体流程介绍。
使用Netty搭建WebSocket服务器,该资源示范如何修改单包大小限制,解决不能发送大数据包的问题。
ESP32模块通过WebSocket 连接服务器,服务器通过发送"OFF"打开灯,发送“ON”关闭灯,服务器来的数据打印出来,同时返回给服务器。
搭建webSocket服务器,以及运行一个jsmpeg的js文件,Node.js采用C++语言编写而成,它不是Javascript应用,它通过Node.js实现WebSocket服务端,同时也提供客户端JS库。Socket.IO支持以事件为基础的实时双向通讯,它...
unty websocket 客户端 服务端 通信 使用WebSocketSharp框架
E自带组件搭建Websocket服务器,可以收发消息
2、搭建简易服务器 2.1 服务端代码 代码简介 route: 注册请求路径 example_1(request, data): request: socket句柄,能够发送和接收数据接。发送数据request.ws.send(data),收数据request.ws_recv(1024) data:...
ESP8266硬件上, NODEMCU软件环境, 连接WEBSOCKET 服务器的lua程序, 记得:服务器是tomcat8
Vccode 搭建webSocket服务端和apicloud app
Websocket服务器这是一个用PHP编写的简单Websocket服务器。如何使用它? 克隆此仓库并使用Composer安装所有依赖项: composer install现在,您需要将现有的.env.example文件复制到.env文件。 打开它,并根据需要更改...
这是客户端,服务端:https://blog.csdn.net/abcd5711664321/article/details/125094523?spm=1001.2014.3001.5502 服务器阿里云 亲测 能用
Vue中使用WebSocket,搭建服务器进行webSocket测试。 使用:下载解压之后,npm i 安装之后,npm run dev进行运行即可,别忘记更改端口号!
完整websocket 的vb2010工程服务端示例,直接能用于搭建WEBSOCKET服务器。
主要介绍了C#实现WebSocket协议客户端和服务器websocket sharp组件实例解析,包括websocket sharp组件的概念及使用方法,需要的朋友可以参考下
本篇文章主要介绍了spring框架下websocket的搭建,非常具有实用价值,需要的朋友可以参考下。
C#_WinForm实现WebSocket及时通讯,客户端定向推送。
websocket是一个浏览器和服务器通信的新的协议,websocket则和一般的socket一样,使得浏览器和服务器建立了一个双工的通道。今天我们就来详细探讨下使用Python实现websocket服务器的具体方法
支持多连接的 ESP8266 Websocket 服务器 这是一个轻量级的 websocket 服务器库。 适用于 ESP8266 - 小巧但功能强大的 wifi SoC! 它实际上是从许多优秀的参考资料中移植过来的: (主要基于) - 一个轻量级的 ...
一个完成的websocket实时通信demo,能够做到多人聊天,单人聊天的聊天室,可以应用到自己的项目中,欢迎交流