JavaSocket服务端处理多个硬件客户端并监测硬件客户端是否在线
服务端对接的是硬件客户端,客户端反馈的结果是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服务端处理多个硬件客户端并监测硬件客户端是否在线相关推荐
- 西部数据php一键安装,【贪狼某道1.60特色服务端】WD某道1.60一键安装客户端带GM管理工具[附视频搭建教程]...
[贪狼某道1.60特色服务端]WD某道1.60一键安装客户端带GM管理工具[附视频搭建教程] 出生就进传送阵 然后地上宝箱随便点就125了 你会看到北极仙翁 前面传送阵出来就能看到他哥哥南极仙翁 领取 ...
- mongoDB服务端mongod安装启动成功后找不到客户端mongo
mongoDB服务端mongod安装启动成功后找不到客户端mongo mongodb正常安装后,修改环境变量,且mongod能轻松跑同,但是mongo命令无法被正确执行 前往安装目录下/bin目录中, ...
- NFS介绍、NFS服务端配置安装配置、 NFS配置选项、 客户端的配置
NFS介绍 NFS是Network File System的缩写 ,是在网络层面,NFS(Network File System)网络文件系统会经常用到,用于在网络上共享存储.这样讲,你对NFS可能不 ...
- Javasocket服务端持久化,持续更新中
TCP 报文段结构 一谈到 TCP 协议,大家最先想到的词就是「面向连接」和「可靠」.没错,TCP 协议的设计就是为了能够在客户端和服务器之间建立起一个可靠连接. 在讲连接过程之前,我们先来看看 TC ...
- Javasocket服务端程序
那么,如何学习Kafka源码?? 我觉得最高效的方式就是去读最核心的源码,先看一张 Kafka结构图 以及 Kafka 源码全景图 梳理一下关于 Kafka 框架,找到学习的重点. 其次,我要说的就是 ...
- Java面试必问!javasocket服务端持久化
前言 最近刷到了一句耐人寻味的话,"解决雪崩问题的最好办法是不发生雪崩". 不论是在硅谷互联网公司里还是在国内的互联网平台上,曾多次遇到过海量规模的交易瞬间吞噬平台的悲惨故事. 核 ...
- Esp8266学习之旅⑧ 你要找的8266作为UDP、TCP客户端或服务端的角色通讯,都在这了。(带Demo)
本系列博客学习由非官方人员 半颗心脏 潜心所力所写,不做开发板.仅仅做个人技术交流分享,不做任何商业用途.如有不对之处,请留言,本人及时更改. 序号 SDK版本 内容 链接 1 nonos2.0 搭建 ...
- 客户端负载均衡与服务端负载均衡
原文:https://segmentfault.com/a/1190000011081111 通过Nginx负载均衡服务器发送到不同的上游服务器去处理,这种负载均衡就是一种典型的服务端负载均衡,那么客 ...
- 【初识Netty使用Netty实现简单的客户端与服务端的通信操作Netty框架中一些重要的类以及方法的解析】
一.Netty是什么? Netty 由 Trustin Lee(韩国,Line 公司)2004 年开发 本质:网络应用程序框架 实现:异步.事件驱动 特性:高性能.可维护.快速开发 用途:开发服务器和 ...
最新文章
- 用BRAT进行中文情感分析语料标注
- java中的assert
- 微服务已过时!DDD领域建模与架构设计才是未来!
- 关于ContinuationFilter的使用
- 上海新阳半导体收到ASML-1400光刻机 将用于研发193nm ArF光刻胶
- java安卓6.0闪退_Android开发activity跳转闪退
- 黑客声称攻陷并加密白俄罗斯国家铁路的服务器
- Contextual 上下文绑定机制
- 如何用python制作动画电影_用Python制作3D动画
- 为什么你还没有买新能源汽车? 1
- arcgis 删除创建的自定义地理变换文件
- 解决桌面图标左下角蓝色问号问题
- spring hateoas初体验
- 1.NR中PointA、Offsettocarrier、RIV等计算
- stream銆俠oxed_电脑关机时显示OX100672ed指令引用的OX0000000C内存,该内存不能为written是什么意思...
- win7 ads出现Unhandled exception:c0000005
- 安装黑群晖,打开群晖助手初始化失败问题,报错35(ESXI6.7虚拟机安装黑群辉最新版DSM6.2.1)
- 【Unity3D 教程系列第 15 篇】本地数据持久化之 Playerprefs 类
- Python爬虫编程11——JS反爬
- Linux中的ftp命令怎么写,linux中的ftp命令用法