软件的客户端原来是用DELPHI写的,翻译成C#,服务器端是VC写的,原来的协议比较复杂,我就用DELPHI写了一个非常简单的现在卡在了C#发送结构体,结构体中字符串与BYTE类型的都没有问题,但是发送整数据(delphi中integer,C#中int或Int32)收到的数据是错误的另外如果结构体中有结构体数组时,应该如何写,如何给结构体的数据赋值呢?
上代码 using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;using System.Windows.Forms;
using System.Runtime.InteropServices;
using MTWS.Net.SocketClient;
namespace MTWS.Net.AppCode
{
public partial class TestTcp : Form
{
public TestTcp()
{
InitializeComponent();
}
struct TMsgHeadInfo
{
//[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public char MsgCode;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public char[] MsgType;
public byte Sender;
//public int SendInt;
}
struct TMsgBody
{
public TMsgHeadInfo msghead; //假如这里是一个结构体数组时应该如何定义和赋值呢?
//[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
//public TMsgHeadInfo[] msghead; 这样是不对的
//public TMsgHeadInfo[2] msghead; 这样也不对
//此处到底应该怎样定义与赋值?另外,协议是原来定好了的,肯定不能变了,改协议来解决这个问题的话,就不用提了
public Int32 body; //这里哪个类型对就DELPHI里的integer?
}
public static byte[] StructToBytes(object structObj)
{
//得到结构体的大小
int size = Marshal.SizeOf(structObj);
//创建byte数组
byte[] bytes = new byte[size];
//分配结构体大小的内存空间
IntPtr structPtr = Marshal.AllocHGlobal(size);
//将结构体拷到分配好的内存空间
Marshal.StructureToPtr(structObj, structPtr, false);
//从内存空间拷到byte数组
Marshal.Copy(structPtr, bytes, 0, size);
//释放内存空间
Marshal.FreeHGlobal(structPtr);
//返回byte数组
return bytes;
}
private void TestTcp_Load(object sender, EventArgs e)
{ }
private void button1_Click(object sender, EventArgs e)
{
int ret;
TMsgBody msgbody;
//TMsgHeadInfo msghead;
TCPClient tcp = new TCPClient();
string code = "zp";
string type = "ai";
//string body = "cc";
ret = tcp.ConnectServer("127.0.0.1", 3578);
if (ret == 0)
{
MessageBox.Show("连接服务器失败");
}
else
{
MessageBox.Show("连接服务器成功");
msgbody.msghead.MsgCode = code.ToCharArray();
msgbody.msghead.MsgType = type.ToCharArray();
msgbody.msghead.Sender = 5;
msgbody.body = 44;// 服务器端收到后,实际不是44,其他数据类型没有问题
byte[] msg = StructToBytes(msgbody);
if (tcp.SendMsg(msg) > 0)
{
MessageBox.Show("发送成功");
}
else
{
MessageBox.Show("发送失败");
}
}
}
}
}服务器端delphi代码,组件用的indy9unit Unit1;interfaceuses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, IdBaseComponent, IdComponent, IdTCPServer;type
TChar2 = array[0..1] of Char;
TMsgHead=packed record
MsgCode, MsgType: TChar2;
sender: Byte;
senderint: Integer;
end; TMsgBody=packed record
msgHead: TMsgHead;
body: Integer;
end; TForm1 = class(TForm)
IdTCPServer1: TIdTCPServer;
Button1: TButton;
Edit1: TEdit;
Edit2: TEdit;
Edit3: TEdit;
Edit4: TEdit;
procedure Button1Click(Sender: TObject);
procedure IdTCPServer1Execute(AThread: TIdPeerThread);
private
{ Private declarations }
public
{ Public declarations }
end;var
Form1: TForm1;implementation{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);
begin
IdTCPServer1.DefaultPort := 3578;
IdTCPServer1.Active := True;
end;function Min(AValueOne, AValueTwo : Integer): Integer;
begin
If AValueOne > AValueTwo then
begin
Result := AValueTwo
end //If AValueOne > AValueTwo then
else
begin
Result := AValueOne;
end; //..If AValueOne > AValueTwo then
end;function PCharToStr(ABuf: array of char; ABufLen: Integer): string;
{
将PChar(#0结尾)转换为string
}
var
LenOfStr: Integer;
begin
LenOfStr := Min(ABufLen, StrLen(ABuf));
if LenOfStr <= 0 then
begin
Result := '';
end
else
begin
SetLength(Result, LenOfStr);
Move(ABuf[0], Result[1], LenOfStr);
end;
end;procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread);
//var msgHead: TMsgHead;
var msgBody: TMsgBody;
begin
if AThread.Connection.Connected then begin
FillChar(msgBody, SizeOf(TMsgBody), 0);
AThread.Connection.ReadBuffer(msgBody, SizeOf(TMsgBody));
Edit1.Text := PCharToStr(msgBody.msgHead.MsgCode, 2);
Edit2.Text := PCharToStr(msgBody.msgHead.MsgType, 2);
Edit3.Text := IntToStr(Integer(msgBody.msgHead.sender));
Edit4.Text := IntToStr(msgBody.msgHead.senderint);
end;
end;end.C#socketStructureDelphi结构体
上代码 using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;using System.Windows.Forms;
using System.Runtime.InteropServices;
using MTWS.Net.SocketClient;
namespace MTWS.Net.AppCode
{
public partial class TestTcp : Form
{
public TestTcp()
{
InitializeComponent();
}
struct TMsgHeadInfo
{
//[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public char MsgCode;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public char[] MsgType;
public byte Sender;
//public int SendInt;
}
struct TMsgBody
{
public TMsgHeadInfo msghead; //假如这里是一个结构体数组时应该如何定义和赋值呢?
//[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
//public TMsgHeadInfo[] msghead; 这样是不对的
//public TMsgHeadInfo[2] msghead; 这样也不对
//此处到底应该怎样定义与赋值?另外,协议是原来定好了的,肯定不能变了,改协议来解决这个问题的话,就不用提了
public Int32 body; //这里哪个类型对就DELPHI里的integer?
}
public static byte[] StructToBytes(object structObj)
{
//得到结构体的大小
int size = Marshal.SizeOf(structObj);
//创建byte数组
byte[] bytes = new byte[size];
//分配结构体大小的内存空间
IntPtr structPtr = Marshal.AllocHGlobal(size);
//将结构体拷到分配好的内存空间
Marshal.StructureToPtr(structObj, structPtr, false);
//从内存空间拷到byte数组
Marshal.Copy(structPtr, bytes, 0, size);
//释放内存空间
Marshal.FreeHGlobal(structPtr);
//返回byte数组
return bytes;
}
private void TestTcp_Load(object sender, EventArgs e)
{ }
private void button1_Click(object sender, EventArgs e)
{
int ret;
TMsgBody msgbody;
//TMsgHeadInfo msghead;
TCPClient tcp = new TCPClient();
string code = "zp";
string type = "ai";
//string body = "cc";
ret = tcp.ConnectServer("127.0.0.1", 3578);
if (ret == 0)
{
MessageBox.Show("连接服务器失败");
}
else
{
MessageBox.Show("连接服务器成功");
msgbody.msghead.MsgCode = code.ToCharArray();
msgbody.msghead.MsgType = type.ToCharArray();
msgbody.msghead.Sender = 5;
msgbody.body = 44;// 服务器端收到后,实际不是44,其他数据类型没有问题
byte[] msg = StructToBytes(msgbody);
if (tcp.SendMsg(msg) > 0)
{
MessageBox.Show("发送成功");
}
else
{
MessageBox.Show("发送失败");
}
}
}
}
}服务器端delphi代码,组件用的indy9unit Unit1;interfaceuses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, IdBaseComponent, IdComponent, IdTCPServer;type
TChar2 = array[0..1] of Char;
TMsgHead=packed record
MsgCode, MsgType: TChar2;
sender: Byte;
senderint: Integer;
end; TMsgBody=packed record
msgHead: TMsgHead;
body: Integer;
end; TForm1 = class(TForm)
IdTCPServer1: TIdTCPServer;
Button1: TButton;
Edit1: TEdit;
Edit2: TEdit;
Edit3: TEdit;
Edit4: TEdit;
procedure Button1Click(Sender: TObject);
procedure IdTCPServer1Execute(AThread: TIdPeerThread);
private
{ Private declarations }
public
{ Public declarations }
end;var
Form1: TForm1;implementation{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);
begin
IdTCPServer1.DefaultPort := 3578;
IdTCPServer1.Active := True;
end;function Min(AValueOne, AValueTwo : Integer): Integer;
begin
If AValueOne > AValueTwo then
begin
Result := AValueTwo
end //If AValueOne > AValueTwo then
else
begin
Result := AValueOne;
end; //..If AValueOne > AValueTwo then
end;function PCharToStr(ABuf: array of char; ABufLen: Integer): string;
{
将PChar(#0结尾)转换为string
}
var
LenOfStr: Integer;
begin
LenOfStr := Min(ABufLen, StrLen(ABuf));
if LenOfStr <= 0 then
begin
Result := '';
end
else
begin
SetLength(Result, LenOfStr);
Move(ABuf[0], Result[1], LenOfStr);
end;
end;procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread);
//var msgHead: TMsgHead;
var msgBody: TMsgBody;
begin
if AThread.Connection.Connected then begin
FillChar(msgBody, SizeOf(TMsgBody), 0);
AThread.Connection.ReadBuffer(msgBody, SizeOf(TMsgBody));
Edit1.Text := PCharToStr(msgBody.msgHead.MsgCode, 2);
Edit2.Text := PCharToStr(msgBody.msgHead.MsgType, 2);
Edit3.Text := IntToStr(Integer(msgBody.msgHead.sender));
Edit4.Text := IntToStr(msgBody.msgHead.senderint);
end;
end;end.C#socketStructureDelphi结构体
public byte[] StructToBytes(object obj)
{
int size = Marshal.SizeOf(obj);
byte[] bytes = new byte[size];
IntPtr structPtr = Marshal.AllocHGlobal(size); //分配结构体大小的内存空间
Marshal.StructureToPtr(obj, structPtr, false); //将结构体拷到分配好的内存空间
Marshal.Copy(structPtr, bytes, 0, size); //从内存空间拷到byte数组
Marshal.FreeHGlobal(structPtr); //释放内存空间
return bytes;
} public object BytesToStruct(byte[] bytes, Type type)
{
int size = Marshal.SizeOf(type);
if (size > bytes.Length)
return null;
IntPtr structPtr = Marshal.AllocHGlobal(size); //分配结构大小的内存空间
Marshal.Copy(bytes, 0, structPtr, size); //将byte数组拷到分配好的内存空间
object obj = Marshal.PtrToStructure(structPtr, type);
Marshal.FreeHGlobal(structPtr);
return obj;
}
然后再看看C#的结构体转成Byte里面真实的字节内容是什么两者对比就知道是什么原因了。总觉的C#的结构体转成字节后会出问题
发送前要用方法System.Net.IPAddress.HostToNetworkOrder()进行转换
使用了这个方法后,在服务器端“正常”了,但是只限于256以下的数字,如果c#发256,delphi显示0,以此类似,到了512,又显示0,513显示1
使用了这个方法后,在服务器端“正常”了,但是只限于256以下的数字,如果c#发256,delphi显示0,以此类似,到了512,又显示0,513显示1256刚好是8为二进制数字,这里,这里,是否丢掉高位的字节了?
给个建议:
1、你写一发和收的两个小程序。发送程序发送设定数据,然后在接收端调试看看你接收到的数据到底是什么样的!!!依据此分析。当然,结构体里面,你还是要用到上面的marshal类的处理。
2、接收端用DELPHI程序接收,在看看它接收的数据是什么,比较下,据此查找原因和找到解决方法。
使用了这个方法后,在服务器端“正常”了,但是只限于256以下的数字,如果c#发256,delphi显示0,以此类似,到了512,又显示0,513显示1256刚好是8为二进制数字,这里,这里,是否丢掉高位的字节了?
给个建议:
1、你写一发和收的两个小程序。发送程序发送设定数据,然后在接收端调试看看你接收到的数据到底是什么样的!!!依据此分析。当然,结构体里面,你还是要用到上面的marshal类的处理。
2、接收端用DELPHI程序接收,在看看它接收的数据是什么,比较下,据此查找原因和找到解决方法。
本身写的就是一个测试程序,代码很少,都在楼上,你所说的调试应该如何调试?
使用了这个方法后,在服务器端“正常”了,但是只限于256以下的数字,如果c#发256,delphi显示0,以此类似,到了512,又显示0,513显示1256刚好是8为二进制数字,这里,这里,是否丢掉高位的字节了?
给个建议:
1、你写一发和收的两个小程序。发送程序发送设定数据,然后在接收端调试看看你接收到的数据到底是什么样的!!!依据此分析。当然,结构体里面,你还是要用到上面的marshal类的处理。
2、接收端用DELPHI程序接收,在看看它接收的数据是什么,比较下,据此查找原因和找到解决方法。delphi处用了这个方法Edit4.Text := IntToStr(ntohl(msgBody.body));
ntohl网络顺序转主机顺序
使用了这个方法后,在服务器端“正常”了,但是只限于256以下的数字,如果c#发256,delphi显示0,以此类似,到了512,又显示0,513显示1byte类型的不用转换了,高于一个字节才需要
也不知道你的协议是不是完全遵循NetworkOrder的,不过问题很可能就出在数字存储字节序了
你最好把发送和接收到的都纪录下了,然后比对一下
//将每个字节用两位十六进制的形式输出
int i = 1234;
Console.WriteLine(string.Join(" ", BitConverter.GetBytes(i).Select(b => b.ToString("X2")).ToArray()));
Console.WriteLine(string.Join(" ", BitConverter.GetBytes(System.Net.IPAddress.HostToNetworkOrder(i)).Select(b => b.ToString("X2")).ToArray()));
使用了这个方法后,在服务器端“正常”了,但是只限于256以下的数字,如果c#发256,delphi显示0,以此类似,到了512,又显示0,513显示1byte类型的不用转换了,高于一个字节才需要
也不知道你的协议是不是完全遵循NetworkOrder的,不过问题很可能就出在数字存储字节序了
你最好把发送和接收到的都纪录下了,然后比对一下
//将每个字节用两位十六进制的形式输出
int i = 1234;
Console.WriteLine(string.Join(" ", BitConverter.GetBytes(i).Select(b => b.ToString("X2")).ToArray()));
Console.WriteLine(string.Join(" ", BitConverter.GetBytes(System.Net.IPAddress.HostToNetworkOrder(i)).Select(b => b.ToString("X2")).ToArray()));
不懂linq
msg = BitConverter.GetBytes(msgbody.body);
for (int i = 0; i < msg.Length - 1; i++)
{
x2 += msg[i].ToString("X2"); MessageBox.Show(x2);
} x2 = "";
byte[] msg2 = BitConverter.GetBytes(System.Net.IPAddress.HostToNetworkOrder(msgbody.body));
for (int i = 0; i < msg.Length - 1; i++)
{
x2 += msg2[i].ToString("X2"); MessageBox.Show(x2);
}
使用了这个方法后,在服务器端“正常”了,但是只限于256以下的数字,如果c#发256,delphi显示0,以此类似,到了512,又显示0,513显示1256刚好是8为二进制数字,这里,这里,是否丢掉高位的字节了?
给个建议:
1、你写一发和收的两个小程序。发送程序发送设定数据,然后在接收端调试看看你接收到的数据到底是什么样的!!!依据此分析。当然,结构体里面,你还是要用到上面的marshal类的处理。
2、接收端用DELPHI程序接收,在看看它接收的数据是什么,比较下,据此查找原因和找到解决方法。
本身写的就是一个测试程序,代码很少,都在楼上,你所说的调试应该如何调试?写一个测试结构体,赋值,然后收发,把收到的字节流,打印出来。通过这样调试