到网上找到了一篇文章《 使用protobuf进行C#与Java通信 》进行学习 ,使用protobuf进行编码,传递数据,好像这样可以避免编码的问题。
(虽然编码问题解决了,但是粘包问题并没有解决,有经验的朋友介绍下怎样解决粘包的问题)
服务器端基于networkcomms V3 C#通信框架. networkcomms 通信框架是商业版的,本文也并不提供。
引用原文:http://blog.csdn.net/wangpei421/article/details/8004903
用protobuf进行C#与Java通信 在之前已写一篇关于ProtoBuf的文章了,主要是.net版本的实现。今天主要是讲如何利用ProtoBuf定义一个协议,来实现C#与Java双方进行通信(这个通信指的是双方数据协议,而不是通信协议。) ProtoBuf 应用场景 个人认为,主要用于数据交互和共享,此种情况需要双方制定一个特定的数据结构。那么使用ProtoBuf 定义一个数据结构,然后大家从这个描述文件,各自生成自己使用的编程语言对应的代码文件,再使用这些代码对双方的数据进行处理。那么,只要都遵守这个数据文件格式,数据共享就可以实现夸平台。如果数据描述文件做了修改,只要遵守一定的规则,那么原有数据还是可以兼容使用的。这个就是做了一个平台无关的文件与平台和语言相关的数据对象之间的适配转化工作,就和很多xml解析器一样。 实现C#与Java通信步骤 1.定义协议 创建一个以.proto为后缀的文件,本篇创建了一个名为msg.proto的消息文件,具体信息如下: package tutorial; option java_package = "com.protobuftest.protobuf"; (生成Java类时包名;C#类的命名空间) option java_outer_classname = "PersonProbuf"; (生成Java、C#类的类名) message Person { required string name = 1; required int32 id = 2; optional string email = 3; enum PhoneType { MOBILE = 0; HOME = 1; WORK = 2; } message PhoneNumber { required string number = 1; optional PhoneType type = 2 [default = HOME]; } repeated PhoneNumber phone = 4; message CountryInfo { required string name = 1; required string code = 2; optional int32 number = 3; } } message AddressBook { repeated Person person = 1; } package在Java里面代表这个文件所在的包名,在c#里面代表该文件的命名空间; message代表一个类; required 代表该字段必填; optional 代表该字段可选,并可以为其设置默认值,默认值格式 :[defalut=Home],它是一个枚举类型。
引用原文:
2.双方都编译.proto文件(本篇文章主要用的是2.4.1版本的protobuf) proto可以在Linux、Windows下编译。 protobuf 下载列表请参照:http://code.google.com/p/protobuf/downloads/list ,选择其中的win版本下载。解压后会得到一个 protoc.exe 文件,此时就可以开始编译了。 java 的编译的步骤如下: (1) 打开命令工具 cmd (2) 把protoc.exe文件放在D:/protoc 目录下,先cd 到该目录cd D:/protoc (3) 输入protoc.exe --java_out=./ msg.proto 此时会发现 D:/protoc目录中多了一个文件夹com/protobuftest/protobuf,即以该proto的package命名的目录,会产生一个Msg.java的文件,这时这个文件就可以使用到我们的java或者android 工程了。 (4) 下载一个protobuf-java-2.4.1.jar的jar 包引用到你的java和android工程里面,之后可以使用你的protobuf了。 C# 的编译步骤: .net 版的protobuf来源于proto社区,有两个版本。一个版本叫protobuf-net,官方站点:http://code.google.com/p/protobuf-net/ 写法上比较符合c#一贯的写法。 另一个版本叫protobuf-csharp-sport , 官方站点:http://code.google.com/p/protobuf-csharp-port/ 写法上跟java上的使用极其相似,比较遵循Google 的原生态写法,跨平台选择此版本比较好。因为你会发现几乎和java的写法没啥两样,本篇也是使用这个版本。 http://code.google.com/p/protobuf-csharp-port/下载Win版本,编译步骤如下: (1) 把proto文件放在你解压出来的目录与protoc.exe 、ProtoGen.exe、ProtoGen.exe.config、Google.ProtocolBuffers.dll放于一起。其他文件可以删除或者备份。 (2) 打开命令行cmd,定位于对应的目录里面。 输入:protoc --descriptor_set_out=msg.protobin --include_imports msg.proto msg.protobin是要生成的prtobobin文件,可以使用这个bin文件生成cs文件 再输入protogen msg.protobin 使用该bin文件生成cs文件,这样你就可以得到该msg.cs 的CSharp版文件了,同时在VS里面使用要引入Google.ProtocolBuffers.dll。
忙了一下午,把相关的工具都找齐了,proto版本与引用的文中的版本号不是一个版本,可以使用
c# 相关protobuf文件
java 相关protobuf文件
服务器端代码:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using NetworkCommsDotNet; using NetworkCommsDotNet.DPSBase; using NetworkCommsDotNet.Tools; using NetworkCommsDotNet.Connections; using NetworkCommsDotNet.Connections.TCP; using System.Net; using Google.ProtocolBuffers; using tutorial; namespace protobufServer { public partial class Form1 : Form { SendReceiveOptions sro = new SendReceiveOptions(DPSManager.GetDataSerializer<NullSerializer>(), null, null); public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { //服务器开始监听客户端的请求 //开始监听某端口 //与其他语言通信 禁用ApplicationLayerProtocolStatus TCPConnectionListener listener=new TCPConnectionListener (sro,ApplicationLayerProtocolStatus.Disabled); Connection.StartListening(listener, new IPEndPoint(IPAddress.Parse(txtIP.Text), int.Parse(txtPort.Text))); button1.Text = "监听中"; button1.Enabled = false; //此方法中包含服务器具体的处理方法。 StartListening(); } private void StartListening() { NetworkComms.DisableLogging(); //array 收到字节 NetworkComms.AppendGlobalIncomingUnmanagedPacketHandler((header, connection, array) => { Person person2 = Person.ParseFrom(array); LogInfo.LogMessage(person2.Id + "," + person2.Name + ", " + person2.Email, "日志.txt"); IList<Person.Types.PhoneNumber> lstPhones = person2.PhoneList; foreach (Person.Types.PhoneNumber phoneNumber in lstPhones) { LogInfo.LogMessage(phoneNumber.Number.ToString(), "日志.txt"); } //返回一个数据给客户端 //序列化 Person.Builder builder = new Person.Builder(); builder.SetEmail("名山大川@email.com"); builder.SetId(1); builder.SetName("大江东去浪淘尽"); builder.AddPhone(new Person.Types.PhoneNumber.Builder().SetNumber("12345679").SetType(Person.Types.PhoneType.MOBILE)); builder.AddPhone(new Person.Types.PhoneNumber.Builder().SetNumber("123456").SetType(Person.Types.PhoneType.HOME)); Person person = builder.Build(); byte[] buf = person.ToByteArray(); connection.SendUnmanagedBytes(buf); }); } private void Form1_FormClosing_1(object sender, FormClosingEventArgs e) { NetworkComms.Shutdown(); Environment.Exit(Environment.ExitCode); } } }View Code
客户端
服务器端:
java代码
package com.protobuftest.protobuf; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintWriter; import java.net.Socket; import com.google.protobuf.InvalidProtocolBufferException; import java.util.List; import java.io.BufferedReader; import java.io.InputStreamReader; import java.lang.Runtime; import java.io.IOException; public class First extends Thread{ public static byte[] readStream(InputStream inStream) throws Exception { int count = 0; while (count == 0) { count = inStream.available(); } byte[] b = new byte[count]; inStream.read(b); return b; } /** * @param args */ public static void main(String[] args) throws Exception { Socket socket = null; int j = 0; try { socket = new Socket("127.0.0.1", 3000); if (socket.isConnected()) { System.out.println("已建立连接!---"); PersonProbuf.Person.Builder builder = PersonProbuf.Person.newBuilder(); builder.setEmail("kkk@email.com"); builder.setId(1); builder.setName("TestName"); builder.addPhone(PersonProbuf.Person.PhoneNumber.newBuilder().setNumber("131111111").setType(PersonProbuf.Person.PhoneType.MOBILE)); builder.addPhone(PersonProbuf.Person.PhoneNumber.newBuilder().setNumber("011111").setType(PersonProbuf.Person.PhoneType.HOME)); PersonProbuf.Person person = builder.build(); byte[] buf = person.toByteArray(); //2.得到socket读写流 OutputStream os=socket.getOutputStream(); //3.利用流按照一定的操作,对socket进行读写操作 os.write(buf); os.flush(); System.out.println("----------------------------------"); InputStream ips = socket.getInputStream(); byte[] rebyte = readStream(ips); // String resultStr = new String(rebyte, 0, rebyte.length, "UTF-8"); // System.out.println("收到主机消息:" + resultStr); PersonProbuf.Person person2 = PersonProbuf.Person.parseFrom(rebyte); System.out.println(person2.getId()+","+person2.getName() + ", " + person2.getEmail()); List<PersonProbuf.Person.PhoneNumber> lstPhones = person2.getPhoneList(); for(PersonProbuf.Person.PhoneNumber phoneNumber : lstPhones) { System.out.println(phoneNumber.getNumber()); } } } catch(Exception s){ System.out.print(s); } } }View Code
c#工程文件 (不含通信库) 通信库用别的库也是一样的