Java和C#的socket通信相关(转)
这几天在博客园上看到好几个写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的反转读取。

- 1 /// <summary>
- 2 /// 读取大端序的int
- 3 /// </summary>
- 4 /// <param name="value"></param>
- 5 public int ReadInt(byte[] intbytes)
- 6 {
- 7 Array.Reverse(intbytes);
- 8 return BitConverter.ToInt32(intbytes, 0);
- 9 }
- 10
- 11 /// <summary>
- 12 /// 写入大端序的int
- 13 /// </summary>
- 14 /// <param name="value"></param>
- 15 public byte[] WriterInt(int value)
- 16 {
- 17 byte[] bs = BitConverter.GetBytes(value);
- 18 Array.Reverse(bs);
- 19 return bs;
- 20 }

粘包问题解决。
C#代码

- 1 using System;
- 2 using System.Collections.Generic;
- 3 using System.IO;
- 4 using System.Linq;
- 5 using System.Text;
- 6 using System.Threading.Tasks;
- 7
- 8 /**
- 9 *
- 10 * @author 失足程序员
- 11 * @Blog http://www.cnblogs.com/ty408/
- 12 * @mail 492794628@qq.com
- 13 * @phone 13882122019
- 14 *
- 15 */
- 16 namespace Sz.Network.SocketPool
- 17 {
- 18 public class MarshalEndian : IMarshalEndian
- 19 {
- 20
- 21 public enum JavaOrNet
- 22 {
- 23 Java,
- 24 Net,
- 25 }
- 26
- 27 public MarshalEndian()
- 28 {
- 29
- 30 }
- 31
- 32 public static JavaOrNet JN = JavaOrNet.Net;
- 33
- 34 /// <summary>
- 35 /// 读取大端序的int
- 36 /// </summary>
- 37 /// <param name="value"></param>
- 38 public int ReadInt(byte[] intbytes)
- 39 {
- 40 Array.Reverse(intbytes);
- 41 return BitConverter.ToInt32(intbytes, 0);
- 42 }
- 43
- 44 /// <summary>
- 45 /// 写入大端序的int
- 46 /// </summary>
- 47 /// <param name="value"></param>
- 48 public byte[] WriterInt(int value)
- 49 {
- 50 byte[] bs = BitConverter.GetBytes(value);
- 51 Array.Reverse(bs);
- 52 return bs;
- 53 }
- 54
- 55 //用于存储剩余未解析的字节数
- 56 private List<byte> _LBuff = new List<byte>(2);
- 57
- 58 //字节数常量一个消息id4个字节
- 59 const long ConstLenght = 4L;
- 60
- 61 public void Dispose()
- 62 {
- 63 this.Dispose(true);
- 64 GC.SuppressFinalize(this);
- 65 }
- 66
- 67 protected virtual void Dispose(bool flag1)
- 68 {
- 69 if (flag1)
- 70 {
- 71 IDisposable disposable = this._LBuff as IDisposable;
- 72 if (disposable != null) { disposable.Dispose(); }
- 73 }
- 74 }
- 75
- 76 public byte[] Encoder(SocketMessage msg)
- 77 {
- 78 MemoryStream ms = new MemoryStream();
- 79 BinaryWriter bw = new BinaryWriter(ms, UTF8Encoding.Default);
- 80 byte[] msgBuffer = msg.MsgBuffer;
- 81
- 82 if (msgBuffer != null)
- 83 {
- 84 switch (JN)
- 85 {
- 86 case JavaOrNet.Java:
- 87 bw.Write(WriterInt(msgBuffer.Length + 4));
- 88 bw.Write(WriterInt(msg.MsgID));
- 89 break;
- 90 case JavaOrNet.Net:
- 91 bw.Write((Int32)(msgBuffer.Length + 4));
- 92 bw.Write(msg.MsgID);
- 93 break;
- 94 }
- 95
- 96 bw.Write(msgBuffer);
- 97 }
- 98 else
- 99 {
- 100 switch (JN)
- 101 {
- 102 case JavaOrNet.Java:
- 103 bw.Write(WriterInt(0));
- 104 break;
- 105 case JavaOrNet.Net:
- 106 bw.Write((Int32)0);
- 107 break;
- 108 }
- 109 }
- 110 bw.Close();
- 111 ms.Close();
- 112 bw.Dispose();
- 113 ms.Dispose();
- 114 return ms.ToArray();
- 115 }
- 116
- 117 public List<SocketMessage> Decoder(byte[] buff, int len)
- 118 {
- 119 //拷贝本次的有效字节
- 120 byte[] _b = new byte[len];
- 121 Array.Copy(buff, 0, _b, 0, _b.Length);
- 122 buff = _b;
- 123 if (this._LBuff.Count > 0)
- 124 {
- 125 //拷贝之前遗留的字节
- 126 this._LBuff.AddRange(_b);
- 127 buff = this._LBuff.ToArray();
- 128 this._LBuff.Clear();
- 129 this._LBuff = new List<byte>(2);
- 130 }
- 131 List<SocketMessage> list = new List<SocketMessage>();
- 132 MemoryStream ms = new MemoryStream(buff);
- 133 BinaryReader buffers = new BinaryReader(ms, UTF8Encoding.Default);
- 134 try
- 135 {
- 136 byte[] _buff;
- 137 Label_0073:
- 138 //判断本次解析的字节是否满足常量字节数
- 139 if ((buffers.BaseStream.Length - buffers.BaseStream.Position) < ConstLenght)
- 140 {
- 141 _buff = buffers.ReadBytes((int)(buffers.BaseStream.Length - buffers.BaseStream.Position));
- 142 this._LBuff.AddRange(_buff);
- 143 }
- 144 else
- 145 {
- 146 long offset = 0;
- 147 switch (JN)
- 148 {
- 149 case JavaOrNet.Java:
- 150 offset = ReadInt(buffers.ReadBytes(4));
- 151 break;
- 152 case JavaOrNet.Net:
- 153 offset = buffers.ReadInt32();
- 154 break;
- 155 }
- 156
- 157 //剩余字节数大于本次需要读取的字节数
- 158 if (offset <= (buffers.BaseStream.Length - buffers.BaseStream.Position))
- 159 {
- 160 int msgID = 0;
- 161 switch (JN)
- 162 {
- 163 case JavaOrNet.Java:
- 164 msgID = ReadInt(buffers.ReadBytes(4));
- 165 break;
- 166 case JavaOrNet.Net:
- 167 msgID = buffers.ReadInt32();
- 168 break;
- 169 }
- 170 _buff = buffers.ReadBytes((int)(offset - 4));
- 171 list.Add(new SocketMessage(msgID, _buff));
- 172 goto Label_0073;
- 173 }
- 174 else
- 175 {
- 176 //剩余字节数刚好小于本次读取的字节数 存起来,等待接受剩余字节数一起解析
- 177 buffers.BaseStream.Seek(ConstLenght, SeekOrigin.Current);
- 178 _buff = buffers.ReadBytes((int)(buffers.BaseStream.Length - buffers.BaseStream.Position));
- 179 this._LBuff.AddRange(_buff);
- 180 }
- 181 }
- 182 }
- 183 catch { }
- 184 finally
- 185 {
- 186 buffers.Close();
- 187 if (buffers != null) { buffers.Dispose(); }
- 188 ms.Close();
- 189 if (ms != null) { ms.Dispose(); }
- 190 }
- 191 return list;
- 192 }
- 193 }
- 194 }

java netty

- 1 /*
- 2 * To change this license header, choose License Headers in Project Properties.
- 3 * To change this template file, choose Tools | Templates
- 4 * and open the template in the editor.
- 5 */
- 6 package sz.network.socketpool.nettypool;
- 7
- 8 import io.netty.buffer.ByteBuf;
- 9 import io.netty.buffer.Unpooled;
- 10 import io.netty.channel.ChannelHandlerContext;
- 11 import io.netty.handler.codec.ByteToMessageDecoder;
- 12 import java.nio.ByteOrder;
- 13 import java.util.ArrayList;
- 14 import java.util.List;
- 15 import org.apache.log4j.Logger;
- 16
- 17 /**
- 18 * 解码器
- 19 */
- 20 class NettyDecoder extends ByteToMessageDecoder {
- 21
- 22 private static final Logger logger = Logger.getLogger(NettyDecoder.class);
- 23
- 24 private byte ZreoByteCount = 0;
- 25 private ByteBuf bytes;
- 26 private final ByteOrder endianOrder = ByteOrder.LITTLE_ENDIAN;
- 27 private long secondTime = 0;
- 28 private int reveCount = 0;
- 29
- 30 public NettyDecoder() {
- 31
- 32 }
- 33
- 34 ByteBuf bytesAction(ByteBuf inputBuf) {
- 35 ByteBuf bufferLen = Unpooled.buffer();
- 36 if (bytes != null) {
- 37 bufferLen.writeBytes(bytes);
- 38 bytes = null;
- 39 }
- 40 bufferLen.writeBytes(inputBuf);
- 41 return bufferLen;
- 42 }
- 43
- 44 /**
- 45 * 留存无法读取的byte等待下一次接受的数据包
- 46 *
- 47 * @param bs 数据包
- 48 * @param startI 起始位置
- 49 * @param lenI 结束位置
- 50 */
- 51 void bytesAction(ByteBuf intputBuf, int startI, int lenI) {
- 52 if (lenI - startI > 0) {
- 53 bytes = Unpooled.buffer();
- 54 bytes.writeBytes(intputBuf, startI, lenI);
- 55 }
- 56 }
- 57
- 58 @Override
- 59 protected void decode(ChannelHandlerContext chc, ByteBuf inputBuf, List<Object> outputMessage) {
- 60 if (System.currentTimeMillis() - secondTime < 1000L) {
- 61 reveCount++;
- 62 } else {
- 63 secondTime = System.currentTimeMillis();
- 64 reveCount = 0;
- 65 }
- 66
- 67 if (reveCount > 50) {
- 68 logger.error("发送消息过于频繁");
- 69 chc.disconnect();
- 70 return;
- 71 }
- 72
- 73 if (inputBuf.readableBytes() > 0) {
- 74 ZreoByteCount = 0;
- 75 //重新组装字节数组
- 76 ByteBuf buffercontent = bytesAction(inputBuf);
- 77 List<NettyMessageBean> megsList = new ArrayList<>(0);
- 78 for (;;) {
- 79 //读取 消息长度(short)和消息ID(int) 需要 8 个字节
- 80 if (buffercontent.readableBytes() >= 8) {
- 81 ///读取消息长度
- 82 int len = buffercontent.readInt();
- 83 if (buffercontent.readableBytes() >= len) {
- 84 int messageid = buffercontent.readInt();///读取消息ID
- 85 ByteBuf buf = buffercontent.readBytes(len - 4);//读取可用字节数;
- 86 megsList.add(new NettyMessageBean(chc, messageid, buf.array()));
- 87 //第二次重组
- 88 if (buffercontent.readableBytes() > 0) {
- 89 bytesAction(buffercontent, buffercontent.readerIndex(), buffercontent.readableBytes());
- 90 buffercontent = Unpooled.buffer();
- 91 buffercontent.writeBytes(bytes);
- 92 continue;
- 93 } else {
- 94 break;
- 95 }
- 96 }
- 97 ///重新设置读取进度
- 98 buffercontent.setIndex(buffercontent.readableBytes() - 2, inputBuf.readableBytes());
- 99 }
- 100 ///缓存预留的字节
- 101 bytesAction(buffercontent, buffercontent.readerIndex(), buffercontent.readableBytes());
- 102 break;
- 103 }
- 104 outputMessage.addAll(megsList);
- 105 } else {
- 106 ZreoByteCount++;
- 107 if (ZreoByteCount >= 3) {
- 108 //todo 空包处理 考虑连续三次空包,断开链接
- 109 logger.error("decode 空包处理 连续三次空包");
- 110 chc.close();
- 111 }
- 112 }
- 113 }
- 114 }

这是我封装的部分代码,因为现目前公司的开发组织架构为,java是服务器端。U3D 使用C#是客户端开发。所以考虑性能问题,是C#妥协进行字节序反转操作~!
就不在添加调试和测试代码和结果因为觉得没多少意义~!
到此结束~!
*
* @author 失足程序员
* @Blog http://www.cnblogs.com/ty408/
* @mail 492794628@qq.com
* @phone 13882122019
*
*/
跪求保留标示符
本程序猿所有博客园相关全套源码奉献 淘宝SVN。特别鸣谢淘宝SVN提供免费仓储。
http://code.taobao.org/svn/flynetwork_csharp/trunk/Flynetwork/BlogTest
Java和C#的socket通信相关(转)的更多相关文章
- Java进阶(四十七)Socket通信
Java进阶(四十七)Socket通信 今天讲解一个 Hello Word 级别的 Java Socket 通信的例子.具体通讯过程如下: 先启动Server端,进入一个死循环以便一直监听某端口是 ...
- 我看不下去鸟。。。。Java和C#的socket通信真的简单吗?
这几天在博客园上看到好几个写Java和C#的socket通信的帖子.但是都为指出其中关键点. C# socket通信组件有很多,在vs 使用nuget搜索socket组件有很多类似的.本人使用的是自己 ...
- java和C#之间SOCKET通信的问题
转自:http://www.cdtarena.com/javapx/201307/9170.html java和C#之间SOCKET通信的问题 一.服务器端(使用java编写) /** * 监听客户端 ...
- Java网络编程和NIO详解1:JAVA 中原生的 socket 通信机制
Java网络编程和NIO详解1:JAVA 中原生的 socket 通信机制 JAVA 中原生的 socket 通信机制 摘要:本文属于原创,欢迎转载,转载请保留出处:https://github.co ...
- Java实现简单的socket通信
今天学习了一下java如何实现socket通信,感觉难点反而是在io上,因为java对socket封装已经很完善了. 今天代码花了整个晚上调试,主要原因是io的flush问题和命令行下如何运行具有pa ...
- Java 实现简单的 Socket 通信
Java socket 封装了传输层的实现细节,开发人员可以基于 socket 实现应用层.本文介绍了 Java socket 简单用法. 1. 传输层协议 传输层包含了两种协议,分别是 TCP (T ...
- Java和C++通过Socket通信中文乱码的解决
理想的开发状态是我开始就是C开发,一直是C的开发,现在还是C的开发,若干年后,幸运的话,我可以成为C语言的高手或者专家…… 更实际的情况是我开始是C开发,后来变成了JAVA开发,然后又做起了VC++的 ...
- [java]基于UDP的Socket通信Demo
java课编程作业:在老师给的demo的基础上实现客户端发送数据到服务器端,服务器端接受客户端后进行数据广播. 整体功能类似于聊天室,代码部分不是太难,但是在本机测试的时候出现这样的问题: 服务端通过 ...
- Jmeter自定义编写Java代码调用socket通信
一.前言 最近需要测试一款手机游戏的性能,找不到啥录制脚本的工具,然后,另外想办法.性能测试实际上就是对服务器的承载能力的测试,和各种类型的手机客户端没有啥多大关系,手机再好,服务器负载不了,也不能够 ...
随机推荐
- Python学习入门基础教程(learning Python)--2.3.1 Python传参函数设计
本节主要讨论设计传递多个参数子函数的设计方法. 在2.3节里我们讨论了如何自己设计一个带参数的子函数的设计方法,现在我们研究一下如何传递两个及以上参数的设计方法. 函数为何要带参数呢?其实原因很简单, ...
- java.lang.NullPointerException错误分析
java.lang.NullPointerException是什么错误 你使用了空的指针.在java中虽然号称抛弃了C++中不安全的指针,但其实他所有的东西你都可以理解为指针.这种情况一般发生在你使用 ...
- windows phone (15) UI变换上
原文:windows phone (15) UI变换上 在wp中只要是继承自UIElement 的任何对象都可以应用变换,当然包含Textblock,Rectangle等所有的元素,下面我们使用Tex ...
- 高速幂 POW优化
#include <iostream> #include <stdio.h> #include <stdlib.h> #include <string.h&g ...
- Coco2dx-3.0中怎样调用LUA
一个用3.0的工具导出类到lua,自己主动生成代码的方法. 曾经要导出c++类到lua.就得手动维护pkg文件,那简直就是噩梦.3.0以后就会感觉生活非常轻松了. 以下我就在说下详细做法. 1.安装必 ...
- 领域驱动设计(DDD)部分核心概念的个人理解(转)
领域驱动设计(DDD)是一种基于模型驱动的软件设计方式.它以领域为核心,分析领域中的问题,通过建立一个领域模型来有效的解决领域中的核心的复杂问题.Eric Ivans为领域驱动设计提出了大量的最佳实践 ...
- Qt计算器开发(二):信号槽实现数学表达式合法性检查
表达式的合法性 由于我们的计算器不是单步计算的,所以我们能够一次性输入一个长表达式.然而假设用户输入的长表达式不合法的话,那么就会引发灾难.所以有必要对于用户的输入做一个限制. 一些限制举例: 比方, ...
- Jenkins(转)
1 修改jenkins的根目录,默认地在C:\Documents and Settings\AAA\.jenkins . .jenkins ├─jobs│ └─JavaHelloWorld│ ...
- 【Python项目】配合爱漫画爬取漫画脚本而设计的GUI漫画阅读器 (一)
博客园的第一个坑,想想都有点小激动 =3= 首先是那个爬虫的地址: [原创]最近写的一个比较hack的小爬虫 选择工具: 以前用过Qt,那么选pyqt4也就是情理之中了. 明确需求: 0.首先,要读取 ...
- hdu 4308 Saving Princess claire_ BFS
为了准备算法考试刷的,想明确一点即可,全部的传送门相当于一个点,当遇到一个传送门的时候,把全部的传送门都压入队列进行搜索 贴代码: #include <iostream> #include ...