c# socket发送对象

shuihan20e 2014-02-10 09:51:32

[Serializable]
[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
class TMsgHeadInfo
{
public char[] MsgCode;
public char[] MsgType;
public byte SenderType;
public char[] Sender;
public byte ReceiverType;
public char[] Receiver;
public int TotalLength;
public char[] VerifyCode;

public TMsgHeadInfo()
{
MsgCode = new char[2];
MsgType = new char[2];
SenderType = 1;
Sender = new char[6];
ReceiverType = 4;
Receiver = new char[6];
TotalLength = 0;
VerifyCode = new char[32];
}
}
//02报文 单检指令报文体
[Serializable]
[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
class TDevCheck
{
public byte DevType;
public char[] DevCode;
public Int32 OutTime;

public TDevCheck()
{
DevType = 0;
DevCode = new char[10];
OutTime = 0;
}
}
//02报文
[Serializable]
[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
class TDevChecks
{
public TMsgHeadInfo MsgHead;
public TDevCheck DevCheck;

public TDevChecks()
{
MsgHead = new TMsgHeadInfo();
DevCheck = new TDevCheck();
}
}

类定义如上

public bool SendCheckDev(byte ADevType,TextBox txt)
{
TDevChecks DevChecks = new TDevChecks();
DevChecks.MsgHead.MsgCode = "02".ToCharArray();
DevChecks.MsgHead.MsgType = "00".ToCharArray();
//DevChecks.MsgHead.Receiver = "000000".ToCharArray();
DevChecks.MsgHead.ReceiverType = 4;
DevChecks.MsgHead.Sender = Global.sLocalCode.ToCharArray();
DevChecks.MsgHead.SenderType = 1;
DevChecks.MsgHead.TotalLength = 0;

DevChecks.DevCheck.DevCode = DevCode.ToCharArray();
DevChecks.DevCheck.DevType = ADevType;
DevChecks.DevCheck.OutTime = Global.nCheckOutTime;
DevChecks.MsgHead.VerifyCode = Global.tool.MD5Byte(Global.tool.GetBinaryFormatData(DevChecks.DevCheck)).ToCharArray();
//此处需要一个对报文体进行MD5加密
MemoryStream ms = new MemoryStream();
BinaryWriter bw = new BinaryWriter(ms, Encoding.GetEncoding("GB2312"));
bw.Write(DevChecks.MsgHead.MsgCode);
bw.Write(DevChecks.MsgHead.MsgType);
bw.Write(DevChecks.MsgHead.Receiver);
bw.Write(DevChecks.MsgHead.ReceiverType);
bw.Write(DevChecks.MsgHead.Sender);
bw.Write(DevChecks.MsgHead.SenderType);
bw.Write(DevChecks.MsgHead.TotalLength);
bw.Write(DevChecks.MsgHead.VerifyCode);
bw.Write(DevChecks.DevCheck.DevCode);
bw.Write(DevChecks.DevCheck.DevType);
bw.Write(DevChecks.DevCheck.OutTime);

//发送单检命令
txt.Text = "正在连接服务器....";
string sErr = "";
if (!ConnectServer(out sErr))
{
txt.Text = txt.Text + Environment.NewLine + "执行设备单检命令时,连接服务器失败:" + sErr;
return false;
}
txt.Text = txt.Text + Environment.NewLine + "开始发送单检命令....";
try
{
tcpclient.Client.Send(ms.ToArray());

}
catch (Exception ex)
{
tcpclient.Client.Disconnect(true);
txt.Text = txt.Text + Environment.NewLine + "发送单检命令时出现异常:" + ex.Message;
return false;
//throw;
}
//读取服务器回复
if (!tcpclient.Connected)
{
txt.Text = txt.Text + Environment.NewLine + "读取服务器回复信息时,网络断开:" + sErr;
return false;
}

TResponseMsgHead resp = new TResponseMsgHead();
byte[] Response = new byte[Marshal.SizeOf(resp)];

try
{
tcpclient.Client.Receive(Response, Response.Length, SocketFlags.None);

}
catch (Exception ex)
{
//tcpclient.Client.Disconnect(true);
txt.Text = txt.Text + Environment.NewLine + "读取服务器回复信息时发生异常:" + ex.Message;
return false;
//throw;
}
//校验
//成功或失败


if (((TResponseMsgHead)(Global.tool.RetrieveObject(Response))).RecResult == 0)
{
txt.Text = txt.Text + Environment.NewLine + "服务器执行指令成功,等待返回检测结果...";
}
else
{
txt.Text = txt.Text + Environment.NewLine + "服务器执行指令失败:" + ((TResponseMsgHead)(Global.tool.BytesToStruct(Response, resp.GetType()))).Description;
return false;
}
if (tcpclient.Client.Connected)
tcpclient.Client.Disconnect(true);

return true;
}

上面用到的md5算法如下

public string MD5Byte(byte[] by)
{
string pwd = "";
MD5 md5 = MD5.Create();
byte[] s = md5.ComputeHash(by);
for (int i = 0; i < s.Length; i++)
{
pwd = pwd + s[i].ToString("X");
}
return pwd;
}


发送正常,服务器能接收到,但是md5总是验证不通过,这个算法是不是不对,应该如何改呢?

接收正常,但是if (((TResponseMsgHead)(Global.tool.RetrieveObject(Response))).RecResult == 0)这一步中Global.tool.RetrieveObject(Response)提示错误

public object RetrieveObject(byte[] binaryData)
{
MemoryStream memStream = new MemoryStream(binaryData);
IFormatter brFormatter = new BinaryFormatter();
Object obj = brFormatter.Deserialize(memStream);
return obj;
}
...全文
630 21 打赏 收藏 转发到动态 举报
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
shuihan20e 2014-02-21
  • 打赏
  • 举报
回复
引用 19 楼 jiaoshiyao 的回复:
[quote=引用 17 楼 sp1234 的回复:] 没有看你的代码,太多了。随便说一两点。 至少在10年多以前,应用系统已经全面时髦起了更加通用的协议格式,例如xml、json,以及几十种类似的东西。 假如有许多终端,它们之间未必是同一个版本的实体定义。例如可能有7、8种不同的“旧”版本的实体与某服务器对话,有的版本多了几个属性、有的少了。而字符串长度不定,二进制使用base64编码,等等。但是系统完全可以非常方便地互通! 根本不是用什么无灵活性的“结构体”来承载内容。
晕啊 给个例子 具体怎么用的 我现在都是用的结构体。。。。。。。[/quote] 你遇到什么 问题了,我现在是用结构体没有问题,但是用对象不行
shuihan20e 2014-02-21
  • 打赏
  • 举报
回复
引用 18 楼 sp1234 的回复:
如果从根源上,你学习比较高级的软件设计知识,而不是15年前ms c6.0入门课程,那么也许进步更快。
现在是维护的老系统,我也想用新的东西,但是现在时间不允许那样,感谢您的建议,我会考虑用新的技术
jiaoshiyao 2014-02-20
  • 打赏
  • 举报
回复
引用 17 楼 sp1234 的回复:
没有看你的代码,太多了。随便说一两点。 至少在10年多以前,应用系统已经全面时髦起了更加通用的协议格式,例如xml、json,以及几十种类似的东西。 假如有许多终端,它们之间未必是同一个版本的实体定义。例如可能有7、8种不同的“旧”版本的实体与某服务器对话,有的版本多了几个属性、有的少了。而字符串长度不定,二进制使用base64编码,等等。但是系统完全可以非常方便地互通! 根本不是用什么无灵活性的“结构体”来承载内容。
晕啊 给个例子 具体怎么用的 我现在都是用的结构体。。。。。。。
  • 打赏
  • 举报
回复
如果从根源上,你学习比较高级的软件设计知识,而不是15年前ms c6.0入门课程,那么也许进步更快。
  • 打赏
  • 举报
回复
没有看你的代码,太多了。随便说一两点。 至少在10年多以前,应用系统已经全面时髦起了更加通用的协议格式,例如xml、json,以及几十种类似的东西。 假如有许多终端,它们之间未必是同一个版本的实体定义。例如可能有7、8种不同的“旧”版本的实体与某服务器对话,有的版本多了几个属性、有的少了。而字符串长度不定,二进制使用base64编码,等等。但是系统完全可以非常方便地互通! 根本不是用什么无灵活性的“结构体”来承载内容。
本拉灯 2014-02-19
  • 打赏
  • 举报
回复
引用 11 楼 shuihan20e 的回复:
[quote=引用 10 楼 wyd1520 的回复:] 你返序列化后的对像,是同引用同一个DLL么。。。
?什么意思[/quote] 就是你发送前不是有把new xxx后的对象进行序列化么,这个new xxx的对像是在某个DLL里 然后你把序列化后的值发给另一端,这个另一端引用的是不是相同的这这个DLL就是说 两个端所引用的DLL是一样的
shuihan20e 2014-02-19
  • 打赏
  • 举报
回复
引用 10 楼 wyd1520 的回复:
你返序列化后的对像,是同引用同一个DLL么。。。
?什么意思
本拉灯 2014-02-19
  • 打赏
  • 举报
回复
你返序列化后的对像,是同引用同一个DLL么。。。
shuihan20e 2014-02-19
  • 打赏
  • 举报
回复
引用 8 楼 rtdb 的回复:
这里有错,输出格式得是X2: public string MD5Byte(byte[] by) { pwd = pwd + s[i].ToString("X2"); }
这个问题已解决,请回答上面关于对象的问题吧
本拉灯 2014-02-19
  • 打赏
  • 举报
回复
还有C#没有C++那种概念,什么对像大小,
本拉灯 2014-02-19
  • 打赏
  • 举报
回复
引用 14 楼 shuihan20e 的回复:
[quote=引用 12 楼 wyd1520 的回复:] [quote=引用 11 楼 shuihan20e 的回复:] [quote=引用 10 楼 wyd1520 的回复:] 你返序列化后的对像,是同引用同一个DLL么。。。
?什么意思[/quote] 就是你发送前不是有把new xxx后的对象进行序列化么,这个new xxx的对像是在某个DLL里 然后你把序列化后的值发给另一端,这个另一端引用的是不是相同的这这个DLL就是说 两个端所引用的DLL是一样的[/quote] 另外,C#中是不是无法取得对象的大小啊[/quote] 对像序列化后 要返序例化回来引用的DLL对像要同一个DLL才行。包括命名空间,类名
shuihan20e 2014-02-19
  • 打赏
  • 举报
回复
引用 12 楼 wyd1520 的回复:
[quote=引用 11 楼 shuihan20e 的回复:] [quote=引用 10 楼 wyd1520 的回复:] 你返序列化后的对像,是同引用同一个DLL么。。。
?什么意思[/quote] 就是你发送前不是有把new xxx后的对象进行序列化么,这个new xxx的对像是在某个DLL里 然后你把序列化后的值发给另一端,这个另一端引用的是不是相同的这这个DLL就是说 两个端所引用的DLL是一样的[/quote] 另外,C#中是不是无法取得对象的大小啊
shuihan20e 2014-02-19
  • 打赏
  • 举报
回复
引用 12 楼 wyd1520 的回复:
[quote=引用 11 楼 shuihan20e 的回复:] [quote=引用 10 楼 wyd1520 的回复:] 你返序列化后的对像,是同引用同一个DLL么。。。
?什么意思[/quote] 就是你发送前不是有把new xxx后的对象进行序列化么,这个new xxx的对像是在某个DLL里 然后你把序列化后的值发给另一端,这个另一端引用的是不是相同的这这个DLL就是说 两个端所引用的DLL是一样的[/quote] 一端是VC做的,另一端是C#做的,C#发的时候,序列化对象,发出,VC端接收显示都没有问题,VC回复时,C#端接收到数据后,按结构体来解析是没有问题的,但是按对象来解析就会出错,提示“输入流是无效的二进制格式。开始内容(以字节为单位)是:” 你所说的放到DLL类库里,我也发现有人提到了 http://bbs.csdn.net/topics/310155028#r_79565590 我这那样做了,但是还是提示上面的错误 序列化与反序列化的代码如下

        public static byte[] GetBinaryFormatData(object msg)
        {
            byte[] binaryDataResult = null;
            MemoryStream memStream = new MemoryStream();
            IFormatter brFormatter = new BinaryFormatter();
            brFormatter.Serialize(memStream, msg);
            binaryDataResult = memStream.ToArray();
            memStream.Close();
            memStream.Dispose();
            return binaryDataResult;
        }

        public static object RetrieveObject(byte[] binaryData)
        {
            MemoryStream memStream = new MemoryStream(binaryData);
            IFormatter brFormatter = new BinaryFormatter();
            Object obj = brFormatter.Deserialize(memStream);
            return obj;
        }
网上找的,其他人提供的和这段代码大同小异,另外,用C#发结构时,如果结构体里有汉字,就会有错误,需要将编码改成UNICODE,但是接收到的如果用UNICODE就会有乱码,我想应该另一端的程序没用UNICODE吧
rtdb 2014-02-18
  • 打赏
  • 举报
回复
这里有错,输出格式得是X2: public string MD5Byte(byte[] by) { pwd = pwd + s[i].ToString("X2"); }
shuihan20e 2014-02-18
  • 打赏
  • 举报
回复
引用 5 楼 feiyun0112 的回复:
我的意思是你先确认发送和接收到的byte数组是一致的,先不考虑序列化、反序列化的问题
版主
shuihan20e 2014-02-10
  • 打赏
  • 举报
回复
引用 5 楼 feiyun0112 的回复:
我的意思是你先确认发送和接收到的byte数组是一致的,先不考虑序列化、反序列化的问题
不大明白您的意思,服务器回复的信息应该是没有问题的,我用结构体来接收,解析出来完全正确


    //报文头
    [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    struct TMsgHeadInfo
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
        public char[] MsgCode;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
        public char[] MsgType; public byte SenderType;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
        public char[] Sender; public byte ReceiverType;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
        public char[] Receiver; public int TotalLength;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
        public char[] VerifyCode;
    }
    //01 报文  设备基本信息
    [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    struct TDevInfo
    {
        public byte DevType;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
        public char[] DevCode;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)]
        public char[] CheckTime;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
        public char[] ErrorStr;
        public Int32 CheckError;
    }
    //02报文 单检指令报文体
    [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    struct TDevCheck
    {
        public byte DevType;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
        public char[] DevCode;
        public Int32 OutTime;
    }
    //02报文
    [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    struct TDevChecks
    {
        public TMsgHeadInfo MsgHead;
        public TDevCheck DevCheck;
    }
接收代码如下
            TResponseMsgHead resp;
            resp.MsgHead.MsgCode = "00".ToCharArray();
            resp.MsgHead.MsgType = "00".ToCharArray();
            resp.MsgHead.Receiver = "000000".ToCharArray();
            resp.MsgHead.ReceiverType = 1;
            resp.MsgHead.Sender = "000000".ToCharArray();
            resp.MsgHead.SenderType = 2;
            resp.MsgHead.TotalLength = 0;
            resp.MsgHead.VerifyCode = new char[32];
            resp.RecResult = 1;
            resp.Description = new char[128];

            byte[] Response = Global.tool.StructToBytes(resp);
            try
            {
                tcpclient.Client.Receive(Response, Response.Length, SocketFlags.None);
                Application.DoEvents();
                //tcpclient.Client.Receive(Response, Response.Length, SocketFlags.None);
            }
            catch (Exception ex)
            {
                //tcpclient.Client.Disconnect(true);
                txt.Text = txt.Text + Environment.NewLine + "读取服务器回复信息时发生异常:" + ex.Message;
                //throw;
            }

            ;
            if (((MTWS.Net.TResponseMsgHead)(Global.tool.BytesToStruct(Response, resp.GetType()))).RecResult==0)
            {
                txt.Text = txt.Text + Environment.NewLine + "服务器执行指令成功,等待返回检测结果...";
            }
            else
            {
                txt.Text = txt.Text + Environment.NewLine + "服务器执行指令失败:" + new string(((MTWS.Net.TResponseMsgHead)(Global.tool.BytesToStruct(Response, resp.GetType()))).Description);
            }
feiyun0112 2014-02-10
  • 打赏
  • 举报
回复
我的意思是你先确认发送和接收到的byte数组是一致的,先不考虑序列化、反序列化的问题
shuihan20e 2014-02-10
  • 打赏
  • 举报
回复
引用 1 楼 feiyun0112 的回复:
把发送和接收的byte数组存到2个文件,比较是否一致 ***************************************************************************** 签名档: http://feiyun0112.cnblogs.com/
高手,我描述一下我的需求吧 发送给服务器一个包,服务器处理完成后,发送回复消息,我用socket接收,想用对象来处理,声明一个对象,将其转为byte[],作为tcpclient.receive的一个参数,然后再将其转换为对象 另,我上面的md5 byte[]应该怎么改?
shuihan20e 2014-02-10
  • 打赏
  • 举报
回复
引用 1 楼 feiyun0112 的回复:
把发送和接收的byte数组存到2个文件,比较是否一致 ***************************************************************************** 签名档: http://feiyun0112.cnblogs.com/
RetrieveObject提示如下错误: 未处理的“System.Runtime.Serialization.SerializationException”类型的异常出现在 mscorlib.dll 中。 其他信息: 输入流是无效的二进制格式。开始内容(以字节为单位)是: 39-39-30-31-00-38-30-33-30-30-01-00-00-00-00-00-00... 另外Marshal.SizeOf(resp)得到的值并不是对象实际的大小
feiyun0112 2014-02-10
  • 打赏
  • 举报
回复
把发送和接收的byte数组存到2个文件,比较是否一致

*****************************************************************************
签名档: http://feiyun0112.cnblogs.com/

110,538

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧