java socket 发送二进制流的问题

想通过java socket发送一个二进制流:
0x05 0x03 0x00 0x00 0x00 0x40 0x45 0xbe
说明:这个二进制不代表任何字符串,就是一个命令,服务器端能够识别。

做法是这样的,先申请一块空间赋值,然后发送出去。
char cmd[] = {0x05, 0x03, 0x00, 0x00, 0x00, 0x40, 0x45, 0xbe};
os.print(cmd);
os.flush

或者:
char cmd[] = {0x05, 0x03, 0x00, 0x00, 0x00, 0x40, 0x45, 0xbe};
String command = new String(cmd);
os.print(command);
os.flush

用wireshark抓包看的话,
实际发送的数据是:
0x05, 0x03, 0x00, 0x00, 0x00, 0x40, 0x45, 0x3f.

这个是怎么回事儿?有大神知道吗?
我试了下,貌似数据大于0x80的都有这个问题,是不是二进制转化为字符的时候会有特殊处理?如果我真想要发送一个大于0x80的二进制该怎么处理?

4个回答

既然是二进制,为什么不用byte类型呢

qufudashaozi
qufudashaozi byte类型也试过,和char是一样的效果。
3 年多之前 回复

你这种写法是不对的,web发送数据时,写成byte发送,不会出现你的那种情况,到时候考虑高低位就行。

貌似数据大于0x80的都有这个问题,是不是二进制转化为字符的时候会有特殊处理?如果我真想要发送一个大于0x80的二进制该怎么处理?

这个问题和java语言底层实现有关,简单说就是java中-127--128中简单数都使用的是缓存实例,大于128的都重新生成实例。详见这篇博客:http://www.codeceo.com/article/why-java-1000-100.html

找到原因和解决方法了。
我之前用的是BufferedReader(字符缓冲输入流)发送的数据,二进制在发送前都要转化为字符再发送。
0x80以上的二进制转化为字符都会存在问题。

如果想要发送单纯的二进制流的话,用DataInputStream(数据输入流)这个就好了。

Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
其他相关推荐
关于java 不能完全读取socket二进制流的问题(数据量越大问题就越严重)

我在java中用socket读取server端发过来的二进制流,从包头前面11个字节中读取包体的字节总数,然后再循环读取包体的字节数,但当server端的数据字节比较大时就不能完全读过来 ,如从server端发送了 3万个字节,这时client端程序就会不能完全读出server端的字节,可能只能读2万多个; 当字节数少于2000 以下时,就基本没有出现过问题。 我把程序贴出来,这段程序有什么问题么?接收大量的数据该如何处理为好? 想了很久,没想明白是怎么回事,望各位不吝赐教!!! public class SocketService { private static Socket socket; private static InputStream is; private static OutputStream os; private static BufferedInputStream br; public static byte[] getReceiveBytes(Catalog catalog,byte[] b) { byte[] receive_body_byte = {}; try { socket = new Socket(catalog.getPrivateTcpIp(), Integer.parseInt(catalog.getPrivateTcpIPPort())); is = new DataInputStream(socket.getInputStream()); os = new DataOutputStream(socket.getOutputStream()); os.write(b); br = new BufferedInputStream(is); // 包体长度 packlength。 String packlength = ""; // 先收11个字节,函数解析出数据包长度 byte[] encry_byte = new byte[11]; int sizeHead = br.read(encry_byte); for (int m = 0; m < sizeHead; m++) { if (m > 6) { packlength = packlength + Util.byte2HexStr(encry_byte[m]); } } receive_body_byte = new byte[Integer.parseInt(packlength, 16)]; // 接收剩下的字节 int size = br.read(receive_body_byte); //打印接收到的字节 System.out.println("\n-------接收到的字节总数是-------------- "+receive_body_byte.length); os.flush(); is.close(); os.close(); br.close(); } catch (Exception e) { System.out.print("**********Socket异常!!!!*********"+e.getMessage()); return null; } return receive_body_byte; } ========= 上面的程序不知哪里有问题,于是我就又优化了一下,代码如下,但遇到大数据还是不能全读出来=================== public class SocketService { private static Socket socket; private static InputStream is; private static OutputStream os; private static BufferedInputStream br; public static byte[] getReceiveBytes(Catalog catalog,byte[] b) { byte[] receive_body_byte = {}; try { socket = new Socket(catalog.getPrivateTcpIp(), Integer.parseInt(catalog.getPrivateTcpIPPort())); is = new DataInputStream(socket.getInputStream()); os = new DataOutputStream(socket.getOutputStream()); os.write(b); br = new BufferedInputStream(is); // 包体长度 packlength。 String packlength = ""; // 先收11个字节,函数解析出数据包长度 byte[] encry_byte = new byte[11]; int sizeHead = br.read(encry_byte); for (int m = 0; m < sizeHead; m++) { if (m > 6) { packlength = packlength + Util.byte2HexStr(encry_byte[m]); } } receive_body_byte = new byte[Integer.parseInt(packlength, 16)]; int size = 0 // 分次取server端的数据,即每次从流中取1024个字节,不足1024就一次取过来 while(true){ int a = receive_body_byte.length/1024; if(a>=1){ int last=0; Thread.sleep(280); for(int i=0;i<a;i++){ //Thread.sleep(50); byte[] btmp = new byte[1024]; br.read(btmp); getBytes(receive_body_byte,i*1024,btmp); last = last + i*1024; Thread.sleep(100); } //然后取剩余不足1024个的字节 int aa = receive_body_byte.length%1024; byte[] bmp = new byte[aa]; //Thread.sleep(200); if(aa!=0){ br.read(bmp); System.out.println(" aa------------"+aa); p(bmp); Thread.sleep(100); getBytes(receive_body_byte,a*1024,bmp); } break; }else{ br.read(receive_body_byte); break; } } //打印接收到的字节 System.out.println("\n-------接收到的字节总数是-------------- "+receive_body_byte.length); os.flush(); is.close(); os.close(); br.close(); } catch (Exception e) { System.out.print("**********Socket异常!!!!*********"+e.getMessage()); return null; } return receive_body_byte; }

急。。。。交作业 !java socket发送和接收数据

一、 项目需求 模拟socket发送(发送随机16进制数据)和接收(接收后解析成10进制),并在前台进行显示和规则判断,判断符合条件的数据,向前台发送报警信息。 模拟两组数据同时发送(并发),发送间隔5秒。 二、 流程说明 ![图片说明](https://img-ask.csdn.net/upload/201711/07/1510034044_771810.png) 用户角色为两个,A角色接收报警,并对报警进行处理(如点击确认按钮),处理后B角色才能看到这条报警信息。同时两个角色都可以查询历史报警。 三、 编码要求 编码规范结构清晰,注释规范。 四、 项目输出 可运行的项目代码;需求分析;设计说明书;项目总结。

请问通过netty或者socket怎么接收16进制的字节码?

我这面做服务器接收 客户端发来的16进制 字节码,如图(图片是客户端发来![图片说明](https://img-ask.csdn.net/upload/201712/11/1512985640_549678.png)的)我想原模原样的接收到这些字节码,返回一个字节数组

java socket客户端往服务器端发送文件

java socket客户端往服务器端发送文件包括二进制文件word文件, 请问文件传输的通讯协议该如何定义,不知道怎么自定义通讯协议。 我所说的发送文件是指多个文件,不是简单的一个文件。我想要的是自定义协议,客户端与 服务器端通讯的协议。

关于java发送socket身份确认的信息

![图片说明](https://img-ask.csdn.net/upload/201707/01/1498876832_776169.png) 像发送这样一种数据包java该怎么实现,路过的大神帮帮忙,我是初次接触网络编程

关于Java Socket双工通信的问题,请教

通信过程发送二进制数据(可能很大)和命令码,如何设计可以使命令码优先处理,如果用两个socket分开传输管理又比较麻烦。 :lol: :lol:

java socket 收不到客户端消息

直接用字节留能收到 InputStream is = socket.getInputStream(); 转成字符六就收不到消息了 br = new BufferedReader(new InputStreamReader(socket.getInputStream())); 请问这是怎么回事.在线等...谢谢 . 对方发过来的是16进制的数据.我用InputStream处理不了,必须转成BufferedReader,但是转完就收不到数据了.

网络传输发送的文件内容大小不一致

Server端: [code="java"]import java.net.*; import java.io.*; public class Server { // 服务器监听端口 private int port; // 文件保存路径 private String path; // 判断server是否启动 private boolean started = false; public static void main(String[] args) { new Server(8888, "E:/").listen(8888); } // 初始化服务器端口及文件保存路径 private Server(int port, String path) { this.port = port; this.path = path; } // 二进制转换为十进制 public static int b2i(byte[] b) { int value = 0; for (int i = 0; i < 4; i++) { int shift = (4 - 1 - i) * 8; value += (b[i] & 0x000000FF) << shift; } return value; } public static long b2l(byte[] b) { long s = 0; long s0 = b[0] & 0xff; long s1 = b[1] & 0xff; long s2 = b[2] & 0xff; long s3 = b[3] & 0xff; long s4 = b[4] & 0xff; long s5 = b[5] & 0xff; long s6 = b[6] & 0xff; long s7 = b[7] & 0xff; s1 <<= 8; s2 <<= 16; s3 <<= 24; s4 <<= 8 * 4; s5 <<= 8 * 5; s6 <<= 8 * 6; s7 <<= 8 * 7; s = s0 | s1 | s2 | s3 | s4 | s5 | s6 | s7; return s; } // 主线程始终处于监听状态,等待客户端连接 private void listen(int port) { Socket s = null; ServerSocket ss = null; try { ss = new ServerSocket(port); started = true; System.out.println("监听端口:" + port); while (started) { s = ss.accept(); System.out.println("A client connected!"); new Thread(new HandleThread(s)).start(); } } catch (IOException e) { e.printStackTrace(); } } // 处理接收文件并做相关处理的线程类 private class HandleThread implements Runnable { Socket s = null; private HandleThread(Socket s) { this.s = s; } public void run() { String name = getName(s); System.out.println(name); String isOver = getFile(name, s); System.out.println(isOver); } // 1、先获取文件名,并按照文件名创建相应文件壳,用于储存文件内容 private String getName(Socket s) { try { InputStream is = s.getInputStream(); BufferedInputStream bis = new BufferedInputStream(is); byte[] buffer1 = new byte[4]; bis.read(buffer1); int name_len = b2i(buffer1); System.out.println("s_name_len = " + name_len); // 开始获取文件名 byte[] buffer2 = new byte[name_len]; bis.read(buffer2); return new String(buffer2); } catch (IOException e) { return new String("接收过程出现故障!"); } } // 2、开始接收文件 private String getFile(String name, Socket s) { InputStream is = null; BufferedInputStream bis = null; FileOutputStream fos = null; BufferedOutputStream bos = null; File file = null; try { file = new File(path + "/" + name); if (!file.exists()) { file.createNewFile(); } is = s.getInputStream(); bis = new BufferedInputStream(is); fos = new FileOutputStream(file); bos = new BufferedOutputStream(fos); byte[] bytes = new byte[8]; bis.read(bytes); long size = b2l(bytes); System.out.println("s_size = " + size); byte[] buffer = new byte[1024]; long count = 0; while (count < size) { long num = bis.read(buffer); bos.write(buffer); count = count + num; } /* int a = -1; while ((a = bis.read()) != -1) { bos.write(a); }*/ bos.flush(); bos.close(); return "文件 " + file.getName() + " 大小 " + file.length() + "接收完成!"; } catch (IOException e) { return "接收失败"; } finally { try { if (bos != null) { bos.close(); bos = null; } if (fos != null) { fos.close(); fos = null; } if (bis != null) { bis.close(); bis = null; } if (is != null) { is.close(); is = null; } if (s != null) { s.close(); s = null; } } catch (IOException e) { e.printStackTrace(); } } } } } [/code] Client [code="java"]import java.net.*; import java.io.*; public class Client { // 服务器ip地址 private String ipAdd; // 服务器监听端口号 private int port; // 发送文件路径 private String path; public static void main(String[] args) { new Client("127.0.0.1", 8888, "D:\\把悲伤留给自己.mp3").connect(); } public Client(String ipAdd, int port, String path) { this.ipAdd = ipAdd; this.port = port; this.path = path; } // 连接到服务器 private void connect() { Socket s = null; OutputStream os = null; BufferedOutputStream bos = null; try { s = new Socket(ipAdd, port); os = s.getOutputStream(); bos = new BufferedOutputStream(os); File file = new File(path); // 文件名 String name = file.getName(); // 文件大小 long size = file.length(); System.out.printf("%s%s%s%s%s", "Sending file ", name, " size ", size, " bytes to server..."); // 先发送文件名到服务器 boolean completed1 = sendName(name, bos); boolean completed2 = sendContent(file, bos); if (completed1 && completed2) { System.out.println("文件发送成功"); } else { System.out.println("文件发送失败"); } } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { System.out.println("文件未检测到"); } finally { try { if (bos != null) { bos.close(); bos = null; } if (os != null) { os.close(); os = null; } } catch (IOException e) { } } } // 整型数据转换为byte数据方法 public static byte[] i2b(int i) { return new byte[] { (byte) ((i >> 24) & 0xFF), (byte) ((i >> 16) & 0xFF), (byte) ((i >> 8) & 0xFF), (byte) (i & 0xFF) }; } // long类型转成byte数组 public static byte[] l2b(long number) { long temp = number; byte[] b = new byte[8]; for (int i = 0; i < b.length; i++) { b[i] = new Long(temp & 0xff).byteValue(); temp = temp >> 8; // 向右移8位 } return b; } // 发送文件名长度以及文件名到服务器 private boolean sendName(String name, BufferedOutputStream bos) { byte[] buffer = name.getBytes(); int name_len = buffer.length; try { // 这就要求文件名长度不能长于65535,当然,这显然不太可能!!! bos.write(i2b(name_len)); bos.write(buffer); bos.flush(); return true; } catch (IOException e) { return false; } } // 发送文件内容到服务器 private boolean sendContent(File file, BufferedOutputStream bos) { try { long size = file.length(); // 先发送文件长度 bos.write(l2b(size)); FileInputStream fis = new FileInputStream(file); BufferedInputStream bis = new BufferedInputStream(fis); byte[] buffer = new byte[1024]; long count = 0; // 一边读入,一边写出 while (count < size) { long d = bis.read(buffer); count = count + d; bos.write(buffer); } bos.flush(); return true; } catch (FileNotFoundException e) { System.out.println("未检测到发送文件!"); return false; } catch (IOException e) { return false; } } } [/code]

C#移植JAVA程序,WIFI通信问题

C#端指令:byte[] test = new byte[] {171,6,0,0,1,0,8,0,84,70,69,77,77,69,70,84,245,38,97, 139}; JAVA端指令:byte[] test = new byte[]{(-85),6,0,0,1,0,8,0,84,70,69,77,77,69,70,84,-11,38,97,-117}; 因为byte范围原因,把超范围数转成同二进制的负数。通过Socket发送控制下位机,但是C#可正常控制,JAVA不行。求原因

通过Golang中的Websocket发送和接收[] []字节

<div class="post-text" itemprop="text"> <p>I have a two-dimensional byte array:</p> <pre><code>data := [][]byte{{104, 105}, {104, 105}} </code></pre> <p>which I need to transport through a websocket connection, but I don't find a way how to convert this array so I can efficiently reconvert it back to a two-dimensional array on my java client.</p> <pre><code>func socketManager (connection *websocket.Conn ){ fmt.Print("Websocket connection established ") //determining the request for { //awaiting messages from clients messageType, message, err := connection.ReadMessage() if err != nil { //ending connection when error accursed Logger.LogError(err.(error).Error()) break } data := [][]byte{{104, 105}, {104, 105}} //How can I send this two dimensional byte array? err = connection.WriteMessage(websocket.BinaryMessage, message) if err != nil { log.Println("write:", err) break } err = connection.WriteMessage(messageType, message) if err != nil { log.Println("write:", err) break } } //closing the connection defer connection.Close() } </code></pre> </div>

socket编程客户端连接失败

想用socket通信,没法解决客户端连接失败,代码是一本书上的实例,书上的都运行不成功吗,大家帮看下问题在那里,谢谢了![图片说明](https://img-ask.csdn.net/upload/201507/13/1436783188_607205.png) 代码如下: 服务器端:################################################### #include<stdio.h> #include<winsock.h> /*引入winsock头文件*/ int main() { /*-----------------------------------------*/ /*------------定义变量---------------------*/ /*-----------------------------------------*/ char Sendbuf[100]; /*发送数据的缓冲区*/ char Receivebuf[100]; /*接受数据的缓冲区*/ int SendLen; /*发送数据的长度*/ int ReceiveLen; /*接收数据的长度*/ int Length; /*表示SOCKADDR的大小*/ SOCKET socket_server; /*定义服务器套接字*/ SOCKET socket_receive; /*定义用于连接套接字*/ SOCKADDR_IN Server_add; /*服务器地址信息结构*/ SOCKADDR_IN Client_add; /*客户端地址信息结构*/ WORD wVersionRequested; /*字(word):unsigned short*/ WSADATA wsaData; /*库版本信息结构*/ int error; /*表示错误*/ /*-----------------------------------------*/ /*------------初始化套接字库---------------*/ /*-----------------------------------------*/ /*定义版本类型。将两个字节组合成一个字,前面是第字节,后面是高字节*/ wVersionRequested = MAKEWORD( 2, 2 ); /*加载套接字库,初始化Ws2_32.dll动态链接库*/ error = WSAStartup( wVersionRequested, &wsaData); if(error!=0) { printf("加载套接字失败!"); return 0; /*程序结束*/ } /*判断请求加载的版本号是否符合要求*/ if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 ) { WSACleanup( ); /*不符合,关闭套接字库*/ return 0; /*程序结束*/ } /*-----------------------------------------*/ /*------------设置连接地址-----------------*/ /*-----------------------------------------*/ Server_add.sin_family=AF_INET;/*地址家族,对于必须是AF_INET,注意只有它不是网络网络字节顺序*/ Server_add.sin_addr.S_un.S_addr=htonl(INADDR_ANY);/*主机地址*/ Server_add.sin_port=htons(5000);/*端口号*/ /*------------创建套接字-------------------*/ /*AF_INET表示指定地址族,SOCK_STREAM表示流式套接字TCP,特定的地址家族相关的协议。*/ socket_server=socket(AF_INET,SOCK_STREAM,0); /*-----------------------------------------*/ /*---绑定套接字到本地的某个地址和端口上----*/ /*-----------------------------------------*/ /*socket_server为套接字,(SOCKADDR*)&Server_add为服务器地址*/ if(bind(socket_server,(SOCKADDR*)&Server_add,sizeof(SOCKADDR) )==SOCKET_ERROR) { printf("绑定失败\n"); } /*-----------------------------------------*/ /*------------设置套接字为监听状态---------*/ /*-----------------------------------------*/ /*监听状态,为连接做准备,最大等待的数目为5*/ if(listen(socket_server,5)<0) { printf("监听失败\n"); } /*-----------------------------------------*/ /*------------接受连接---------------------*/ /*-----------------------------------------*/ Length=sizeof(SOCKADDR); /*接受客户端的发送请求,等待客户端发送connect请求*/ socket_receive=accept(socket_server,(SOCKADDR*)&Client_add,&Length); if(socket_receive==SOCKET_ERROR) { printf("接受连接失败"); } /*-----------------------------------------*/ /*--------------进行聊天-------------------*/ /*-----------------------------------------*/ while(1) /*无限循环*/ { /*--------接收数据---------*/ ReceiveLen =recv(socket_receive,Receivebuf,100,0); if(ReceiveLen<0) { printf("接收失败\n"); printf("程序退出\n"); break; } else { printf("client say: %s\n",Receivebuf); } /*--------发送数据---------*/ printf("please enter message:"); scanf("%s",Sendbuf); SendLen=send(socket_receive,Sendbuf,100,0); if(SendLen<0) { printf("发送失败\n"); } } /*-----------------------------------------*/ /*---------释放套接字,关闭动态库----------*/ /*-----------------------------------------*/ closesocket(socket_receive); /*释放客户端的套接字资源*/ closesocket(socket_server);/*释放套接字资源*/ WSACleanup();/*关闭动态链接库*/ return 0; } 客户端:##################################################### #include<stdio.h> #include<winsock.h> /*引入winsock头文件*/ int main() { /*-----------------------------------------*/ /*------------定义变量---------------------*/ /*-----------------------------------------*/ char Sendbuf[100]; /*发送数据的缓冲区*/ char Receivebuf[100]; /*接受数据的缓冲区*/ int SendLen; /*发送数据的长度*/ int ReceiveLen; /*接收数据的长度*/ SOCKET socket_send; /*定义套接字*/ SOCKADDR_IN Server_add; /*服务器地址信息结构*/ WORD wVersionRequested; /*字(word):unsigned short*/ WSADATA wsaData; /*库版本信息结构*/ int error; /*表示错误*/ /*-----------------------------------------*/ /*------------初始化套接字库---------------*/ /*-----------------------------------------*/ /*定义版本类型。将两个字节组合成一个字,前面是第字节,后面是高字节*/ wVersionRequested = MAKEWORD( 2, 2 ); /*加载套接字库,初始化Ws2_32.dll动态链接库*/ error = WSAStartup( wVersionRequested, &wsaData); if(error!=0) { printf("加载套接字失败!"); return 0; /*程序结束*/ } /*判断请求加载的版本号是否符合要求*/ if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 ) { WSACleanup( ); /*不符合,关闭套接字库*/ return 0; /*程序结束*/ } /*-----------------------------------------*/ /*------------设置服务器地址---------------*/ /*-----------------------------------------*/ Server_add.sin_family=AF_INET;/*地址家族,对于必须是AF_INET,注意只有它不是网络网络字节顺序*/ /*服务器的地址,将一个点分十进制表示为IP地址,inet_ntoa是将地址转成字符串*/ Server_add.sin_addr.S_un.S_addr = inet_addr("192.168.1.238"); Server_add.sin_port=htons(5000);/*端口号*/ /*-----------------------------------------*/ /*-------------进行连接服务器--------------*/ /*-----------------------------------------*/ /*客户端创建套接字,但是不需要绑定的,只需要和服务器建立起连接就可以了,*/ /*socket_sendr表示的是套接字,Server_add服务器的地址结构*/ socket_send=socket(AF_INET,SOCK_STREAM,0); /*-----------------------------------------*/ /*-------------创建用于连接的套接字--------*/ /*-----------------------------------------*/ /*AF_INET表示指定地址族,SOCK_STREAM表示流式套接字TCP,特定的地址家族相关的协议。*/ if(connect(socket_send,(SOCKADDR*)&Server_add,sizeof(SOCKADDR)) == SOCKET_ERROR) { printf("连接失败!\n"); } /*-----------------------------------------*/ /*--------------进行聊天-------------------*/ /*-----------------------------------------*/ while(1) /*无限循环*/ { /*---------------发送数据过程----------*/ printf("please enter message:"); scanf("%s",Sendbuf); SendLen = send(socket_send,Sendbuf,100,0); /*发送数据*/ if(SendLen < 0) { printf("发送失败!\n"); } /*--------------接收数据过程---------------*/ ReceiveLen =recv(socket_send,Receivebuf,100,0); /*接受数据*/ if(ReceiveLen<0) { printf("接收失败\n"); printf("程序退出\n"); break; } else { printf("Server say: %s\n",Receivebuf); } } /*-----------------------------------------*/ /*---------释放套接字,关闭动态库----------*/ /*-----------------------------------------*/ closesocket(socket_send);/*释放套接字资源*/ WSACleanup();/*关闭动态链接库*/ return 0; }

3年swing,1年JavaEE,1年java socket转android什么待遇

3年swing,技能除了跟做游戏的比足够了。做过IM 3款,手术X光机客户端1款,线程是我的强项,过度Android有绝对的自信。 <br />1年JavaEE,spring struts都摸过,腻外了 <br />1年java服务器开发,做过的项目包括网关、邮件服务器、金融信息发布、用过纯socket,MIMA框架,设计过协议,也熟悉一些协议比如sip、xmpp、activesync、webdav等等,http更不用说。写过点C代码,不多,JNI调用。 <br />在外企干过2年,目前做手机服务器端。 <br /> <br />如果转Android,能给什么价格。听说android动辄就10k?有那么值钱么 <br />主要和市场升温有关吧,android诞生2007年底,企业用人都是1年android开发经验。 <br />android人才紧缺是不是?<br/><strong>问题补充</strong><br/><div class="quote_title">proper 写道</div><div class="quote_div">Android没那么值钱的... <br /> <br />show一下你的app,然后再讨论工资... <br /> <br /></div> <br /> <br />package com.xxx.framework.components.transport.socket.codec; <br /> <br />import java.nio.ByteOrder; <br />import org.apache.mina.common.ByteBuffer; <br />import org.apache.mina.common.IoSession; <br />import org.apache.mina.filter.codec.CumulativeProtocolDecoder; <br />import org.apache.mina.filter.codec.ProtocolDecoderOutput; <br /> <br />/** <br /> * 新华社系统Socket通信协议解码器。具体协议信息参见《xxx》。 <br /> * 解码器的解码时机由MINA框架决定,一般地:客户端发来的二进制消息先是经过协议解码器处理,即doDecode方法; <br /> * 解码器处理、过滤、封装后抛给下一层解码器(如果存在);最后由最终的解码器抛给应用层的Handler处理具体业务逻辑。 <br /> * 总之,解码器的责任是将网络直接发送来的原始的二进制数据封装成应用层能识别的特定类对象,并上抛给应用层。 <br /> * 上抛的过程由解码器方法参数ProtocolDecoderOutput的write方法完成。 <br /> * 注意:为配合与多种异构客户端的通信,规定:协议解码的字节序是从最低有效位到最高有效位。 <br /> * <br /> * @author xxx <br /> */ <br />final class UploadDecoder extends CumulativeProtocolDecoder { <br /> <br />&nbsp;&nbsp;&nbsp; /** <br />&nbsp;&nbsp;&nbsp;&nbsp; * 覆盖超类的回调方法完成自定义协议解码,该方法由MINA框架负责调用 <br />&nbsp;&nbsp;&nbsp;&nbsp; * @param session IoSession对象,由框架创建 <br />&nbsp;&nbsp;&nbsp;&nbsp; * @param ioBuffer 存储原始二进制数据的缓冲区,由框架创建 <br />&nbsp;&nbsp;&nbsp;&nbsp; * @param out ProtocolDecoderOutput对象,由框架创建 <br />&nbsp;&nbsp;&nbsp;&nbsp; * @return 返回true,当且仅当缓冲区内有可以解析的数据而你需要再次调用doDecode时;返回false,如果缓冲区内其余的数据不足以进行解析, <br />&nbsp;&nbsp;&nbsp;&nbsp; * 然后当有更多的数据积累到缓冲区时doDecode方法会再次被通知。 <br />&nbsp;&nbsp;&nbsp;&nbsp; * @throws Exception <br />&nbsp;&nbsp;&nbsp;&nbsp; */ <br />&nbsp;&nbsp;&nbsp; @Override <br />&nbsp;&nbsp;&nbsp; protected boolean doDecode(IoSession session, ByteBuffer ioBuffer, ProtocolDecoderOutput out) throws Exception { <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ioBuffer.order(ByteOrder.LITTLE_ENDIAN); // 修改缓冲区的字节顺序为little-endian,按照此顺序,多字节值的字节顺序是从最低有效位到最高有效位的。 <br /> <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 根据新华社系统Socket通信协议规范,协议由两部分构成:消息头与消息体。 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 其中消息头长度恒定为17字节;消息体长度不定,由消息头前4个字节给出。 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 因此解析一条由客户端上传的消息需要2个步骤:获取并解析消息头;获取并解析消息体。 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */ <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Upload request = (Upload) session.getAttribute("xhs-upload"); // 从session对象中获取“xhs-upload”属性值 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (request == null) { <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 如果request对象是null,则表示是解析消息头的阶段。如果是消息刚刚接收到即解析的是新消息,request对象一定是在session中不存在的。 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */ <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ioBuffer.remaining() &gt;= 17) { <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 检查缓冲区可用字节个数是否大于等于17。因为根据协议规定,消息头的长度恒定为17, <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 分别是消息长度4字节、客户端标识11字节、命令标识1字节、zip压缩标识1字节。 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 如果大于等于17,就表明有足够的数据来解析消息头了。 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */ <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int totalLength = ioBuffer.getInt(); // 读取缓冲区前4个字节合并为一个整型,该值受字节序的影响,但是规定字节序是从最低有效位到最高有效位 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; byte[] clientIdentify = new byte[11]; // 创建11字节容量的数组容纳客户端标识 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ioBuffer.get(clientIdentify); // 从缓冲区读取11个字节的数据填充进数组 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; byte command = ioBuffer.get(); // 从冲缓冲区读取1字节作为命令标识 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; byte zip = ioBuffer.get(); // 从冲缓冲区读取1字节作为zip压缩标识 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; request = UploadFactory.createUpload(command); // 根据命令的类型创建适当的请求 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; request.messageTotalSize = totalLength; // 设置请求的消息长度 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; request.clientIdentify = new String(clientIdentify); // 设置请求的客户端标识属性 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; request.zip = (zip != (byte) 0); // 设置请求的zip压缩标识属性,当且仅当数值 0 代表非压缩 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 向session添加标识键为“xhs-upload”的属性,将请求对象作为属性值传入。这有两个作用: <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 1、将xhs-upload键设置成有值状态,代表消息头已经解析完成。 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 2、将之前解析出来的消息长度、客户端标识、命令标识、zip压缩标识等信息封装进请求对象暂时存储到session对象中,以便下次调用doDecode方法时利用。 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 注意:这时消息应该缺少消息体部分。 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */ <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; session.setAttribute("xhs-upload", request); <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 因为当消息头解析完成后,这时缓冲区内可能还有足够的积累数据可以继续解析消息体甚至下一条消息(也可能没有),返回true使框架再次调用doDecode方法。 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 即使缓冲区内没有足够的数据了,也应该留给下次调用doDecode方法时去判断。 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */ <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return true; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else { <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 如果缓冲区可用字节个数不足15个,直接返回false告诉框架不要再回调doDecode方法,直到网络获取到数据压进缓冲区时再调用。 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */ <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return false; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else { <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 如果request对象不是null,则表示是消息头已经解析完成并存储,目前是解析消息体阶段。 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */ <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int bodyLength = request.messageTotalSize - 17; // 取得消息体的长度,即消息的总长度 - 消息头的长度(17) <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ioBuffer.remaining() &gt;= bodyLength) { <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 检查缓冲区的可用字节数是否大于等于消息体长度,即是否读取到消息体了。 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */ <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; byte[] messageBody = new byte[bodyLength]; // 创建定长的数组存放消息体 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ioBuffer.get(messageBody); // 从缓冲区中读取bodyLength字节的数据填充进数组 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; request.messageBody = messageBody; // 设置请求的消息体 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 将session对象的“xhs-upload”键及其对应的属性值移除从而: <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 1、将xhs-upload键设置成无值状态,代表消息体已经解析完成。再次进入等待解析消息头阶段 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 2、释放存储“xhs-upload”键的属性值占用的内存。 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */ <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; session.removeAttribute("xhs-upload"); <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 将解码后生成的请求对象对象抛给位于应用层的Handler处理,或者抛给下一层解码器(如果存在)。 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */ <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.write(request); <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 因为当一条完整消息解析完成后,这时缓冲区内可能还有足够的积累数据可以继续解析下一条消息(也可能没有),返回true使框架再次调用doDecode方法。 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 即使缓冲区内没有足够的数据了,也应该留给下次调用doDecode方法时去判断。 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */ <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return true; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else { <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 如果缓冲区内可用字节个数不足以构成完整的消息体,直接返回false告诉框架不要再回调doDecode方法,直到网络获取到数据压进缓冲区时再调用。 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */ <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return false; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />&nbsp;&nbsp;&nbsp; } <br />} <br /> <br />新闻发布程序的MINA解码器,别被注释吓死 <br /><br/><strong>问题补充</strong><br/><div class="quote_title">javagui 写道</div><div class="quote_div"> <br /> <br />应该是MINA把。 <br /></div> <br /> <br />拼错了,是Apache MINA,本来是想用xsocket来着,但是xsocket人气没MINA高 <br />

java这个简单的服务器我要如何读取客户端的输入信息?

import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintWriter; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Iterator; import java.util.Set; public class EchoServer { public static int DEFAULT_PORT = 7; public static String text=""; public static ServerSocketChannel server; public static SocketChannel client ; public static ByteBuffer output ; public static void main(String[] args){ int port; try{ port = Integer.parseInt(args[0]); }catch(RuntimeException ex){ port = DEFAULT_PORT; } System.out.println("Listening for connertions on port "+port); ServerSocketChannel serverChannel; Selector selector; try{ serverChannel = ServerSocketChannel.open(); ServerSocket ss = serverChannel.socket(); InetSocketAddress address = new InetSocketAddress(port); ss.bind(address); serverChannel.configureBlocking(false); selector =Selector.open(); serverChannel.register(selector, SelectionKey.OP_ACCEPT); }catch(IOException ex){ ex.printStackTrace(); return; } while(true){ try{ selector.select(); }catch(IOException ex){ ex.printStackTrace(); break; } Set<SelectionKey> readyKeys = selector.selectedKeys(); Iterator<SelectionKey> iterator = readyKeys.iterator(); while(iterator.hasNext()){ SelectionKey key = iterator.next(); iterator.remove(); try{ if(key.isAcceptable()){ ServerSocketChannel server = (ServerSocketChannel) key.channel(); SocketChannel client = server.accept(); System.out.println("Accepted connection from "+client); client.configureBlocking(false); SelectionKey clientKey = client.register(selector, SelectionKey.OP_WRITE|SelectionKey.OP_READ); ByteBuffer buffer = ByteBuffer.allocate(100); clientKey.attach(buffer); } if(key.isReadable()){ client =(SocketChannel)key.channel(); output = (ByteBuffer)key.attachment(); client.read(output); output.flip(); Charset charset = Charset.forName("UTF-8"); CharsetDecoder decoder = charset.newDecoder(); CharBuffer charBuffer = null; charBuffer = decoder.decode(output); text=charBuffer.toString(); //if(text.equals("time")) //{ //System.out.println("2"); Date date=new Date(); DateFormat format=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String time=format.format(date); byte b[] = time.getBytes(); //将十六进制字符串转换成十进制整数 //int i=Integer.decode(time); //创建一个大小为1的字节缓冲区因为只放一个byte值 ByteBuffer bb=ByteBuffer.allocate(1); //将十进制整数转换成二进制byte值然后存进ByteBuffer //bb.put(b); //打印ByteBuffer中的byte值 //byte []b1=bb.array(); client.write(output); // output.compact(); //} // text=output.toString(); //System.out.println(text); //output.compact(); } if(key.isWritable()){ client = (SocketChannel) key.channel(); output = (ByteBuffer)key.attachment(); //output.flip(); client.write(output); //output.compact(); } }catch(IOException ex){ key.cancel(); try{ key.channel().close(); }catch(IOException cex){} } } } } } 这是我写的,中间有点乱,因为客户在cmd访问我的服务器如果他输入time,我要给他返回时间。。。大神求助!!

浏览器用WebSocket接收数据丢包

var reader = new FileReader(); websocket.onmessage = function(evt){ if (evt.data instanceof Blob) { reader.readAsText(evt.data,"UTF-8"); //reader.readAsText(evt.data,"gbk"); reader.onload = function(e){ var str=reader.result; document.getElementById("myDiv").innerHTML=document.getElementById("myDiv").innerHTML+e.target.result; } } }; 当服务器发送二进制数据频率过快时,流浪器端会丢包(前面的数据接收不到,只接收到最后的数据)。如果服务器端每100ms发一次的话,浏览器就能够完整接收数据。为什么?

java 关于NIO实现UDP数据传输问题 ,急谢谢,C币不足请不要介意

各位大侠好,小弟想问一下问题,搞了一两天没有搞明白的。因为要实现一个UDP传输服务端,于是在网上找了很多资料然后就写了一个。但是写好之后发现有两个很严重的问题,希望各位大哥给点意见或者思路去解决。 问题一:启动服务端,同时也启动客户端,客户端传输数据服务器正常接收,但是断开客户端后,再启动客户端,服务器就收不到任何客户端发送的消息,好像是服务器关闭了UDP一样,但是重启服务器后(重新打开UDP)客户端既可以发送信息过来。 问题二:多个客户端。第一个客户端连接上后,第二个客户端怎么也链接不上了。即使关闭了第一个客户端也一样。 如下是代码: package com.gateway.socket; import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.nio.channels.DatagramChannel; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.util.Iterator; import java.util.Set; import org.apache.log4j.Logger; public class UDPEchoServerSelector extends Thread { private static final Logger log = Logger.getLogger(ServerSocket.class); // private InetSocketAddress inetSocketAddress; // socket处理类 private UDPSocketHandler handler = new UDPSocketHandler(); // 注册的接受服务 private SocketReceiver receiver = null; /** * 初始化socket * * @param receiver * @param hostname * @param port * @throws IOException * @throws UnknownHostException */ public UDPEchoServerSelector(SocketReceiver receiver, String hostname, int port) { if (hostname.isEmpty()) { inetSocketAddress = new InetSocketAddress(port); } else { inetSocketAddress = new InetSocketAddress(hostname, port); } this.receiver = receiver; } @Override public void run() { try { Selector selector = Selector.open(); // 创建选择器,可以处理多路通道。 DatagramChannel serverSocketChannel = DatagramChannel.open(); // 打开通道 serverSocketChannel.configureBlocking(false); // 非阻塞 serverSocketChannel.socket().bind(inetSocketAddress); /* * 将通道管理器和该通道绑定,并为该通道注册SelectionKey.OP_READ事件,注册该事件后, * 当该事件到达时,selector.select()会返回,如果该事件没到达selector.select()会一直阻塞。 */ serverSocketChannel.register(selector, SelectionKey.OP_READ, new ClientData()); log.info("Server: socket server started."); /* * 采用轮询的方式监听selector上是否有需要处理的事件,如果有,则进行处理 */ while (true) { // 轮询 // 当注册的事件到达时,方法返回;否则,该方法会一直阻塞 int nKeys = selector.select(); if (nKeys == 0) { continue; } // 得到选择键列表 Set Keys = selector.selectedKeys(); Iterator it = Keys.iterator(); while (it.hasNext()) { SelectionKey key = null; key = (SelectionKey) it.next(); // 键为位掩码 it.remove(); // 客户端请求连接事件 if (key.isValid() && key.isWritable()) { log.info("Server: SelectionKey is acceptable."); handler.handleWrite(key); } if (key.isReadable()) {// 获得了可读的事件 log.info("Server: SelectionKey is readable."); handler.receiveMsg(key, receiver); } } Keys.clear(); } } catch (IOException e) { e.printStackTrace(); } } public static class ClientData { public SocketAddress clientAddress; public ByteBuffer buffer = ByteBuffer.allocate(255); } } package com.gateway.socket; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.DatagramChannel; import java.nio.channels.SelectionKey; import org.apache.log4j.Logger; import com.gateway.common.DeviceDataTools; import com.gateway.common.data.HexUtils; import com.gateway.socket.UDPEchoServerSelector.ClientData; /** * * 处理socket类 * * @author Andy * */ public class UDPSocketHandler { private static Logger log = Logger.getLogger(UDPSocketHandler.class); /** * 链接请求 * * @throws IOException */ public void handleWrite(SelectionKey key) { try { DatagramChannel channel = (DatagramChannel) key.channel(); ClientData clntDat = (ClientData) key.attachment(); clntDat.buffer.flip(); // 从起始位置开始发送 int bytesSent; bytesSent = channel.send(clntDat.buffer, clntDat.clientAddress); if (bytesSent != 0) { key.interestOps(SelectionKey.OP_READ); // 关注客户端发送数据 } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 读请求 * * @throws IOException */ public void receiveMsg(SelectionKey key, SocketReceiver receiver) { ByteBuffer byteBuffer = ByteBuffer.allocate(1024); byteBuffer.clear(); DatagramChannel socketChannel = (DatagramChannel) key.channel(); //非阻塞 try { socketChannel.configureBlocking(false); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } System.out.println("channel code:" + socketChannel.hashCode()); try { while (true) { InetSocketAddress client = (InetSocketAddress) socketChannel .receive(byteBuffer); byteBuffer.flip(); // byteBuffer中传过来的是10进制的bytep[] byte[] dst = new byte[byteBuffer.limit()]; byteBuffer.get(dst); // 将10进制的byte[]转化成16进制字符串 String data = HexUtils.converBytesToHex(dst); System.out.println(data); log.info("Server: data1 = " + data); byteBuffer.clear(); receiver.udpreceive(socketChannel, data, client); break; } } catch (java.io.IOException e) { //e.printStackTrace(); //this.closeChannel(key, socketChannel); } catch (Exception e) { //e.printStackTrace(); //this.closeChannel(key, socketChannel); } } /** * * @param socketChannel */ private void closeChannel(SelectionKey key, DatagramChannel socketChannel) { try { while (socketChannel.isOpen()) { key.cancel(); socketChannel.close(); } } catch (IOException e1) { e1.printStackTrace(); } } /** * 根据socketKey从内存中获取channel,通过channel向client端发送消息 * * @param socketKey * 内存在channel对应的key * @param data * 发送的数据 * @return * @throws IOException */ public static boolean send(String socketKey, String data) throws IOException { DatagramChannel socketChannel = SocketChannelMapper .getUDPChannel(socketKey); if (socketChannel == null || !socketChannel.isOpen()) { return false; } InetSocketAddress client = SocketChannelMapper .getUDPInetSocketAddress(socketKey + "address"); boolean f = socketChannel.isConnected(); ByteBuffer byteBuffer = ByteBuffer.wrap(DeviceDataTools.hex2Byte(data)); if (f) { socketChannel.write(byteBuffer); } else { socketChannel.connect(new InetSocketAddress(client.getAddress(), client.getPort())); socketChannel.send(byteBuffer, client); } return true; } /** * 根据socketKey从内存中获取channel,通过channel向client端发送消息 * * @param socketKey * 内存在channel对应的key * @param data * 发送的数据 * @return * @throws IOException */ public static boolean send(DatagramChannel socketChannel, String data, InetSocketAddress client) throws IOException { if (socketChannel == null) { return false; } System.out.println("#########################ADDRESS" + client.getAddress()); System.out.println("#########################PORT" + client.getPort()); boolean f = socketChannel.isConnected(); ByteBuffer byteBuffer = ByteBuffer.wrap(DeviceDataTools.hexStr2ByteArray(data)); if (f) { socketChannel.write(byteBuffer); } else { socketChannel.connect(new InetSocketAddress(client.getAddress(), client.getPort())); socketChannel.send(byteBuffer, client); } return true; } }

springboot websocket @MessageMapping注解不生效

``` @Controller public class WsController { @MessageMapping("ws/chat") public void handleChat(@Header("destination") String destination) throws Exception { System.out.println(destination); } } ``` java springboot 使用websocket实现在线聊天,添加@MessageMapping("ws/chat")注解之后handleChat方法显示Method 'handleChat(java.lang.String)' is never used从未被调用, websocket连接正常,消息发送也正常: ``` 打开浏览器f12可见 <<< CONNECTED version:1.1 heart-beat:0,0 ``` ``` >>> SEND destination:http://localhost:8082/ws.chat content-length:12 哈哈哈哈 ```

netty5的channel写回websocket数据时候,onmessage方法接收不到

``` handler处理如下 package com.amarky.websocket; import org.apache.log4j.Logger; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.handler.codec.http.DefaultFullHttpResponse; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.HttpVersion; import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame; import io.netty.handler.codec.http.websocketx.PingWebSocketFrame; import io.netty.handler.codec.http.websocketx.PongWebSocketFrame; import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; import io.netty.handler.codec.http.websocketx.WebSocketFrame; import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker; import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory; import io.netty.util.CharsetUtil; /** * * @author AMARKY * @date 2016年9月8日 * @Desc 处理WEBSOCKET的请求 */ public class WebsocketServerHandler extends SimpleChannelInboundHandler<Object> { private static final Logger logger = Logger.getLogger(WebsocketServerHandler.class.getName()); private WebSocketServerHandshaker handsharker; /** * 接受数据 */ @Override protected void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception { // 如果是HTTP请求 if (msg instanceof FullHttpRequest) { handleHttpRequest(ctx, (FullHttpRequest) msg); } // WEBSOCKET接入 else if (msg instanceof WebSocketFrame) { handleWebSocketFrame(ctx, (WebSocketFrame) msg); } } /** * 数据处理完成后,刷新出去 */ @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { ctx.flush(); } /** * 处理HTTP请求 * * @param ctx * @param msg */ private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) { // 如果解码失败,返回异常 if (!req.getDecoderResult().isSuccess() || (!"websocket".equals(req.headers().get("Upgrade")))) { sendHttpResponse(ctx, new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST)); return; } // 构造握手相应 WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory( "ws://localhost:8080/websocket", null, Boolean.FALSE); handsharker = wsFactory.newHandshaker(req); if (handsharker == null) { WebSocketServerHandshakerFactory.sendUnsupportedWebSocketVersionResponse(ctx.channel()); } else { handsharker.handshake(ctx.channel(), req); } } /** * 处理WEBSOCKET请求 * * @param ctx * @param frame */ private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) { // 判断链路是否关闭 if (frame instanceof CloseWebSocketFrame) { handsharker.close(ctx.channel(), (CloseWebSocketFrame) frame.retain()); return; } if (frame instanceof PingWebSocketFrame) { new PongWebSocketFrame(frame.content().retain()); return; } // 只支持文本消息,不支持二进制消息 if (!(frame instanceof TextWebSocketFrame)) { throw new UnsupportedOperationException( String.format("%s frame type not supported", frame.getClass().getName())); } String request = ((TextWebSocketFrame) frame).text(); logger.info(String.format("%s received %s", ctx.channel(), request)); System.out.println(String.format("%s received %s", ctx.channel(), request)); // ctx.channel().write(new TextWebSocketFrame(request + " , 欢迎使用netty // websocket 服务,现在时刻是: ") // + new java.util.Date().toString()); ctx.channel().writeAndFlush("欢迎使用netty websocket 服务,现在时刻是: " + new java.util.Date().toString()); } /** * 返回请求 * * @param ctx * @param req * @param defaultFullHttpResponse */ private void sendHttpResponse(ChannelHandlerContext ctx, DefaultFullHttpResponse res) { // 返回应答的消息 if (res.getStatus().code() != 200) { ByteBuf byteBuf = Unpooled.copiedBuffer(res.getStatus().toString(), CharsetUtil.UTF_8); res.content().writeBytes(byteBuf); byteBuf.release(); HttpHeaders.setContentLength(res, res.content().readableBytes()); } ChannelFuture f = ctx.channel().writeAndFlush(res); if (!HttpHeaders.isKeepAlive(res) || res.getStatus().code() != 200) { f.addListener(ChannelFutureListener.CLOSE); } } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { ctx.close(); } } ``` ``` websocket如下: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>netty 测试</title> </head> <body> <script type="text/javascript"> var socket; alert(window.WebSocket); if(!window.WebSocket){ window.WebSocket = window.MozWebSocket; } if(window.WebSocket){ socket = new WebSocket("ws://localhost:8080/websocket"); socket.onopen = function(event){ var ta = document.getElementById('responseText'); ta.value = "打开websocket服务正常,支持websocket服务"; }; socket.onmessage = function(event){ var ta = document.getElementById('responseText'); ta.value = ""; ta.value = event.data; }; socket.onclose = function(event){ var ta = document.getElementById('responseText'); ta.value = ""; ta.value = "websocket关闭"; }; } else{ alert("不支持websocket"); } function send(message){ if(!window.WebSocket){return;} if(socket.readyState == WebSocket.OPEN){ socket.send(message); }else{ alert("链接没成功"); } } </script> <form onsubmit="return false;"> <input type = "text" name = "message" value = "netty实践" /> <br><br> <input type = "button" value = "发送" onclick="send(this.form.message.value)" /> <hr color="bule" /> <h3>服务端应答消息</h3> <textarea id = "responseText" style = "width: 500px;height: 300px"></textarea> </form> </body> </html> socket.onmessage方法接受不到writeAndFlush写回的数据,不知道是什么原因​ ```

怎么连接gps发送第一个注册包,这个xml格式怎么写

1概述 1.1术语表 本协议用到以下术语: 术语 全称 描述 GPSBS GPS Business Server GPS业务服务器 GPSMT GPS Monitor System GPS监控终端 XML Extensible Markup Language 可扩展标记语言 1.2协议说明 GPSP协议以TCP/IP作为底层通信承载,具体堆栈结构由(图一)所示: 1.3适用范围 本协议适用于GPSBS与GPSMT之间的消息通讯。 2通信方式 GPSMT做为客户端,GPSBS做为服务端。当客户端要发送命令时,主动向服务器端建立TCP长连接,然后向服务器端发送命令,并接收应答;服务器端从客户端接收命令,返回应答。连接建立以后,客户端可以连续发送多条命令。客户端由于某种原因需要暂时中断通讯,客户端应该发起注销消息,收到返回后主动断开连接。 当信道上没有业务数据传输时,客户端/服务端应每隔时间30秒发送链路检测包以维持此连接, 服务端/客户端收到链路检测包后,立即返回链路检测应答包。服务端/客户端在120秒内没有收到任何消息包,则应断开此连接。 由于某种原因导致连接断开,客户端应尝试重新连接,才能继续发送业务数据包。 2.1连接服务器 客户端连接指定服务器上的端口,建立TCP/IP层上的长连接。 2.2注册通信 在已经连接服务器的基础上,向服务器端注册自己的身份。 注册通信是所有业务数据包发送之前发送的第一个数据包。它由客户端发送登陆名与密码到服务器,服务器根据注册包中的登陆名与密码,对客户端的合法性进行验证,然后返回注册消息返回包给客户端。如果验证通过,则客户端与服务器就可以进行后面的业务数据的通讯,否则断开TCP/IP连接 2.3通信过程 2.3.1 GPSMT、GPSMP发起的消息 2.3.2 GPSBS发起的消息 2.4注销通信 客户端向服务端发起请求断开连接,服务器端收到请求返回一个注销应答,当客户端收到应答后,关闭此连接。 2.5关闭连接 断开TCP/IP层的连接。 2.6通信异常处理 如果服务器端接收到的命令语法错误,比如命令不完整、命令无法识别等,则断开和客户端的连接;客户端应该向服务器端建立新连接继续发送命令。 如果客户端接收到的应答语法错误,比如命令不完整、命令无法识别等,则主动断开和服务器端的连接;服务器端也应该断开和客户端的连接。 如果命令语法正确,但服务器端不处理该命令,则返回相应应答,并在应答中指定错误原因。 如果应答语法正确,但客户端不处理该应答,则丢弃。 2.7连接故障处理 客户端与服务器端的通信过程中,如果由于线路或其他原因导致TCP/IP连接断开,客户端应尝试重连。 3消息定义 3.1消息中数据类型 类型 说明 Unsigned Integer 无符号整数, 采用网络字节顺序 Text 字符串 (表一)消息的数据类型 注:消息说明中的长度指占用字节数。 3.2消息组成 基于TCP/IP连接上GPSP协议消息分为消息头与消息体两部分。 项目 说明 消息头 消息头部分 消息体 消息体部分 (表二)消息的组成 消息头分为同步头、消息长度、消息类型三部分: 项目 类型 长度 说明 取值 同步头 Text 4 为检测每个包的起始位置 “^#~>” 消息长度 Unsigned Integer 4 整个消息头与消息体的长度 消息类型 Unsigned Integer 4 表示此消息的类型 参见【常量定义】中的消息类型定义 (表三)消息头的组成 消息体是由格式良好的XML组成。此XML的根元素必须是<ROOT>;业务请求消息包中必须包含<FUNCODE>(功能码)和<TRACE >(序列号),业务请求应答包必须包含<RETCODE>(返回码)和<TRACE >(序列号)。具体消息定义参见下面消息体描述。 序列号(TRACE)由“MMDDHHmmss”+四位流水号(从0000到9999),长度为14位,能保证一年不重复,如“06241304350345”,表示6月24日13点04分35秒第345个包。 注:以下描述中元素值全为Text类型;所标长度为最大长度(不足长度的不用补其他字符);本文档XML中的汉字为元素值的中文描述。 3.3消息体描述 3.3.1注册消息 注册消息是校验监控终端的合法性。为了不在注册消息中传送明文用户名和明文密码,采用校验GPSBS分配的用户名与密码摘要的方式实现。 <?xml version="1.0" encoding="GB2312" standalone="no"?> <ROOT> <TRACE>序列号</TRACE> MERCID<>ERP代码</MERCID> <USERNAME> 用户名</USERNAME> <PASSWORD >用户密码摘要base64编码</PASSWORD> </ROOT> 元素名 重要性 元素值长度 元素值描述 TRACE 必须 14 序列号 MERCID 必须 8 ERP代码 USERNAME 必须 28 由GPSBS提供的登陆用户名 PASSWORD 必须 28 由GPSBS提供的登陆密码MD5摘要的base64编码,用来检测接入的合法性 3.3.2注销消息 <?xml version="1.0" encoding="GB2312" standalone="no"?> <ROOT> <TRACE>序列号</TRACE> </ROOT> 元素名 重要性 元素值长度 元素值描述 TRACE 必须 14 序列号 3.3.3探测包消息 <?xml version="1.0" encoding="GB2312" standalone="no"?> <ROOT> <TRACE>序列号</TRACE> </ROOT> 元素名 重要性 元素值长度 元素值描述 TRACE 必须 14 序列号 3.3.4业务请求消息 <?xml version="1.0" encoding="GB2312" standalone="no"?> <ROOT> <TRACE>序列号</TRACE> <TRANSFLAG>传送方向</TRANSFLAG> <FUNCODE>功能码</FUNCODE> <!—其他元素待定 </ROOT> 元素名 重要性 元素值长度 元素值描述 TRACE 必须 14 序列号 TRANSFLAG 必须 2 ‘00’服务端请求;’10’客户端请求 FUNCODE 必须 8 功能码,取值参见【常量定义】中的业务请求/应答功能码定义 必须 其他元素,参见下面的具体业务 3.3.5注册应答消息 <?xml version="1.0" encoding="GB2312" standalone="no"?> <ROOT> <TRACE>序列号</TRACE> <RETCODE>返回码</RETCODE> <ERRDESC>失败原因</ERRDESC> </ROOT> 元素名 重要性 元素值长度 元素值描述 TRACE 必须 14 消息序列号原样返回 RETCODE 必须 1 注册消息返回值,返回码参见【常量定义】中的返回码定义 ERRDESC 可选 100 失败原因 3.3.6注销应答消息 <?xml version="1.0" encoding="GB2312" standalone="no"?> <ROOT> <TRACE>序列号</TRACE> </ROOT> 元素名 重要性 元素值长度 元素值描述 TRACE 必须 14 消息序列号原样返回 3.3.7探测包应答消息 <?xml version="1.0" encoding="GB2312" standalone="no"?> <ROOT> <TRACE>序列号</TRACE> </ROOT> 元素名 重要性 元素值长度 元素值描述 TRACE 必须 14 消息序列号原样返回 3.3.8业务请求应答消息 <?xml version="1.0" encoding="GB2312" standalone="no"?> <ROOT> <TRACE>序列号</TRACE> <TRANSFLAG>传送方向</TRANSFLAG> <FUNCODE>功能码</FUNCODE> <RETCODE>返回码</RETCODE> </ROOT> 元素名 重要性 元素值长度 元素值描述 TRACE 必须 14 序列号 TRANSFLAG 必须 2 ’01’服务端应答;’11’客户端应答 FUNCODE 必须 8 业务请求功能码原样返回 RETCODE 必须 8 业务请求消息返回码,参见【常量定义】中的返回码定义 4常量定义 5.1服务端口定义 服务器名称 服务器IP 服务端口 客户端名称 5.2消息类型定义 消息名称 消息取值(十六进制) 注册消息 0x00000001 注册应答消息 0x10000001 注销消息 0x00000002 注销应答消息 0x10000002 探测消息 0x00000003 探测消息应答 0x10000003 业务请求消息 0x00000004 业务请求应答消息 0x10000004 (表五)消息类型定义 5.3返回码定义 错误码 描述 0 无错误,命令正确接收 1 非法登录,如登录名、口令出错、登录名与口令不符等。 2 非法源地址 3 连接过多,指单个节点要求同时建立的连接数过多。 4 设备ID重复登录 5 参数格式错误 7 设备ID不存在 8 设备ID已经存在 9 对应移动终端SIM卡号不存在 10 对应移动终端SIM卡号已经存在 其他 待定 (表六)返回码定义

欢迎进来讨论,,,一起进步

设备通信存在以下特性: 1、单线程,同时只支持一个socket通信 2、采用一问一答(连续发送的指令时,需要前一条指令响应回来,才能发第二条),有一种特殊情况设备随时从udp通道会给我发来告警的信息,如设备上一些异常操作,这个不需要发送指令的 3、现在与设备通信指令有四十种左右,可以理解成api,只不过是异步的 4、每个指令的格式大体相同 ,请求的数据体有区别,响应也是一样。针对不同的响应我们实现了不同的响应处理类。主要是对响应的十六进制的数据进行解析成我们认识的java封装的对象。 下面是楼主面临的问题: 场景:通过各种指令的组合,去完成一个业务工单,比如拆纤的业务工单,在页面发起一个拆纤动作,设备上会以慢闪提示(发了两条慢闪的指令),然后现场操作人员会将慢闪的端口的纤拔了,此时那个端口会有拔出的告警。根据告警会再次发送 灭灯指令,当需要拔的端口都操作完了,这个拆纤业务也就结束了。 楼主的方案: 第一阶段:整个方案没有第三方框架的介入,所有逻辑是自己设计的。首先发送指令和接收指令的核心代码用数据库表设计的队列,启动收发两个线程,发送线程每50毫秒去扫描发送队列表,有数据就进行发送。收线程不停接收,将接收的数据拼成一个完整的响应后分发给不同响应的处理类。 第一阶段的问题很多,主要有: 1、首先用数据库实现队列,50ms去扫描,增加数据库的压力,同时效率不能满足 2、发送和接收核心代码实现了很好封装,但是响应处理类跟业务耦合性太高,而且响应处理类需要根据不同的业务类型做不同的业务,也就是响应处理类后期代码分之会非常多,不便维护 第二阶段:重新选择了方案:用redis内存数据库代替了db数据库,同时引入了activiti流程的概念,收发核心代码跟方案一类似,lz很快实现了。但是activiti是我另一个同事在研究(我们项目大都是一到两年工作经验,lz三年了算是最老了,但是技术还是菜),本来打算用流程来解决不同的工单,但是在尝试过程中结合到实际的业务还是不能很好的满足。而且把流程搞得变味了,工单业务也复杂多了 小弟在这里先谢谢大家,能耐心的看完我对目前工作的理解。有些地方描述的不好,各位多多包涵,希望大神们指导一下,给出一些建议或者技术选型。再次谢谢 更多 0

大学四年自学走来,这些私藏的实用工具/学习网站我贡献出来了

大学四年,看课本是不可能一直看课本的了,对于学习,特别是自学,善于搜索网上的一些资源来辅助,还是非常有必要的,下面我就把这几年私藏的各种资源,网站贡献出来给你们。主要有:电子书搜索、实用工具、在线视频学习网站、非视频学习网站、软件下载、面试/求职必备网站。 注意:文中提到的所有资源,文末我都给你整理好了,你们只管拿去,如果觉得不错,转发、分享就是最大的支持了。 一、电子书搜索 对于大部分程序员...

在中国程序员是青春饭吗?

今年,我也32了 ,为了不给大家误导,咨询了猎头、圈内好友,以及年过35岁的几位老程序员……舍了老脸去揭人家伤疤……希望能给大家以帮助,记得帮我点赞哦。 目录: 你以为的人生 一次又一次的伤害 猎头界的真相 如何应对互联网行业的「中年危机」 一、你以为的人生 刚入行时,拿着傲人的工资,想着好好干,以为我们的人生是这样的: 等真到了那一天,你会发现,你的人生很可能是这样的: ...

Java基础知识面试题(2020最新版)

文章目录Java概述何为编程什么是Javajdk1.5之后的三大版本JVM、JRE和JDK的关系什么是跨平台性?原理是什么Java语言有哪些特点什么是字节码?采用字节码的最大好处是什么什么是Java程序的主类?应用程序和小程序的主类有何不同?Java应用程序与小程序之间有那些差别?Java和C++的区别Oracle JDK 和 OpenJDK 的对比基础语法数据类型Java有哪些数据类型switc...

我以为我学懂了数据结构,直到看了这个导图才发现,我错了

数据结构与算法思维导图

String s = new String(" a ") 到底产生几个对象?

老生常谈的一个梗,到2020了还在争论,你们一天天的,哎哎哎,我不是针对你一个,我是说在座的各位都是人才! 上图红色的这3个箭头,对于通过new产生一个字符串(”宜春”)时,会先去常量池中查找是否已经有了”宜春”对象,如果没有则在常量池中创建一个此字符串对象,然后堆中再创建一个常量池中此”宜春”对象的拷贝对象。 也就是说准确答案是产生了一个或两个对象,如果常量池中原来没有 ”宜春” ,就是两个。...

技术大佬:我去,你写的 switch 语句也太老土了吧

昨天早上通过远程的方式 review 了两名新来同事的代码,大部分代码都写得很漂亮,严谨的同时注释也很到位,这令我非常满意。但当我看到他们当中有一个人写的 switch 语句时,还是忍不住破口大骂:“我擦,小王,你丫写的 switch 语句也太老土了吧!” 来看看小王写的代码吧,看完不要骂我装逼啊。 private static String createPlayer(PlayerTypes p...

Linux面试题(2020最新版)

文章目录Linux 概述什么是LinuxUnix和Linux有什么区别?什么是 Linux 内核?Linux的基本组件是什么?Linux 的体系结构BASH和DOS之间的基本区别是什么?Linux 开机启动过程?Linux系统缺省的运行级别?Linux 使用的进程间通信方式?Linux 有哪些系统日志文件?Linux系统安装多个桌面环境有帮助吗?什么是交换空间?什么是root帐户什么是LILO?什...

Linux命令学习神器!命令看不懂直接给你解释!

大家都知道,Linux 系统有非常多的命令,而且每个命令又有非常多的用法,想要全部记住所有命令的所有用法,恐怕是一件不可能完成的任务。 一般情况下,我们学习一个命令时,要么直接百度去搜索它的用法,要么就直接用 man 命令去查看守冗长的帮助手册。这两个都可以实现我们的目标,但有没有更简便的方式呢? 答案是必须有的!今天给大家推荐一款有趣而实用学习神器 — kmdr,让你解锁 Linux 学习新姿势...

和黑客斗争的 6 天!

互联网公司工作,很难避免不和黑客们打交道,我呆过的两家互联网公司,几乎每月每天每分钟都有黑客在公司网站上扫描。有的是寻找 Sql 注入的缺口,有的是寻找线上服务器可能存在的漏洞,大部分都...

史上最全的 python 基础知识汇总篇,没有比这再全面的了,建议收藏

网友们有福了,小编终于把基础篇的内容全部涉略了一遍,这是一篇关于基础知识的汇总的文章,请朋友们收下,不用客气,不过文章篇幅肯能会有点长,耐心阅读吧爬虫(七十)多进程multiproces...

讲一个程序员如何副业月赚三万的真实故事

loonggg读完需要3分钟速读仅需 1 分钟大家好,我是你们的校长。我之前讲过,这年头,只要肯动脑,肯行动,程序员凭借自己的技术,赚钱的方式还是有很多种的。仅仅靠在公司出卖自己的劳动时...

女程序员,为什么比男程序员少???

昨天看到一档综艺节目,讨论了两个话题:(1)中国学生的数学成绩,平均下来看,会比国外好?为什么?(2)男生的数学成绩,平均下来看,会比女生好?为什么?同时,我又联想到了一个技术圈经常讨...

85后蒋凡:28岁实现财务自由、34岁成为阿里万亿电商帝国双掌门,他的人生底层逻辑是什么?...

蒋凡是何许人也? 2017年12月27日,在入职4年时间里,蒋凡开挂般坐上了淘宝总裁位置。 为此,时任阿里CEO张勇在任命书中力赞: 蒋凡加入阿里,始终保持创业者的冲劲,有敏锐的...

总结了 150 余个神奇网站,你不来瞅瞅吗?

原博客再更新,可能就没了,之后将持续更新本篇博客。

副业收入是我做程序媛的3倍,工作外的B面人生是怎样的?

提到“程序员”,多数人脑海里首先想到的大约是:为人木讷、薪水超高、工作枯燥…… 然而,当离开工作岗位,撕去层层标签,脱下“程序员”这身外套,有的人生动又有趣,马上展现出了完全不同的A/B面人生! 不论是简单的爱好,还是正经的副业,他们都干得同样出色。偶尔,还能和程序员的特质结合,产生奇妙的“化学反应”。 @Charlotte:平日素颜示人,周末美妆博主 大家都以为程序媛也个个不修边幅,但我们也许...

MySQL数据库面试题(2020最新版)

文章目录数据库基础知识为什么要使用数据库什么是SQL?什么是MySQL?数据库三大范式是什么mysql有关权限的表都有哪几个MySQL的binlog有有几种录入格式?分别有什么区别?数据类型mysql有哪些数据类型引擎MySQL存储引擎MyISAM与InnoDB区别MyISAM索引与InnoDB索引的区别?InnoDB引擎的4大特性存储引擎选择索引什么是索引?索引有哪些优缺点?索引使用场景(重点)...

新一代神器STM32CubeMonitor介绍、下载、安装和使用教程

关注、星标公众号,不错过精彩内容作者:黄工公众号:strongerHuang最近ST官网悄悄新上线了一款比较强大的工具:STM32CubeMonitor V1.0.0。经过我研究和使用之...

如果你是老板,你会不会踢了这样的员工?

有个好朋友ZS,是技术总监,昨天问我:“有一个老下属,跟了我很多年,做事勤勤恳恳,主动性也很好。但随着公司的发展,他的进步速度,跟不上团队的步伐了,有点...

我入职阿里后,才知道原来简历这么写

私下里,有不少读者问我:“二哥,如何才能写出一份专业的技术简历呢?我总感觉自己写的简历太烂了,所以投了无数份,都石沉大海了。”说实话,我自己好多年没有写过简历了,但我认识的一个同行,他在阿里,给我说了一些他当年写简历的方法论,我感觉太牛逼了,实在是忍不住,就分享了出来,希望能够帮助到你。 01、简历的本质 作为简历的撰写者,你必须要搞清楚一点,简历的本质是什么,它就是为了来销售你的价值主张的。往深...

大学一路走来,学习互联网全靠这几个网站,最终拿下了一把offer

大佬原来都是这样炼成的

离职半年了,老东家又发 offer,回不回?

有小伙伴问松哥这个问题,他在上海某公司,在离职了几个月后,前公司的领导联系到他,希望他能够返聘回去,他很纠结要不要回去? 俗话说好马不吃回头草,但是这个小伙伴既然感到纠结了,我觉得至少说明了两个问题:1.曾经的公司还不错;2.现在的日子也不是很如意。否则应该就不会纠结了。 老实说,松哥之前也有过类似的经历,今天就来和小伙伴们聊聊回头草到底吃不吃。 首先一个基本观点,就是离职了也没必要和老东家弄的苦...

为什么你不想学习?只想玩?人是如何一步一步废掉的

不知道是不是只有我这样子,还是你们也有过类似的经历。 上学的时候总有很多光辉历史,学年名列前茅,或者单科目大佬,但是虽然慢慢地长大了,你开始懈怠了,开始废掉了。。。 什么?你说不知道具体的情况是怎么样的? 我来告诉你: 你常常潜意识里或者心理觉得,自己真正的生活或者奋斗还没有开始。总是幻想着自己还拥有大把时间,还有无限的可能,自己还能逆风翻盘,只不是自己还没开始罢了,自己以后肯定会变得特别厉害...

什么时候跳槽,为什么离职,你想好了么?

都是出来打工的,多为自己着想

为什么程序员做外包会被瞧不起?

二哥,有个事想询问下您的意见,您觉得应届生值得去外包吗?公司虽然挺大的,中xx,但待遇感觉挺低,马上要报到,挺纠结的。

当HR压你价,说你只值7K,你该怎么回答?

当HR压你价,说你只值7K时,你可以流畅地回答,记住,是流畅,不能犹豫。 礼貌地说:“7K是吗?了解了。嗯~其实我对贵司的面试官印象很好。只不过,现在我的手头上已经有一份11K的offer。来面试,主要也是自己对贵司挺有兴趣的,所以过来看看……”(未完) 这段话主要是陪HR互诈的同时,从公司兴趣,公司职员印象上,都给予对方正面的肯定,既能提升HR的好感度,又能让谈判气氛融洽,为后面的发挥留足空间。...

面试阿里p7,被按在地上摩擦,鬼知道我经历了什么?

面试阿里p7被问到的问题(当时我只知道第一个):@Conditional是做什么的?@Conditional多个条件是什么逻辑关系?条件判断在什么时候执...

你期望月薪4万,出门右拐,不送,这几个点,你也就是个初级的水平

先来看几个问题通过注解的方式注入依赖对象,介绍一下你知道的几种方式@Autowired和@Resource有何区别说一下@Autowired查找候选者的...

面试了一个 31 岁程序员,让我有所触动,30岁以上的程序员该何去何从?

最近面试了一个31岁8年经验的程序猿,让我有点感慨,大龄程序猿该何去何从。

大三实习生,字节跳动面经分享,已拿Offer

说实话,自己的算法,我一个不会,太难了吧

程序员垃圾简历长什么样?

已经连续五年参加大厂校招、社招的技术面试工作,简历看的不下于万份 这篇文章会用实例告诉你,什么是差的程序员简历! 疫情快要结束了,各个公司也都开始春招了,作为即将红遍大江南北的新晋UP主,那当然要为小伙伴们做点事(手动狗头)。 就在公众号里公开征简历,义务帮大家看,并一一点评。《启舰:春招在即,义务帮大家看看简历吧》 一石激起千层浪,三天收到两百多封简历。 花光了两个星期的所有空闲时...

立即提问
相关内容推荐