socketio依赖及版本

Message javaBean

@Data
public class MyMessage {
    private String username;
    private Integer age;
    private String content;

server端 代码片段

// 监听事件
@OnEvent("message")
public void onMessage(SocketIOClient client, MyMessage message) {
    log.info("接收消息: sessionId={}, message={}", client.getSessionId(), message.toString());

client-js端 代码片段

var msg = {
    username: "icetea",
    age: 18,
    content: "my name is icetea."
socket.emit('message', msg);

client-java端 代码片段

MyMessage msg = new MyMessage("icetea", 18, "my name is icetea.");
socket.emit("message", msg); // 直接传javaBean不行
// 或者 socket.emit("message", JSON.toJSONString(msg)); javaBean转为json string也不行

使用socketio js客户端时可以正常解析参数,但使用 socketio java客户端发送java bean消息时,netty-socketio无法解析传来的参数,并且将javabean转换成json字符串也会报错

ERROR 11236 — [ntLoopGroup-3-3] c.c.socketio.JsonSupportWrapper: Can’t read value: [“message-model”,“MyMessage(username=icetea, age=18, content=my name is icetea.)”] for type: class com.corundumstudio.socketio.protocol.Event

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of life.icetea.test.nettysocketio.domain.MyMessage (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value (‘MyMessage(username=icetea, age=19, content=my name is icetea.)’)
at [Source: (io.netty.buffer.ByteBufInputStream); line: 1, column: 18]

查看netty-socketio官方仓库的issues发现有相同的问题,https://github.com/mrniko/netty-socketio/issues/258, 里面有人说是client传参序列化的问题,并且给出了解决方案。如下:

参考1:https://github.com/mrniko/netty-socketio/issues/258#issuecomment-417607871

//Android client use json parser is "org.json",when emit message,you should like this:
ChatEvent data = new ChatEvent(); 
mSocket.emit("message", new JSONObject(data));
// 该方法中的org.json的JSONObject构造只能传递一个map类型
 

参考2:https://github.com/mrniko/netty-socketio/issues/258#issuecomment-449638424

//try and convert the object you are trying to send to a string using GSON library
mSocket.emit("message", new JSONObject(new Gson().toJson(data)));
// 该方法使用Gson所以需要引入Gson依赖
 

参考3: https://github.com/mrniko/netty-socketio/issues/258#issuecomment-465497609

此回答解释了为什么js-client会成功而java-client会失败的原因,因为java-client在序列化参数时存在问题。

参考后得出的解决方法

参考前两个回答,都是将javaBean转成对应依赖(Gson和org.json)的Json对象,因为我的项目使用的是fastJson,而fastJson也有对应的JSONObject,所以照葫芦画瓢,示例如下:

MyMessage msg = new MyMessage("icetea", 18, "my name is icetea.");
socket.emit("message", JSON.toJSON(msg));
// 该方法能够让server正常接收参数

找到解决方法,然后来详细总结一下为什么在socket.emit()方法中直接传递javabean或者传递json的字符串不行,debug找到socketio-java-client底层序列化参数的源码片段如下:

// io.socket.client.Socket#emit(java.lang.String, java.lang.Object[], io.socket.client.Ack)
// ······
// 要发送的参数都放到了org.json.JSONArray对象
JSONArray jsonArgs = new JSONArray();
jsonArgs.put(event);
if (args != null) {
    for (Object arg : args) {
        jsonArgs.put(arg);
// 将JSONArray参数封装成packet
Packet<JSONArray> packet = new Packet<JSONArray>(Parser.EVENT, jsonArgs);
// ······

从以上片段看出要发送的参数都放到了org.json.JSONArray对象中并封装成Packet,然后再往下debug找到了将参数encode成String的方法,代码片段如下:

// io.socket.parser.IOParser.Encoder#encodeAsString
// ······
private String encodeAsString(Packet obj) {
    StringBuilder str = new StringBuilder("" + obj.type);
    // ······
    if (obj.data != null) {
        str.append(obj.data);
    // ······
    return str.toString();

从以上片段看出,Packet有被解析成一串字符串,且要传送的参数是字符串中的一部分,然后往下debug就是直接send方法。到此参数封装结束。那么从以上分析得出,java-client的参数封装和JSONArray这个类有很大关系,所以可以测试一下JSONArray的toString方法看看展示出的结果是什么样子:

public static void main(String[] args) {
    MyMessage msg = new MyMessage("icetea", 18, "my name is icetea.");
    // 直接put java bean
    JSONArray jsonArray = new JSONArray();
    jsonArray.put("message");
    jsonArray.put(msg);
    System.out.println(jsonArray);
    // 转成fastJson的JSONObject
    JSONArray jsonArray1 = new JSONArray();
    jsonArray1.put("message");
    jsonArray1.put(JSON.toJSON(msg));
    System.out.println(jsonArray1);
    // 使用Map测试一下,因为fastJson的JSONObject其实就是一个Map
    JSONArray jsonArray2 = new JSONArray();
    jsonArray2.put("message");
    HashMap<String, Object> map = new HashMap<>();
    map.put("username", "icetea");
    map.put("age", 18);
    map.put("content", "my name is icetea.");
    jsonArray2.put(map);
    System.out.println(jsonArray2);
    // 将javaBean转成json string测试
    JSONArray jsonArray3 = new JSONArray();
    jsonArray3.put("message");
    jsonArray3.put(JSON.toJSONString(msg));
    System.out.println(jsonArray3);
// 输出如下:
["message","MyMessage(username=icetea, age=18, content=my name is icetea.)"]
["message",{"age":18,"content":"my name is icetea.","username":"icetea"}]
["message",{"age":18,"content":"my name is icetea.","username":"icetea"}]
["message","{\"age\":18,\"content\":\"my name is icetea.\",\"username\":\"icetea\"}"]

从测试结果可以看出,第二种方式(转成JSONObject)和第三种方式(使用Map封装参数)得出的结果符合json字符串的标准,且能够被netty-socketio反序列化成javaBean。

总结的出另一种方式

// 注意:使用map方式属性必须都是基本类型,不能嵌套有javaBean,否则还会报错,所以推荐使用JSONObject方式
Map<String, Object> msg = new HashMap<>();
msg.put("username", "icetea");
msg.put("age", 18);
msg.put("content", "my name is icetea.");
socket.emit("message", msg);
                    socketio依赖及版本server: netty-socketio v1.7.17client-java: socket.io-client-java v1.0.0client-js: socket.io-client-js v2.1.1关键代码Message javaBean@Datapublic class MyMessage {    private String username;    private Integer age;    private String con
import houlei.net.tcp.codec.GenericPackageClassifierCodec;
import houlei.net.tcp.codec.GenericPackageCodec;
import houlei.net.tcp.hdr.NettyServerHandler;
import io.netty.boo
import com.corundumstudio.socketio.Configuration;
import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstud...
一个简单的模型,在Android手机上部署一个Netty写的服务器,绑定端口9000,等待客户端连接,连接建立后,读取来自PC客户端的发送过来的字符串。
在Android手机上安装部署的Netty服务器:
package zhangphil.netttserver;
import...
  A. 起始分隔符:标明一个数据包的开始部分(里面还隐含了小端模式的信息,这个小端模式可以忽略);
  B. 协议的版本:当前版本是明文传输的,考虑到后期升级可能要采用密文传输包体,所以,设计了一个版本字段;
  C. 频道号:这个字段的作用不明显,目前是想将包信息按照业务分类,比如:网络连接,权限认证,聊天信息等;
  D. 命令字:与频道号联合起来作...
				
在使用 Node http 服务器,需要解决跨域问题 在server对应文件夹运行终端node index.js(index为自定义的名称) index.js文件中(名称自定) 原var io = require('socket.io')(app); 改为var io = require('socket.io')(app,{cors:true}); 一般我们不会自己写一个服务器,所以,用express框架 npm install --save express
下面主要讲解跟 @OnEvent 相关代码的注释 一:SocketIoServer创建 启动服务端,首先要创建SocketIoServer,创建socketIoServer实例做了如下几件事: 创建namespacesHub = new NamespacesHub(读取到的配置#{com.corundumstudio.socketio}),存放创建的所有的Namespace 创建并添加默认mainNamespace<“”,mainNamespace>到namespacesHub.namesp
1. 在客户端,使用 HTML5 的 File API 读取本地图片文件。 2. 将图片文件换为二进制数据。 3. 使用 netty-socketio 客户端库向服务器端发送二进制数据。 在服务器端,您可以使用以下步骤来接收并保存图片: 1. 使用 netty-socketio 服务器端库接收客户端发送的二进制数据。 2. 将二进制数据写入文件或保存到数据库中。 您还可以使用服务器端的某些库将图片换为可以在网页上显示的格式,然后向其他客户端广播图片。 希望这些信息对您有帮助。
ElasticJob启动不了 Caused by:com.dangdang.ddframe.job.exception.JobConfigurationException: Job conflict wujiumengxing: ElasticJob启动不了 Caused by:com.dangdang.ddframe.job.exception.JobConfigurationException: Job conflict Git命令记录 解决idea一直卡在build不动的问题