软硬结合是个漫长的道路,传透模式是男人的浪漫(之一)。11月24号,有个朋友问我发生什么事情了,我说怎么回事,给我发了几张截图,我一看!嗷,原来是昨天,我拿到了刚到的Esp8266-01和烧录模块,一个3cm,一个4cm…… ——前言
实现
Idea 的产生
在一所大专里看见外包团队在保安亭里安装停车记录器(大概是识别进出车辆的车牌号,进行计费和分配车位),稍微了解了一下,这个团队除了物理器械都是自己设计的。我一听啪的就站起来了,很快啊,idea就有了,或许是突然悟了,虽然说做软件是基本操作,但实现软硬互动也未尝不是代码的另一种风格
以下是三端的基本功能
java : 提供基本的交互后台
Esp8266 : 与后台交互
android : 端控制后台数据更新
这一篇先介绍java模块
1.搭建javaweb,完成简单的websocket
毕竟是介绍代码的,不能一上来就介绍Esp8266电路原理
普通的javaweb搭建我就不细说了,这样的一个小项目用不到高级的框架的。
简简单单,直接上码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.OutputStream; import java.net.Socket;
public class SendServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); }
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
| import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.regex.Matcher; import java.util.regex.Pattern;
public class SocketServer { private static final int port = 80; private ExecutorService mExecutorService; private ServerSocket mServerSocket; public static Map<String, Socket> socketMap =new HashMap<>(); private String ip;
public SocketServer() { try { System.out.println("socket启动"); mServerSocket = new ServerSocket(port); mExecutorService = Executors.newCachedThreadPool(); Socket client = null; while(true){ client = mServerSocket.accept(); ip = client.getInetAddress().getHostAddress(); System.out.println("ip="+ip); socketMap.put("1",client); System.out.println(client+"------"); mExecutorService.execute(convertData); }
} catch (IOException e) { e.printStackTrace(); } } public Runnable convertData = new Runnable(){
@Override public void run() { System.out.println("convertData"); int result; try { Socket client = socketMap.get("1"); while (true) { InputStream inputStream = client.getInputStream(); OutputStream outputStream =client.getOutputStream(); while(inputStream.available()>0) { byte[] data = new byte[inputStream.available()]; inputStream.read(data); String resultData = new String(data); resultData = replaceBlank(resultData); System.out.println("resultData=" + resultData); } } } catch (IOException e) { e.printStackTrace(); } } }; }
|
代码到这会就有人质疑了,这不死循环嘛,我说我这个有用,这是化劲儿方便透传,有念头就写出来的就是要讲究四两拨千斤方便
当然,这么做有它的弊端,比如color{red}{mServerSocket = new ServerSocket(port);
这一行,导致了部署端口和应用端口不同,一个项目要用到两个端口,一个端口还没用,加上两个监听端口,,,挺费端口的
另一个很大的弊端在实际操作后体现的更加明显,正常的websocket会对进入的用户进行临时的管理,而这个就比较草率了,如果不停的连接会出现内存无法释放服务器受不了的情况
当然,就这些弊端比起方便来说 不值一提
顺便贴一个有释放有管理的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
| private static final Logger log = LoggerFactory.getLogger(WebSocketServer.class);
public static int onlineCount = 0; public static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();
public Session session;
public Long userId;
public Integer platformType;
@OnOpen public void onOpen(Session session, @PathParam("platformType") Integer platformType, @PathParam("userId") Long userId) { this.session = session; this.userId = userId; this.platformType = platformType; webSocketSet.add(this); addOnlineCount();
log.info("有新连接加入!当前在线人数为" + getOnlineCount() + " userId==== " + userId + " platformType==== " + platformType); try { sendMessage("连接成功"); } catch (IOException e) { log.error("websocket IO异常"); } }
@OnClose public void onClose() { webSocketSet.remove(this); subOnlineCount(); log.info("有一连接关闭!当前在线人数为" + getOnlineCount()); }
@OnMessage public void onMessage(String message, Session session) { log.info("来自客户端的消息:" + message); }
@OnError public void onError(Session session, Throwable error) { log.error("发生错误" + error); error.printStackTrace(); }
public void sendMessage(String message) throws IOException { this.session.getBasicRemote().sendText(message); }
public static void sendInfo(Long userId, String message) throws IOException { for (WebSocketServer item : webSocketSet) { try { if (item.userId.equals(userId)) { item.sendMessage(message); } } catch (IOException e) { continue; } } }
public static void sendInfos(String message) throws IOException { log.info(message); for (WebSocketServer item : webSocketSet) { try { item.sendMessage(message); } catch (IOException e) { continue; } } }
public static synchronized int getOnlineCount() { return onlineCount; }
public static synchronized void addOnlineCount() { WebSocketServer.onlineCount++; }
public static synchronized void subOnlineCount() { WebSocketServer.onlineCount--; }
|
有代码洁癖的可以参考以上代码
初始化
我们的websocket整到post里去了,还创建了队列,这必然要有Listener的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener;
public class SocketListener implements ServletContextListener {
@Override public void contextInitialized(ServletContextEvent servletContextEvent) { new Thread(new Runnable() { @Override public void run() { new SocketServer(); } }).start(); }
@Override public void contextDestroyed(ServletContextEvent servletContextEvent) {
} }
|
关于对Esp8266传来数据的处理
回车,占位都要换掉的
对于硬件发送的数据,特别是Esp8266,一定要小心谨慎,如果觉得不好判断的话可以先建立连接,打印出传过来的数据,再考虑如何转义
当然,这就涉及到http的知识点了,一般我们都是前后端http,https,对于硬件的数据传输,没有\n\t\r一般都不符合规范的,并且对字符的长度,参数的长度都有严格的要求。
1 2 3 4 5 6 7 8 9 10
| public static String replaceBlank(String str) { String dest = ""; if (str!=null) { Pattern p = Pattern.compile("\\s*|\t|\r|\n"); Matcher m = p.matcher(str); dest = m.replaceAll(""); } return dest; }
|
当时数据处理失败,跑去问了软工的dalao,她说她不会硬件,又跑去问物信的dalao,她说她不会软件。。。。
岂可修,只好自己琢磨了
web.xml的配置
1 2 3 4 5 6 7 8 9 10 11
| <servlet> <servlet-name>send</servlet-name> <servlet-class>SendServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>send</servlet-name> <url-pattern>/send.jsp</url-pattern> </servlet-mapping> <listener> <listener-class>SocketListener</listener-class> </listener>
|