TCP与Http混合开发,实现WEB应用与Windows桌面应用或者是单片机之间的通信
来源:互联网 发布:武汉家装哪家好 知乎 编辑:程序博客网 时间:2024/06/10 15:59
百度了好久,都没有找到类似的东西,网上的悠悠一个劲的和我解释Http是什么,哎呦我的天,真不知道现在的人是怎么了,连中文都看不懂了吗,这可是母语啊,亲们。
言归正传,我起初的想法是这样的:当客户端(Windows桌面应用、单片机)通过Tcp长连接上后,就可以自由通信了;但是有一个问题,就是与web的通信,怎么样进行数据的交互。然后我想到了web应用中的过滤器,过滤器的特点是一次初始化,多次调用,直到服务器瓦解,才终将消亡。那么这样就可以把过滤器抽象化,让它成为一个数据解析中转器,那么就可以实现与web间的通信了。
假想图:
项目结构:
用到的jar包,有好多没用上的,不过没关系:
log4j.properties:
### \u8BBE\u7F6E###log4j.rootLogger = debug,stdout,D,E### \u8F93\u51FA\u4FE1\u606F\u5230\u63A7\u5236\u62AC ###log4j.appender.stdout = org.apache.log4j.ConsoleAppenderlog4j.appender.stdout.Target = System.outlog4j.appender.stdout.layout = org.apache.log4j.PatternLayoutlog4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n### \u8F93\u51FADEBUG \u7EA7\u522B\u4EE5\u4E0A\u7684\u65E5\u5FD7\u5230=E://logs/error.log ###log4j.appender.D = org.apache.log4j.DailyRollingFileAppenderlog4j.appender.D.File = C://log/log.loglog4j.appender.D.Append = truelog4j.appender.D.Threshold = DEBUG log4j.appender.D.layout = org.apache.log4j.PatternLayoutlog4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n### \u8F93\u51FAERROR \u7EA7\u522B\u4EE5\u4E0A\u7684\u65E5\u5FD7\u5230=E://logs/error.log ###log4j.appender.E = org.apache.log4j.DailyRollingFileAppenderlog4j.appender.E.File =C://log/error.log log4j.appender.E.Append = truelog4j.appender.E.Threshold = ERROR log4j.appender.E.layout = org.apache.log4j.PatternLayoutlog4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
MyServer.java
package me.mxzf.core;import java.io.IOException;import java.net.ServerSocket;import java.net.Socket;import java.util.Hashtable;import org.apache.log4j.Logger;/** * 线程同步锁、单例模式<br> * 通过调用Servers.getInstance()方法获取ServerSocket的唯一实例<br> * 启用Socket服务,并且告知监听PORT指定的端口<br> * * * * @Title: Servers * @Dscription: Socket服务器 * @author Deleter * @date 2016年11月8日 下午2:25:54 * @version 1.0 */public class MyServer { private static Logger logger = Logger.getLogger(MyServer.class); public static final int PORT = 60000; private static ServerSocket serverSocket; // 在线列表(静态的,无论寄生类实例化多少次都有且仅有一个实例对象) public static Hashtable<Integer, Socket> clientList = null; private MyServer() { } // http://localhost:8080/WebTcpFixed/TcpData?asdasd=asdasd public static ServerSocket getInstance() throws IOException { logger.debug("获取ServerSocket实例对象"); if (serverSocket == null) { synchronized (ServerSocket.class) { if (serverSocket == null) { logger.debug("创建ServerSocket实例对象"); serverSocket = new ServerSocket(PORT); } } } return serverSocket; }}
EncodeFilter.java
package me.mxzf.filter;import java.io.IOException;import javax.servlet.Filter;import javax.servlet.FilterChain;import javax.servlet.FilterConfig;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.annotation.WebFilter;import org.apache.log4j.Logger;/** * 主要拦截所有请求<br> * 将编码格式重置为UTF-8<br> * 以及响应的信息为json文本串 * * * @Title: EncodeFilter * @Dscription: 编码过滤器 * @author Deleter * @date 2016年11月8日 下午2:15:16 * @version 1.0 */@WebFilter(description = "编码过滤器", urlPatterns = { "/*" })public class EncodeFilter implements Filter { private static Logger logger = Logger.getLogger(EncodeFilter.class); public static final String ENCODEING = "UTF-8"; public void destroy() { logger.debug("编码过滤器 - 销毁..."); } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { request.setCharacterEncoding(ENCODEING); response.setCharacterEncoding(ENCODEING); // response.setContentType("application/Json;charset=" + ENCODEING); response.setContentType("text/html;charset=" + ENCODEING); logger.debug("设置编码参数"); chain.doFilter(request, response); } public void init(FilterConfig fConfig) throws ServletException { logger.debug("编码过滤器 - 初始化..."); }}
HttpFilter.java
package me.mxzf.filter;import java.io.IOException;import java.net.ServerSocket;import java.net.Socket;import java.util.Hashtable;import javax.servlet.Filter;import javax.servlet.FilterChain;import javax.servlet.FilterConfig;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.annotation.WebFilter;import org.apache.log4j.Logger;import me.mxzf.core.MyServer;import me.mxzf.thread.CilentThread;/** * 根据过滤器只初始化一次、多次调用的特点<br> * 在init()方法中初始化ServerSocket实例对象,生成唯一的在线列表<br> * 在此方法中开启一个匿名的accept线程,当客户端连上的时候,客户端首次发起通信,进行握手注册<br> * 当调用web接口的时候,就会调用此拦截器中的findByKey()方法<br> * 根据对应的key,寻找对应的通道,将数据传输到客户端/服务端<br> * * * @Title: HttpFilter * @Dscription: 请求过滤器 * @author Deleter * @date 2016年11月8日 下午2:17:04 * @version 1.0 */@WebFilter(description = "请求过滤器", urlPatterns = { "/TcpData" })public class HttpFilter implements Filter { private static Logger logger = Logger.getLogger(HttpFilter.class); // 是否持续监听 private boolean isDone = true; // 数据接口唯一实例 public ServerSocket socketMain; @Override public void init(FilterConfig filterConfig) throws ServletException {// 初始化 logger.debug("请求过滤器 - 初始化..."); try { socketMain = MyServer.getInstance();// 获得ServerSocket的唯一实例对象 MyServer.clientList = new Hashtable<Integer, Socket>();// 创建在线列表 new Thread(new Runnable() {// 监听线程 @Override public void run() { try { while (isDone) {// 持续监听? Socket socket = socketMain.accept();// 等待客户端的连接 new Thread(new CilentThread(socket)).start();// 将注册验证任务放到一个线程中进行 } } catch (IOException e) { e.printStackTrace(); } } }).start(); } catch (IOException e) { e.printStackTrace(); } } @Override public void destroy() { logger.debug("请求过滤器 - 销毁..."); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException { logger.debug("Http过滤 - 调用"); filterChain.doFilter(request, response); } /** * 写出数据 * * @param key * 关键key * @param value * 数据 */ public static void writeByKey(String key, String value) { if (MyServer.clientList != null && MyServer.clientList.get(key) != null) { try { // 数据写入对应"客户端"的流道 logger.debug("数据写入对应'客户端'的流道 (key=" + key + ") - value:" + value); MyServer.clientList.get(key).getOutputStream().write(value.getBytes()); return; } catch (IOException e) { e.printStackTrace(); } } }}
TcpData.java
package me.mxzf.Servlet;import java.io.IOException;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.log4j.Logger;import me.mxzf.filter.HttpFilter;/** * 所有的请求先通过Encode编码过滤器和Http请求拦截器<br> * 当有请求来到TcpData时,执行doPost()方法,从请求体中取出对应的key和值<br> * 当且只当key和value的值不为空的情况下,调用Http请求拦截器的findByKey(),向对应的通道写出数据<br> * * * * @Title: TcpData * @Dscription: Servlet * @author Deleter * @date 2016年11月8日 下午2:29:25 * @version 1.0 */@WebServlet("/TcpData")public class TcpData extends HttpServlet { private static Logger logger = Logger.getLogger(TcpData.class); private static final long serialVersionUID = 1L; public TcpData() { super(); logger.debug("TcpData - Servlet初始化..."); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 经过TcpData过滤器,来到这里 logger.debug("doPost"); String key = request.getParameter("key"); String value = request.getParameter("value"); if (key != null && value != null) { HttpFilter.writeByKey(key, value); response.getWriter().write(value); } } @Override public void destroy() { super.destroy(); logger.debug("TcpData - Servlet销毁..."); }}
CilentThread.java
package me.mxzf.thread;import java.io.IOException;import java.net.Socket;import org.apache.log4j.Logger;import me.mxzf.core.MyServer;/** * 当服务器accept()方法接收到一个客户端的时候</br> * 创建一个新的线程去确认来者何人 </br> * 根据关键key确定了来者是谁之后</br> * 添加到在线列表,以及添加对应的socket对象</br> * * </br> * 关键key为int类型</br> * * * @Title: CilentThread * @Dscription: 服务器与客户端的注册线程 * @author Deleter * @date 2016年11月8日 下午1:59:58 * @version 1.0 */public class CilentThread implements Runnable { private static Logger logger = Logger.getLogger(CilentThread.class); private boolean isDone = true; private Integer key; private Socket socket; public CilentThread(Socket socket) { this.socket = socket; logger.debug("新建一个注册线程:" + Thread.currentThread().getName()); } @Override public void run() { int buff = -1;// 关键key try { while (isDone) {// 客户端通信(关键key,流通道) if (socket != null && socket.isConnected() && (buff = socket.getInputStream().read()) != -1) { this.key = buff; this.isDone = false; logger.debug("新用户到达:" + Thread.currentThread().getName()); break;// 停止阻塞 } } } catch (IOException e) { e.printStackTrace(); } MyServer.clientList.put(key, this.socket);// 添加到在线列表 logger.debug("server(记录流向、注册) - key:" + key);// 线程结束 }}
好了,基本上实现过程就是这样的,代码我都贴出来了。
附上源代码链接: http://pan.baidu.com/s/1nuVFjZz 密码: 2d8h,欢迎提出问题和建议。
2017.1.20日补充:其实可以不用那么麻烦,直接在spring容器中注册通过配置init-method即可以实现TCP/UDP + Http共存。
0 0
- TCP与Http混合开发,实现WEB应用与Windows桌面应用或者是单片机之间的通信
- 【Qt】Web与本地应用的混合开发
- QT Web与本地应用的混合开发
- 【Qt】Web与本地应用的混合开发
- QT Web与本地应用的混合开发
- Windows* 8商店与桌面应用开发
- node-webkit:开发桌面+WEB混合型应用的神器
- node-webkit:开发桌面+WEB混合型应用的神器
- node-webkit:开发桌面+WEB混合型应用的神器
- node-webkit:开发桌面+WEB混合型应用的神器
- node-webkit:开发桌面+WEB混合型应用的神器
- node-webkit:开发桌面+WEB混合型应用的神器
- node-webkit:开发桌面+WEB混合型应用的神器
- HTTP协议:web应用的通信与控制
- 【Android 应用开发】Activity生命周期 与 Activity 之间的通信
- 服务器应用:实现Linux与宿主机之间的通信
- paip.java桌面开发应用与WEB RIA应用
- (单片机原理与应用)理解单片机串行口实现通信的各种工作方式
- 二叉树的所有路径
- tensorflow学习笔记四:mnist实例--用简单的神经网络来训练和测试
- C# Socket编程 服务端与客户端(四) 异步服务端
- SSL 和 TLS
- 1.1.8、嵌入式和单片机的区别
- TCP与Http混合开发,实现WEB应用与Windows桌面应用或者是单片机之间的通信
- bzoj 4296 [PA2015]Mistrzostwa 宽搜 并查集
- Spring3.2和jdk1.8之间的兼容性错误
- 关于thinkPHP 往数据库里插入中文变问号的问题.....Navicat-大坑
- ubuntu GNUPLOT安装
- java学习-----数组
- rsync核心算法介绍及应用探索
- android 基于jsBridge实现js交互时对webview监听onPageStarted及onPageFinished
- Android6.0权限申请-代码自动插入