服务端对接的是硬件客户端,客户端反馈的结果是byte[],需要先解析出来硬件的编号,然后存储到map集合中,方便服务端接收到用户指令给另外一个硬件客户端发送指令。

服务端:

public class ServerDemo {private static final int PORT = 60020;public static HashMap<String, Socket> socketList = new HashMap<>();public static String channelToken;  //socket 令牌public static void main(String[] args) throws Exception {ServerSocket serverSocket = null;Socket socket = null;try {// 1.创建服务器端ServerSocket对象,并为服务器端注册端口号serverSocket = new ServerSocket(PORT);while(true) {String ret="";try {// 2.每接收一次Socket管道,就分配一个独立的线程来处理客户端的数据socket = serverSocket.accept();BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());DataInputStream dis = new DataInputStream(bis);//解析客户端反馈信息byte[] bytes = new byte[1]; // 一次读取一个bytewhile (dis.read(bytes) != -1) {ret += TcpHelper.bytesToHexString(bytes);if (dis.available() == 0) { //一个请求System.out.println(socket.getRemoteSocketAddress() + ":" + ret);break;}}//截取指令,解析是否为取水指令String substring = ret.substring(ret.length() - 4);//字符串“取”转为16进制为53d6,如果不是发送的取水指令,则进入判断进行开启客户端线程if(!substring.equals("53d6")) {String bh1 = ret.substring(0, 4);String bh2 = ret.substring(4, 8);int covert1 = TcpHelper.covert(bh1);int covert2 = TcpHelper.covert(bh2);//编号channelToken=TcpHelper.padLeft(4, String.valueOf(covert1), 0)+TcpHelper.padLeft(4, String.valueOf(covert2), 0);Socket socket2 = socketList.get(channelToken);if(socket2 == null || socket2.isClosed()) {//如果集合中没有客户端,则保存进去,并开启线程socketList.put(channelToken, socket);}new MyThread(socket,channelToken).start();//开启实时监测客户端反馈}else if(substring.equals("53d6"))  {new MyHandleThread(socket,socketList,ret).start();//处理用户放水反馈}} catch (Exception e) {System.out.println("建立与客户端的连接出现异常");}}}catch (Exception e) {System.out.println("端口被占用");e.printStackTrace();}finally {serverSocket.close();}}

服务端处理线程:

1、处理硬件客户端的反馈,根据反馈内容做出相应的处理

public class MyThread extends Thread{
private Socket socket;
private String channelToken;
private String ret = "";public MyThread(Socket socket,String channelToken) {super();this.socket = socket;this.channelToken = channelToken;}public String getChannelToken() {return channelToken;}public void setChannelToken(String channelToken) {this.channelToken = channelToken;}public MyThread(String name) {super(name);}public Socket getSocket() {return socket;}public void setSocket(Socket socket) {this.socket = socket;}@Overridepublic void run() {try {//开启每隔18秒确认客户端是否在线,掉线则关闭定时任务Timer t = new Timer();t.scheduleAtFixedRate(new TimerTask() {public void run(){try {socket.sendUrgentData(0xFF);} catch (IOException e) {System.out.println("客户端主动断开连接了"+channelToken+","+new Date());t.cancel();}}}, 2000, 18000);// 3.通过Socket管道得到一个字节输入流InputStream in = socket.getInputStream(); // 获取客户端发送的流BufferedInputStream bis = new BufferedInputStream(in);  //  流存放缓冲区DataInputStream dis = new DataInputStream(bis);byte[] bytes = new byte[1]; // 一次读取一个bytewhile (dis.read(bytes) != -1) {ret += bytesToHexString(bytes);  //调用字节转化16进制字符串方法if (dis.available() == 0) { //一个请求System.out.println("收到报文数据: " + ret);//通过获取到的报文进行处理业务代码ret = "";}}} catch(Exception e) {try {socket.close();} catch (IOException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}System.out.println(socket.getRemoteSocketAddress() + "已经断开连接");}}public static String bytesToHexString(byte[] bytes) {StringBuilder sb = new StringBuilder();for (int i = 0; i < bytes.length; i++) {String hex = Integer.toHexString(0xFF & bytes[i]);if (hex.length() == 1) {sb.append('0');}sb.append(hex);}return sb.toString();}

2、处理用户发送的指令,根据反馈内容给指定的硬件客户端发送指令

public class MyHandleThread extends Thread{
private Socket socket;
private String ret;
private HashMap<String, Socket> socketList; public MyHandleThread(Socket socket,HashMap<String, Socket> socketList, String ret) {super();this.socket = socket;this.ret = ret;this.socketList=socketList;}public MyHandleThread(String name) {super(name);}public String getRet() {return ret;}public void setRet(String ret) {this.ret = ret;}public HashMap<String, Socket> getSocketList() {return socketList;}public void setSocketList(HashMap<String, Socket> socketList) {this.socketList = socketList;}public Socket getSocket() {return socket;}public void setSocket(Socket socket) {this.socket = socket;}@Overridepublic void run() {try {//获取编号String bh1 = ret.substring(0, 4);String bh2 = ret.substring(4, 8);int covert1 = TcpHelper.covert(bh1);int covert2 = TcpHelper.covert(bh2);String channelToken=TcpHelper.padLeft(4, String.valueOf(covert1), 0)+TcpHelper.padLeft(4, String.valueOf(covert2), 0);Socket sok = socketList.get(channelToken);System.out.println(sok);//判断集合中是否存在该客户端的socket,不存在则给用户反馈无设备if(sok == null) {//向客户端发送消息OutputStream outputStream = socket.getOutputStream();outputStream.write("notClient".getBytes());outputStream.close();socket.close();}else {//发送成功则反馈成功,发送失败则反馈设备离线String retHex = ret.substring(0, ret.length()-4);//硬件客户端接收的也是byte[],需要把16进制转为byte[]发送过去byte[] hex2Bytes = TcpHelper.hex2Bytes(retHex);try {OutputStream  qsqSok = sok.getOutputStream();qsqSok.write(hex2Bytes);//向客户端发送消息OutputStream ots = socket.getOutputStream();ots.write("sendOK".getBytes());ots.close();socket.close();}catch(Exception e){//向客户端发送消息OutputStream ots = socket.getOutputStream();ots.write("notClient".getBytes());ots.close();socket.close();}}} catch(Exception e) {System.out.println(socket.getRemoteSocketAddress() + "已经断开连接");}}

进制转换一类的方法:

public class TcpHelper {//获取两者之间随机数public static int getRandom(int x, int y) {int num = -1;//说明:两个数在合法范围内,并不限制输入的数哪个更大一些if (x < 0 || y < 0) {return num;} else {int max = Math.max(x, y);int min = Math.min(x, y);int mid = max - min;//求差//产生随机数num = (int) (Math.random() * (mid + 1)) + min;}return num;}//转为16进制并补0public static String subStrToInt(int random,int begin, int count,int digit, int complement) {String ra = String.valueOf(random);String rd = ra.substring(begin, count);int va = Integer.valueOf(rd).intValue();String it = intToHex(va);String pl = padLeft(digit, it, complement);return pl;}public static String intToHex(int n) {StringBuffer s = new StringBuffer();String a;char []b = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};while(n != 0){s = s.append(b[n%16]);n = n/16;            }a = s.reverse().toString();return a;}//向左补0public static String padLeft(int number, String data,int j) {int length = data.length();String p="";if(length<number) {int sum=number-length;String s="";for(int i =0;i<sum;i++) {s+=j;}p=s+data;}else {p=data;}return p;}//转为bccpublic static String getBCC(byte[] data) {String ret = "";byte BCC[]= new byte[1];for(int i=0;i<data.length;i++){BCC[0]=(byte) (BCC[0] ^ data[i]);}String hex = Integer.toHexString(BCC[0] & 0xFF);if (hex.length() == 1) {hex = '0' + hex;}ret += hex.toUpperCase();return ret;}//转为byte字节public static byte[] hex2Bytes(String hex) {if (hex == null || hex.length() == 0) {return null;}char[] hexChars = hex.toCharArray();byte[] bytes = new byte[hexChars.length / 2];   // 如果 hex 中的字符不是偶数个, 则忽略最后一个for (int i = 0; i < bytes.length; i++) {bytes[i] = (byte) Integer.parseInt("" + hexChars[i * 2] + hexChars[i * 2 + 1], 16);}return bytes;}//字符串转为16进制public static String strTo16(String s) {String str = "";for (int i = 0; i < s.length(); i++) {int ch = (int) s.charAt(i);String s4 = Integer.toHexString(ch);str = str + s4;}return str;}/*** byte[]数组转换为16进制的字符串** @param bytes 要转换的字节数组* @return 转换后的结果*/public static String bytesToHexString(byte[] bytes) {StringBuilder sb = new StringBuilder();for (int i = 0; i < bytes.length; i++) {String hex = Integer.toHexString(0xFF & bytes[i]);if (hex.length() == 1) {sb.append('0');}sb.append(hex);}return sb.toString();}/*** @param: [content]* @return: int* @description: 十六进制转十进制*/public static int covert(String content){int number=0;String [] HighLetter = {"a","b","c","d","e","f"};Map<String,Integer> map = new HashMap<>();for(int i = 0;i <= 9;i++){map.put(i+"",i);}for(int j= 10;j<HighLetter.length+10;j++){map.put(HighLetter[j-10],j);}String[]str = new String[content.length()];for(int i = 0; i < str.length; i++){str[i] = content.substring(i,i+1);}for(int i = 0; i < str.length; i++){number += map.get(str[i])*Math.pow(16,str.length-1-i);}return number;}

JavaSocket服务端处理多个硬件客户端并监测硬件客户端是否在线相关推荐

  1. 西部数据php一键安装,【贪狼某道1.60特色服务端】WD某道1.60一键安装客户端带GM管理工具[附视频搭建教程]...

    [贪狼某道1.60特色服务端]WD某道1.60一键安装客户端带GM管理工具[附视频搭建教程] 出生就进传送阵 然后地上宝箱随便点就125了 你会看到北极仙翁 前面传送阵出来就能看到他哥哥南极仙翁 领取 ...

  2. mongoDB服务端mongod安装启动成功后找不到客户端mongo

    mongoDB服务端mongod安装启动成功后找不到客户端mongo mongodb正常安装后,修改环境变量,且mongod能轻松跑同,但是mongo命令无法被正确执行 前往安装目录下/bin目录中, ...

  3. NFS介绍、NFS服务端配置安装配置、 NFS配置选项、 客户端的配置

    NFS介绍 NFS是Network File System的缩写 ,是在网络层面,NFS(Network File System)网络文件系统会经常用到,用于在网络上共享存储.这样讲,你对NFS可能不 ...

  4. Javasocket服务端持久化,持续更新中

    TCP 报文段结构 一谈到 TCP 协议,大家最先想到的词就是「面向连接」和「可靠」.没错,TCP 协议的设计就是为了能够在客户端和服务器之间建立起一个可靠连接. 在讲连接过程之前,我们先来看看 TC ...

  5. Javasocket服务端程序

    那么,如何学习Kafka源码?? 我觉得最高效的方式就是去读最核心的源码,先看一张 Kafka结构图 以及 Kafka 源码全景图 梳理一下关于 Kafka 框架,找到学习的重点. 其次,我要说的就是 ...

  6. Java面试必问!javasocket服务端持久化

    前言 最近刷到了一句耐人寻味的话,"解决雪崩问题的最好办法是不发生雪崩". 不论是在硅谷互联网公司里还是在国内的互联网平台上,曾多次遇到过海量规模的交易瞬间吞噬平台的悲惨故事. 核 ...

  7. Esp8266学习之旅⑧ 你要找的8266作为UDP、TCP客户端或服务端的角色通讯,都在这了。(带Demo)

    本系列博客学习由非官方人员 半颗心脏 潜心所力所写,不做开发板.仅仅做个人技术交流分享,不做任何商业用途.如有不对之处,请留言,本人及时更改. 序号 SDK版本 内容 链接 1 nonos2.0 搭建 ...

  8. 客户端负载均衡与服务端负载均衡

    原文:https://segmentfault.com/a/1190000011081111 通过Nginx负载均衡服务器发送到不同的上游服务器去处理,这种负载均衡就是一种典型的服务端负载均衡,那么客 ...

  9. 【初识Netty使用Netty实现简单的客户端与服务端的通信操作Netty框架中一些重要的类以及方法的解析】

    一.Netty是什么? Netty 由 Trustin Lee(韩国,Line 公司)2004 年开发 本质:网络应用程序框架 实现:异步.事件驱动 特性:高性能.可维护.快速开发 用途:开发服务器和 ...

最新文章

  1. 【渝粤教育】广东开放大学 地基与基础 形成性考核 (27)
  2. 原生js实现jquery库中选择器的功能(jquery库封装一)
  3. 详解HelloWorldBasic实例
  4. Java 技术体系(JDK 与 JRE 的关系)、POJO 与 JavaBeans
  5. ROS的学习(五)在工作空间中构建和使用catkin包
  6. 项目owner看这里,MaxCompute全表扫描新功能,给你“失误”的机会
  7. 咸鱼Maya笔记—Maya 绘制多边形
  8. python利用reportlab打印图文并茂内容
  9. 西门子g120变频器接线图_西门子G120变频器参数设置,快速使用
  10. 两融杠杆渐入警戒区 专家警示结构性风险
  11. Littlefs移植,FLASH用的是W25Q32
  12. goinception审核规则
  13. 云队友丨40岁之前,希望你懂得这5条定律
  14. python 实现的 成语接龙
  15. java拼图游戏系统总体方案_基于JAVA的拼图游戏的设计与实现(含录像)
  16. 华大HC32F460的BOOT和IAP说明
  17. 【渝粤教育】电大中专新媒体营销实务_1作业 题库
  18. 数据库_SQL基本内容整理
  19. **c#下halcon调用相机发生错误,不知道什么原因**
  20. 在智能时代我们能做什么---读《智能时代》有感

热门文章

  1. MySQL 调用存储过程 错误代码: 1366 Incorrect string value: '\xE7\x8E\x8B\xE4\xBA\x94'
  2. [EndNote]关于导入CAJ文献
  3. Android使用AudioTrack播放WAV音频文件
  4. Win 10 C 盘突然爆满,怎么清理?
  5. 【HTML泡泡特效】——效果+代码
  6. 8000 字 Python 数据可视化实操指南
  7. ESP8266/ESP32 + MicroPython (一) 初识
  8. ffmpeg rtmp 花屏_FFmpeg - 如何编码封装透明通道视频
  9. 未来十年,最赚钱的16大行业
  10. 捡石头推荐地:玉龙雪山