socket、websocket后台信息日志输出使用
来源:互联网 发布:mac后台程序关不上 编辑:程序博客网 时间:2024/06/01 15:53
socket俗称套接字,是Java对于tcp、IP协议的封装,目的为了进行网际之间的传输信息。
最近公司有个项目,因为后台查询时间太长,需要我以日志形式将其加载进程输出到前台。在网上百度了下,发现了socket。于是便开始研究咯。
什么socket的三次握手四次分手什么我看了也不是很懂,我说说我对于他使用的心的,以及后面又选择websocket和使用这些中遇见的坑。
对于使用socket的使用我就感觉和用微信或者QQ聊天的感觉一样。在使用socket进行连接时,最主要的两个类就是serverSocket和socket这两个类,前者在服务端使用,后者在客户端使用。我写了个demo
首先是服务端的代码package nc.temptation.test.testSocket;import java.io.*;import java.net.ServerSocket;import java.net.Socket;import java.util.HashMap;import java.util.Map;public class server { public static void main(String[] args) { try { //开始服务端的服务 ServerSocket serverSocket = new ServerSocket(56990); //这是为了建立一个聊天室,但是最后没有去做,因为这个对内存占用太大放弃了 Map<String,String> chatRoom = new HashMap<>(); Socket socket = null; //监听客户端的socket建立 while (true){ socket = serverSocket.accept(); InputStream is = socket.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); String result = br.readLine(); //输出客户端传来的消息 System.out.println(result); } } catch (IOException e) { //socket会导致一个io口输出错误 e.printStackTrace(); } }}
接下来是客户端的代码
package nc.temptation.test.testSocket;import java.io.*;import java.net.Socket;import java.util.Scanner;public class client { public static void main(String[] args) throws IOException { Socket socket = null; OutputStream os = null; PrintWriter pw = null; while (true) { socket = new Socket("localhost", 56990); os = socket.getOutputStream(); pw = new PrintWriter(os); System.out.println("请输入:"); StringBuffer sb = new StringBuffer(); sb.append("小明说:"); Scanner input = new Scanner(System.in); String say = sb.append(input.next()).toString(); pw.write(say); pw.flush(); pw.close(); os.close(); } }}
1、在使用socket时一定要端口号和服务器的端口号保持一致,不能使用已经被使用的端口号,这样的服务是启动不起来的。
2、先是启动服务端的服务,监听客户端的socket
3、异常一定要捕获
现在来谈谈为什么最后我放弃了使用它来实现开始说的功能,首先也是最关键的我们的项目的客户端是客户对我们网页的访问,这导致我无法在客户端运行我的代码;第二点,socket本质是短连接(我测试过,客户端在4秒左右不对服务端发送报文,socket会自动断开),无法自己进行长时间的连接,这样为了让他进行长连接,我就必须让客户端定时发送报文给服务端,保证连接不会断开,这样在服务端连接数不多时没有什么问题,然而当服务端连接数太多时会是个可怕的事情。因此度娘告诉我其实还有个websocket框架啊,你为甚不用他呢?好呗,我谢谢我娘现在告诉我这个咯。
我就把我写的代码贴出来咯。
首先是在controller层的websocketController.java(因为他和路径有关系)
package com.voices.duobaoyu.controller;import com.alibaba.fastjson.JSONObject;import com.voices.duobaoyu.service.ICompanyService;import com.voices.duobaoyu.service.IProductService;import com.voices.duobaoyu.util.IWebsocketResponse;import org.springframework.web.socket.server.standard.SpringConfigurator;import javax.annotation.Resource;import javax.websocket.*;import javax.websocket.server.ServerEndpoint;import java.io.*;import java.lang.reflect.Type;import java.util.concurrent.CopyOnWriteArraySet;@ServerEndpoint(value = "/websocket", configurator = SpringConfigurator.class)public class WebSocketController { private static CopyOnWriteArraySet<WebSocketController> webSocketSet = new CopyOnWriteArraySet<WebSocketController>(); private static int onlineCount = 0; private Session session; @Resource private ICompanyService companyService; @Resource private IProductService productService; public Session getSession() { return session; } /** * 收到客户端消息后调用的方法 * @param message 客户端发送过来的消息 * @param session 可选的参数 */ @OnMessage public void onMessage(String message, Session session) {// message = "{\"api\":\"serializeCompany\",\"param\":\"\"}"; //处理前台的message JSONObject msg = JSONObject.parseObject(message); //api String api = msg.getString("api"); if(api == null){ //TODO error handling return; } String param = msg.getString("param"); //判断使用哪个处理函数 if( "serializeCompany".equals(api)){ /** * @param msg.getstring 编号 * @param session 会话 * @param this hangleMessage回调函数 */ //公司的序列化处理函数 serializeCompany(param, new IWebsocketResponse() { @Override public void send(String msg) { try { session.getBasicRemote().sendText(msg); } catch (IOException e) { e.printStackTrace(); } } }); } else if ( "serializeProduct".equals(api)) { //产品的序列化函数 serializeProduct(param, new IWebsocketResponse() { @Override public void send(String msg) throws IOException { session.getBasicRemote().sendText(msg); } }); } } //向前端发送消息 public void sendMessage(String msg,WebSocketController webSocketController){ try { webSocketController.getSession().getBasicRemote().sendText(msg+"加载完成"); } catch (IOException e) { e.printStackTrace(); } } /** * 连接建立成功调用的方法 * @param session 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据 */ @OnOpen public void onOpen(Session session){ this.session = session; webSocketSet.add(this); //加入set中 addOnlineCount(); //在线数加1 System.out.println("有新连接加入!当前在线人数为" + getOnlineCount()); } /** * 连接关闭调用的方法 */ @OnClose public void onClose() { webSocketSet.remove(this); //从set中删除 subOnlineCount(); //在线数减1 System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount()); } /** * 发生错误时调用 * @param session * @param error */ @OnError public void onError(Session session, Throwable error){ System.out.println("发生错误"); error.printStackTrace(); } //处理公司序列化 public void serializeCompany(String id, IWebsocketResponse response){ //null序列化所有产品,nonull序列化单个产品 Integer param ; if ("".equals(id)){// response.send(""); param = null; }else { param = Integer.parseInt(id); } new Thread(new Runnable() { @Override public void run() { companyService.serializeCompany( param, response); } }).start(); } //处理产品序列化 public void serializeProduct( String id, IWebsocketResponse response){ //null序列化所有产品,nonull序列化单个产品 Integer param ; if ("".equals(id)){// response.send(""); param = null; }else { param = Integer.parseInt(id); } new Thread(new Runnable() { @Override public void run() { productService.serializeProduct( response); } }).start(); } public static synchronized int getOnlineCount() { return onlineCount; } public static synchronized void addOnlineCount() { WebSocketController.onlineCount++; } public static synchronized void subOnlineCount() { WebSocketController.onlineCount--; }}
util层的(这个借口的目的是为了降低controller层与service层的耦合,最开始我使用的类的回调,发现耦合还是很高,我便用借口在service输出了)
package com.voices.duobaoyu.util;import java.io.IOException;public interface IWebsocketResponse { void send(String msg) throws IOException;}
service层代码
@Override //序列化公司 public JSONObject serializeCompany(Integer id, IWebsocketResponse response){ JSONObject result = new JSONObject(); result.put("succ", true); CompanyExample example = new CompanyExample(); CompanyExample.Criteria criteria = example.createCriteria(); if (id != null) criteria.andIdEqualTo(id); List<Company> companyList = companyDao.selectByExample(example); for (Company company : companyList) { try { File file = new File("data/companyDetail/" + company.getId() + ".json"); if (!file.getParentFile().exists()) file.getParentFile().mkdirs(); BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "utf-8")); JSONObject temp = new JSONObject(); temp.put("succ", true); temp.put("data", company); String jsonString = JSONToStringUtil.jsonToString(temp); writer.write(jsonString); writer.close(); if (response != null) { response.send(company.getName()); } } catch (FileNotFoundException e) { e.printStackTrace(); result.put("succ", false); } catch (IOException e) { e.printStackTrace(); result.put("succ", false); } } try { response.send("公司序列化完毕"); } catch (IOException e) { e.printStackTrace(); } return result; }
最后就是前端代码了
<%-- Created by IntelliJ IDEA. User: Administrator Date: 2017/9/15 Time: 13:38 To change this template use File | Settings | File Templates.--%><%@ page contentType="text/html;charset=UTF-8" language="java" %><html><head> <title>序列化公司</title> <script> //发送消息 var websocket = null; console.log(window); //判断当前浏览器是否支持WebSocket if ('WebSocket' in window) { websocket = new WebSocket("ws://" + location.host + "/duobaoyu_manager/websocket"); } else { alert('当前浏览器 Not support websocket') } //连接发生错误的回调方法 websocket.onerror = function () { setMessageInnerHTML("WebSocket连接发生错误"); }; //连接成功建立的回调方法 websocket.onopen = function () { setMessageInnerHTML("WebSocket连接成功"); } //接收到消息的回调方法 websocket.onmessage = function (event) { setMessageInnerHTML(event.data); if (event.data == "公司序列化完毕"){ alert("公司序列化完毕"); } } //连接关闭的回调方法 websocket.onclose = function () { setMessageInnerHTML("WebSocket连接关闭"); } //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。 window.onbeforeunload = function () { closeWebSocket(); } //将消息显示在网页上 function setMessageInnerHTML(innerHTML) { document.getElementById('message').innerHTML += innerHTML + '<br/>'; } function send() { var message = '{\"api\":\"serializeCompany\",\"param\":\"\"}'; websocket.send(message) } //关闭WebSocket连接 function closeWebSocket() { websocket.close(); } </script></head><body><a href="javascript:void(0)" onclick="send()">开始序列化</a><div id="message"></div></body></html>
当然前端不只有这些,这个是ifram标签的内容。
遇到的坑:
1、jaee、spring4.0、Tomcat7.0以后都对他进行了实现,特别是我这个项目开始我用maven加入了这个依赖库,导致我运行项目运行正常,只是这个功能回出现404的错误。
2、在前端第一次握手时,路径一定要填对,天杀的这个我开始无法理解他路径,最后理清楚了,就是 URL:ws://Tomcat初始路径/websocket
3、在ssm中使用它,在他的注释格式是
@ServerEndpoint(value = "/websocket", configurator = SpringConfigurator.class)
value的值就是路径,后面的configurator为了websocket层可以使用自动装配,例如:@autowite @Resource。同时要在web.xml中加上这两个配置
<!--监听器--> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-*.xml</param-value> </context-param>
这两个配置是为了监听web容器的上下文,不添加会报:spring无法寻找到上下文。
引用博客:http://blog.csdn.net/skygm/article/details/68066392
- socket、websocket后台信息日志输出使用
- 使用spring websocket实时读取k8s容器日志输出
- 使用日志类RFileLogger输出调试信息
- 使用日志类RFileLogger输出调试信息
- 使用日志类RFileLogger输出调试信息
- 使用Logcat查看/输出日志信息
- java---使用日志输出信息的方法
- socket输出信息
- 输出信息到日志
- Android:输出日志信息
- ldap输出日志信息
- logger4j输出日志信息
- WebSocket 以及 socket.io 使用
- Java使用WebSocket监控Tomcat日志catalina.out实时输出到Web页面
- [S60]使用日志类RFileLogger输出调试信息
- [S60]使用日志类RFileLogger输出调试信息
- SpringBoot使用logback输出日志并打印sql信息
- SpringBoot使用logback输出日志并打印sql信息
- 《统计学习方法》笔记三
- ccf I’m stuck!
- Ubuntu16.04-x64安装caffe(仅CPU)并测试
- 学习笔记(二)
- Python3网络爬虫:使用Cookie-模拟登陆
- socket、websocket后台信息日志输出使用
- 2017 ACM-ICPC 亚洲区(西安赛区)网络赛 C.Sum
- Java反射机制
- Android Studio 手动下载 gradle 版本地址
- Markdown 高级语法进阶-zybuluo
- PAT [A1020]-Tree Traversals
- 引导页
- java_Throwable继承树
- spring-cloud-build-项目pom结构1.3.4(Dalston.SR3)-boot(1.5.6) 学习笔记