这几天在博客园上看到好几个写Java和C#的socket通信的帖子。但是都为指出其中关键点。

C# socket通信组件有很多,在vs 使用nuget搜索socket组件有很多类似的。本人使用的是自己开发的一套组件。

Java socket通信的组件也有很多,常用的大多数都是用的mina或者netty。游戏行业使用也是居多。

关于socket的底层写法,实在太多,我就不在BB。

这里我想说,C#和C++或者叫VC++把是使用小端序作为字节序。而java使用的是大端序作为字节序。

也就是说比如一个int占用四个字节,java的字节序和c#的字节序是相反的,java的int四个字节第一个字节在数组的最后一个。C#是第一个。

也就是说如果java端正常发送一个int的字节序给C#,需要翻转一次端绪。反之也是一样的。一句话来概括的话就是高位在前还是低位在前的问题。

C#输出数字 int 4 的字节序。为了保证c#下面绝对是是int所以加入了强制int转化。默认的话可能是byte

java的默认输出,这里使用的是netty的默认框架。进行的int4的字节序输出

高位和低位表示法完全不同。

java下面如果传输字符串,那么必须要先把字符串转化成byte数组,然后获取数组长度,在字节序里面压入int表示的数组长度,然后在然如byte数组。不管你的字符串多长。

而C#也是相同做法。但是唯一不同的是数组的长度表示法不同。微软经过了字节压缩的。用字节的前7位表示长度。第8位表示下一个字节是否也是表示长度的字节,值需要与128位于。

从而减少字节的消耗。

现在一般如果我们在java和C#中无论是哪一个语言作为服务器。架设socket通信基准。其中另外一方都要妥协字节序反转问题。

大多数情况下我们也许通信的要求不高,或许把一些类或者参数通过json格式化以后传输给对方。但是在这一条消息的传输中,一般会有两个int需要字节序。最少也要一个字节序。

一个字节序int表示消息长度。另外一个字节序表示消息协议。

如果消息协议都放到json里面没有问题。但是消息长度是必不可少的。因为你需要知道在网络环境中,消息压栈,然后等待系统发出是有可能两条消息一同发送的。也或者消息发送后由于网络阻塞,前后相差好几秒的消息同一时间达到。

这就是所谓的粘包。

我这里就不表演了。

还有另外一种通信方式,就是通过protobuf进行字节序的序列化,和反序列,官方支持java,第三方支持C#。这个组件可以减少字节流。达到省流量,减少网络资源消耗的问题。

例如一个long的类型值是1常规发送需要8个字节,64位。发送。如果改用protobuf的话只需要1字节8位就能发送。

同样的问题,无论你使用哪一种序列化方式,都需要消息长度和消息协议号。

C#下面对int的反转读取。

         /// <summary>
         /// 读取大端序的int
         /// </summary>
         /// <param name="value"></param>
         public int ReadInt(byte[] intbytes)
         {
             Array.Reverse(intbytes);
             );
         }

         /// <summary>
         /// 写入大端序的int
         /// </summary>
         /// <param name="value"></param>
         public byte[] WriterInt(int value)
         {
             byte[] bs = BitConverter.GetBytes(value);
             Array.Reverse(bs);
             return bs;
         }

粘包问题解决。

C#代码

 using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;

 /**
  *
  * @author 失足程序员
  * @Blog http://www.cnblogs.com/ty408/
  * @mail 492794628@qq.com
  * @phone 13882122019
  *
  */
 namespace Sz.Network.SocketPool
 {
     public class MarshalEndian : IMarshalEndian
     {

         public enum JavaOrNet
         {
             Java,
             Net,
         }

         public MarshalEndian()
         {

         }

         public static JavaOrNet JN = JavaOrNet.Net;

         /// <summary>
         /// 读取大端序的int
         /// </summary>
         /// <param name="value"></param>
         public int ReadInt(byte[] intbytes)
         {
             Array.Reverse(intbytes);
             );
         }

         /// <summary>
         /// 写入大端序的int
         /// </summary>
         /// <param name="value"></param>
         public byte[] WriterInt(int value)
         {
             byte[] bs = BitConverter.GetBytes(value);
             Array.Reverse(bs);
             return bs;
         }

         //用于存储剩余未解析的字节数
         );

         //字节数常量一个消息id4个字节
         const long ConstLenght = 4L;

         public void Dispose()
         {
             this.Dispose(true);
             GC.SuppressFinalize(this);
         }

         protected virtual void Dispose(bool flag1)
         {
             if (flag1)
             {
                 IDisposable disposable = this._LBuff as IDisposable;
                 if (disposable != null) { disposable.Dispose(); }
             }
         }

         public byte[] Encoder(SocketMessage msg)
         {
             MemoryStream ms = new MemoryStream();
             BinaryWriter bw = new BinaryWriter(ms, UTF8Encoding.Default);
             byte[] msgBuffer = msg.MsgBuffer;

             if (msgBuffer != null)
             {
                 switch (JN)
                 {
                     case JavaOrNet.Java:
                         bw.Write(WriterInt(msgBuffer.Length + ));
                         bw.Write(WriterInt(msg.MsgID));
                         break;
                     case JavaOrNet.Net:
                         bw.Write((Int32)(msgBuffer.Length + ));
                         bw.Write(msg.MsgID);
                         break;
                 }

                 bw.Write(msgBuffer);
             }
             else
             {
                 switch (JN)
                 {
                     case JavaOrNet.Java:
                         bw.Write(WriterInt());
                         break;
                     case JavaOrNet.Net:
                         bw.Write((Int32));
                         break;
                 }
             }
             bw.Close();
             ms.Close();
             bw.Dispose();
             ms.Dispose();
             return ms.ToArray();
         }

         public List<SocketMessage> Decoder(byte[] buff, int len)
         {
             //拷贝本次的有效字节
             byte[] _b = new byte[len];
             Array.Copy(buff, , _b, , _b.Length);
             buff = _b;
             )
             {
                 //拷贝之前遗留的字节
                 this._LBuff.AddRange(_b);
                 buff = this._LBuff.ToArray();
                 this._LBuff.Clear();
                 );
             }
             List<SocketMessage> list = new List<SocketMessage>();
             MemoryStream ms = new MemoryStream(buff);
             BinaryReader buffers = new BinaryReader(ms, UTF8Encoding.Default);
             try
             {
                 byte[] _buff;
             Label_0073:
                 //判断本次解析的字节是否满足常量字节数
                 if ((buffers.BaseStream.Length - buffers.BaseStream.Position) < ConstLenght)
                 {
                     _buff = buffers.ReadBytes((int)(buffers.BaseStream.Length - buffers.BaseStream.Position));
                     this._LBuff.AddRange(_buff);
                 }
                 else
                 {
                     ;
                     switch (JN)
                     {
                         case JavaOrNet.Java:
                             offset = ReadInt(buffers.ReadBytes());
                             break;
                         case JavaOrNet.Net:
                             offset = buffers.ReadInt32();
                             break;
                     }

                     //剩余字节数大于本次需要读取的字节数
                     if (offset <= (buffers.BaseStream.Length - buffers.BaseStream.Position))
                     {
                         ;
                         switch (JN)
                         {
                             case JavaOrNet.Java:
                                 msgID = ReadInt(buffers.ReadBytes());
                                 break;
                             case JavaOrNet.Net:
                                 msgID = buffers.ReadInt32();
                                 break;
                         }
                         _buff = buffers.ReadBytes(());
                         list.Add(new SocketMessage(msgID, _buff));
                         goto Label_0073;
                     }
                     else
                     {
                         //剩余字节数刚好小于本次读取的字节数 存起来,等待接受剩余字节数一起解析
                         buffers.BaseStream.Seek(ConstLenght, SeekOrigin.Current);
                         _buff = buffers.ReadBytes((int)(buffers.BaseStream.Length - buffers.BaseStream.Position));
                         this._LBuff.AddRange(_buff);
                     }
                 }
             }
             catch { }
             finally
             {
                 buffers.Close();
                 if (buffers != null) { buffers.Dispose(); }
                 ms.Close();
                 if (ms != null) { ms.Dispose(); }
             }
             return list;
         }
     }
 }

java netty

 /*
  * To change this license header, choose License Headers in Project Properties.
  * To change this template file, choose Tools | Templates
  * and open the template in the editor.
  */
 package sz.network.socketpool.nettypool;

 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.handler.codec.ByteToMessageDecoder;
 import java.nio.ByteOrder;
 import java.util.ArrayList;
 import java.util.List;
 import org.apache.log4j.Logger;

 /**
  * 解码器
  */
 class NettyDecoder extends ByteToMessageDecoder {

     private static final Logger logger = Logger.getLogger(NettyDecoder.class);

     private byte ZreoByteCount = 0;
     private ByteBuf bytes;
     private final ByteOrder endianOrder = ByteOrder.LITTLE_ENDIAN;
     private long secondTime = 0;
     private int reveCount = 0;

     public NettyDecoder() {

     }

     ByteBuf bytesAction(ByteBuf inputBuf) {
         ByteBuf bufferLen = Unpooled.buffer();
         if (bytes != null) {
             bufferLen.writeBytes(bytes);
             bytes = null;
         }
         bufferLen.writeBytes(inputBuf);
         return bufferLen;
     }

     /**
      * 留存无法读取的byte等待下一次接受的数据包
      *
      * @param bs 数据包
      * @param startI 起始位置
      * @param lenI 结束位置
      */
     void bytesAction(ByteBuf intputBuf, int startI, int lenI) {
         if (lenI - startI > 0) {
             bytes = Unpooled.buffer();
             bytes.writeBytes(intputBuf, startI, lenI);
         }
     }

     @Override
     protected void decode(ChannelHandlerContext chc, ByteBuf inputBuf, List<Object> outputMessage) {
         if (System.currentTimeMillis() - secondTime < 1000L) {
             reveCount++;
         } else {
             secondTime = System.currentTimeMillis();
             reveCount = 0;
         }

         if (reveCount > 50) {
             logger.error("发送消息过于频繁");
             chc.disconnect();
             return;
         }

         if (inputBuf.readableBytes() > 0) {
             ZreoByteCount = 0;
             //重新组装字节数组
             ByteBuf buffercontent = bytesAction(inputBuf);
             List<NettyMessageBean> megsList = new ArrayList<>(0);
             for (;;) {
                 //读取 消息长度(short)和消息ID(int) 需要 8 个字节
                 if (buffercontent.readableBytes() >= 8) {
                     ///读取消息长度
                     int len = buffercontent.readInt();
                     if (buffercontent.readableBytes() >= len) {
                         int messageid = buffercontent.readInt();///读取消息ID
                         ByteBuf buf = buffercontent.readBytes(len - 4);//读取可用字节数;
                         megsList.add(new NettyMessageBean(chc, messageid, buf.array()));
                         //第二次重组
                         if (buffercontent.readableBytes() > 0) {
                             bytesAction(buffercontent, buffercontent.readerIndex(), buffercontent.readableBytes());
                             buffercontent = Unpooled.buffer();
                             buffercontent.writeBytes(bytes);
                             continue;
                         } else {
                             break;
                         }
                     }
                     ///重新设置读取进度
                     buffercontent.setIndex(buffercontent.readableBytes() - 2, inputBuf.readableBytes());
                 }
                 ///缓存预留的字节
                 bytesAction(buffercontent, buffercontent.readerIndex(), buffercontent.readableBytes());
                 break;
             }
             outputMessage.addAll(megsList);
         } else {
             ZreoByteCount++;
             if (ZreoByteCount >= 3) {
                 //todo 空包处理 考虑连续三次空包,断开链接
                 logger.error("decode 空包处理 连续三次空包");
                 chc.close();
             }
         }
     }
 }

这是我封装的部分代码,因为现目前公司的开发组织架构为,java是服务器端。U3D 使用C#是客户端开发。所以考虑性能问题,是C#妥协进行字节序反转操作~!

就不在添加调试和测试代码和结果因为觉得没多少意义~!

到此结束~!

我看不下去鸟。。。。Java和C#的socket通信真的简单吗?的更多相关文章

  1. Java网络编程和NIO详解1:JAVA 中原生的 socket 通信机制

    Java网络编程和NIO详解1:JAVA 中原生的 socket 通信机制 JAVA 中原生的 socket 通信机制 摘要:本文属于原创,欢迎转载,转载请保留出处:https://github.co ...

  2. java和C#之间SOCKET通信的问题

    转自:http://www.cdtarena.com/javapx/201307/9170.html java和C#之间SOCKET通信的问题 一.服务器端(使用java编写) /** * 监听客户端 ...

  3. Java和C#的socket通信相关(转)

    这几天在博客园上看到好几个写Java和C#的socket通信的帖子.但是都为指出其中关键点. C# socket通信组件有很多,在vs 使用nuget搜索socket组件有很多类似的.本人使用的是自己 ...

  4. Java进阶(四十七)Socket通信

    Java进阶(四十七)Socket通信   今天讲解一个 Hello Word 级别的 Java Socket 通信的例子.具体通讯过程如下: 先启动Server端,进入一个死循环以便一直监听某端口是 ...

  5. Java和C++通过Socket通信中文乱码的解决

    理想的开发状态是我开始就是C开发,一直是C的开发,现在还是C的开发,若干年后,幸运的话,我可以成为C语言的高手或者专家…… 更实际的情况是我开始是C开发,后来变成了JAVA开发,然后又做起了VC++的 ...

  6. java 网络编程之TCP通信和简单的文件上传功能

    */ .hljs { display: block; overflow-x: auto; padding: 0.5em; color: #333; background: #f8f8f8; } .hl ...

  7. java 网络编程之UDP通信和简单的群聊程序

    */ .hljs { display: block; overflow-x: auto; padding: 0.5em; color: #333; background: #f8f8f8; } .hl ...

  8. 170411、java Socket通信的简单例子(UDP)

    服务端代码: package com.bobohe.socket; import java.io.*; import java.net.*; class UDPServer { public stat ...

  9. 170410、java Socket通信的简单例子(TCP)

    服务端代码: package com.bobohe.socket; import java.io.*; import java.net.*; import java.applet.Applet; pu ...

随机推荐

  1. InnoDB关键特性学习笔记

    插入缓存 Insert Buffer Insert Buffer是InnoDB存储引擎关键特性中最令人激动与兴奋的一个功能.不过这个名字可能会让人认为插入缓冲是缓冲池中的一个组成部分.其实不然,Inn ...

  2. 学习ASP.NET Core, 怎能不了解请求处理管道[5]: 中间件注册可以除了可以使用Startup之外,还可以选择StartupFilter

    中间件的注册除了可以借助Startup对象(DelegateStartup或者ConventionBasedStartup)来完成之外,也可以利用另一个叫做StartupFilter的对象来实现.所谓 ...

  3. JavaScript动画-碰撞检测

    ▓▓▓▓▓▓ 大致介绍 碰撞检测是指在页面中有多个元素时,拖拽一个元素会出现碰撞问题,碰撞检测是以模拟拖拽和磁性吸附中的范围限定为基础的 效果:碰撞检测 ▓▓▓▓▓▓ 碰撞检测 先来看看碰撞检测的原理 ...

  4. 基于SignalR实现B/S系统对windows服务运行状态的监测

    通常来讲一个BS项目肯定不止单独的一个BS应用,可能涉及到很多后台服务来支持BS的运行,特别是针对耗时较长的某些任务来说,Windows服务肯定是必不可少的,我们还需要利用B/S与windows服务进 ...

  5. 菜鸟Python学习笔记第二天:关于Python黑客。

    2016年1月5日 星期四 天气:还好 一直不知道自己为什么要去学Python,其实Python能做到的Java都可以做到,Python有的有点Java也有,而且Java还是必修课,可是就是不愿意去学 ...

  6. 纸箱堆叠 bzoj 2253

    纸箱堆叠 (1s 128MB) box [问题描述] P 工厂是一个生产纸箱的工厂.纸箱生产线在人工输入三个参数 n, p, a 之后,即可自动化生产三边边长为 (a mod P, a^2 mod p ...

  7. SSH免手动输入密码和设置代理

    通过使用sshpass将密码写入命令里,直接执行,免去手动密码输入的步骤命令如下: sshpass -p password_abc ssh user_abc@ssh_host -p ssh_port ...

  8. Linux基础介绍【第四篇】

    Linux文件和目录的属性及权限 命令: [root@oldboy ~]# ls -lhi total 40K 24973 -rw-------. 1 root root 1.1K Dec 10 16 ...

  9. Linux网络属性配置

    目录 IP地址分类 如何将Linux主机接入到网络中 网络接口的命名方式 ifcfg系列命令 如何配置主机名 如何配置DNS服务器指向 iproute2系列命令 Linux管理网络服务 永久生效配置路 ...

  10. JavaScript多线程之HTML5 Web Worker

    在博主的前些文章Promise的前世今生和妙用技巧和JavaScript单线程和浏览器事件循环简述中都曾提到了HTML5 Web Worker这一个概念.在JavaScript单线程和浏览器事件循环简 ...