我爱builder

C++Builder 程序员博客

  StreamSend->Write("nihaoma",7);
  StreamSend->Write("1234567",7);
能得到nihaoma1234567来,如果这样
  StreamSend->Write("nihaoma",7);
  DWORD i=htonl(12.5);
  StreamSend->Write(&i,sizeof(DWORD));
  StreamSend->Write("1234567",7);
只能read出nihaoma,为什么??

BCB 问题

我在BCB中看见有一个这样的定义
static const Shortint faDirectory = 0×10;
不是很明白什么意思。尤其是0×10是什么类型?


那也就是说十六进制的10等于十进制的16了。那为什么前面还要加一个"0x"这个是用来干什么?填位?还是做什么呢?

前缀0x是C/C++中表示十六进制的数据。


明白了
谢谢!

存取INI文件 时如果字段值是汉字,显示的乱码,请问怎么办?
程序中我想读取INI文件中的一个字段值,作为Lable的Caption?如果字段值是汉字则显示乱码,请教高手

解决了,原来是我用记事本写的INI文件,在保存编码时没有选择Unicode,所以有乱码,不过还是谢谢!受教了

我定义了一个结构体
struct  GMMessage
  {
  int    MsPGID;
  int GMemberID[50];
  int GMemberCount;     
  };

在发送端的语句是:
GMMessage *GMember = new GMMessage();

…  //给GMember的成员赋值
ClientSocket1->Socket->SendBuf(GMember,sizeof(GMember));

请问在接收端应该用怎样的语句才能接收到这个数据,并读取出原来的GMember的各个成员变量的值?

应该可以的。通过分析数据。来做比较好噢

能不能给段接收端实现接收的具体代码呀?十分感谢~

该回复于2008-07-03 18:33:52被版主删除

那可以这么定义
struct Info1{
    …
};
struct Info2{
    …
};
struct GMMessage{
    BYTE Type;
    union{
        Info1 info1;
        Info2 info2;
    }
};

收到数据 更具Type的值.把Type后面的数据做强制转换赋值给相应类型的指针做处理;

假设 ServerSocket 端 收到数据 Socket->RecvBuffer(buf,Socket->ReceiveLength());

Info1 *p1;
Info2 *p2;
BYTE * pType = buf;
switch(*pType)
{
case X:
    p1 = (Info1 *)(pType ++);
    break;
case Y:
    p2 = (Info2 *)(pType ++);
    break;
}

p1 p2 就是数据的指针.

BYTE * pType = (BYTE*)buf; 这里也需要做下强制转换.

学习 。。

定义一个char变量也可以,但是我觉得最好是定义一个枚举类型的变量~!
根据是什么类型的数据,就做响应的处理
用一个switch语句来判断,先把你的数据包头取出来,判断是不是你要的数据、是哪种数据
然后对数据进行分析
GMMessage *GMemberRev = new GMMessage();
ServerSocket1->Socket->receiveBuf( GMemberRev , sizeof( GMMessage  ) );
当然端口、Ip那些要设置好了~!

为什么我收到的xml文件有乱码?
如下xml文件中ErrorMessage字段

=======================
代码如下:
    //接收
    err = SSL_read(ssl, buff, sizeof(buff) - 1);
    CHK_SSL(err);
    buff[err] = '\0';
    p = buff;
    printf("resv chars:\n%s\n", p);  //打印xml文件

    _di_IXMLDocument xml = NewXMLDocument();  //WideString  ,AnsiString
    xml->LoadFromXML((WideString)p);  /*从一个xml字串导入,也可用LoadFromFile从文件导入,其他用法看帮助吧*/

    _di_IXMLNode root = xml->DocumentElement;  /*XML根节点*/
    if(root->HasChildNodes)      /*是否有子节点*/
    {
      _di_IXMLNode  item;
      _di_IXMLNodeList list = root->ChildNodes;
      item = list->FindNode(WideString("Message"));  /*查找子节点*/
      root = item;
      list = root->ChildNodes;
      item = list->FindNode(WideString("ErrorCode"));
      if(item &&!item->Text.IsEmpty())
      {
        String strT = item->Text;
      }
      item = list->FindNode(WideString("ErrorMessage"));
      if(item &&!item->Text.IsEmpty())
      {
        String strT = item->Text;
      }
    }

=======================
打印出来的XML文件如下:
<?xml version="1.0" encoding="GB2312"?>
<LPMS_EKA>
  <Message>
    <ErrorCode>10 </ErrorCode>
    <ErrorMessage>浣欓涓嶈冻 </ErrorMessage>
  </Message>
  <Response>
    <PointsLeft>1000 </PointsLeft>
    <STNumber>1-10343611 </STNumber>
    <PointsRedemed>0 </PointsRedemed>
  </Response>
</LPMS_EKA>

是的!

字符编码问题

我一个pagecontrol ,子页里面已经已经有很多控件,比如按纽什么的,确实存在,在头文件里找到对象,但是DFM文件里没找到。对象树也没找到,但是不能显示?怎么办?

不能显示!就是可视不能显示!

>>>可视不能显示

听起来好难理解。

看头文件这些控件的声明放在那儿,只有在__Publish那的才能显示,其他都是动态创建的,而__Publish下的是由自动添加的。

编译没问题??

DFM中没有肯定是显示不出来了,

主要是控件加载问题

应该不是控件的问题

看了半天,没明白….
再看一遍先.

奇怪的问题。

(1)控件没放在PAGE上?
(2)控件Visible=false?
(3)控件放在另外一容器上,而该容器Visible=false?
(4)在Form上右单击右键,View as Text,看看控件的定义还有没?
(5)对象察看器中能否列出该控件?
….

我一个pagecontrol ,子页里面已经已经有很多控件,比如按纽什么的,确实存在,

这里的‘确实存在’是指什么?

式published下面有他们的声明?

后面的dfm文件找不到?

你把Form窗体重新设计个看看,

引用 10 楼 program2050 的回复:
奇怪的问题。

把控件重新放上去试试

删除它,重新放,就行了!

我估计是你那一页的TabVisible(注意不是Visible)设置成false了,你可以查找TabSheet对象,然后查看其属性。
以前碰到过类似的问题

个人认为16楼应该说对了,继续关注

这个问题找到,是控件问题!找不到,所有声明被忽略了!

强调一下是代码加密,不是软件加密。
首先,说下为什么需要这个,上次外出调试,期间WC了一下,结果客户趁机偷偷的将我的源代码拷贝到了自己的U盘上,后来无意中发现了,要都要不回来。为了以后不出现这种事,也不伤了客户的和气,请问各位有没有什么解决方法或措施?
之前有人说过用rar压缩加密,好像不是很好。解压后也是暴露出来的。
另外问一下bcb有没有什么类似的插件辅助加密的?谢谢!
方法不限,希望大家各抒己见。谢谢!

老大,人不在的时候怎么保证,而且计算机是别人的,这个是现场调试哦,哎

现场调试?
要那样的话,把代码关键部分都用lib dll什么的来做。只调试有问题地方的代码

要不干脆去两个人得了。

现场调试难道带的不是自己的电脑?如果是自己的电脑为什么不锁屏?

人在电脑在,人不在电脑锁。
Win + L才是王道。

出差的时候,我的设置是一分钟进入屏保,起身之后稍稍消磨一会,电脑就进入保护状态。

现场调试,用的工控机,需要在主板上插采集卡,我就算带了本本也不可能插采集卡,所以用的是别人的电脑,哎
还有什么好的建议没?谢谢了,呵呵

另外就是,出差的时候,即便要访问网络资源,也是通过工具来进行主动性的资料传送,或者要求对方提供访问权限,尽量不主动提供访问权限给别人。

僵哥最后的话有点不太明白哦?能说全一点么?或者举例?谢谢!

不要把源码都放在一个目录中.

引用 7 楼 touyunnaozhang 的回复:
现场调试,用的工控机,需要在主板上插采集卡,我就算带了本本也不可能插采集卡,所以用的是别人的电脑,哎
还有什么好的建议没?谢谢了,呵呵

Remote Debug.

源代码只要复制到客户的机器上(包括调试的那台),即使事后删除了这些源码,客户仍然有90%的机会可以找回这些文件。除非粉碎一下。

僵哥的意思我明白了,就是要我远程调试啊,问题是好多实验室不能上网的……
妖哥的建议确实我当时疏忽了,以前都是直接删除的没粉碎,客户要恢复,估计能找到,还好好多客户不聪明,汗啊,以后注意!

引用 13 楼 touyunnaozhang 的回复:
僵哥的意思我明白了,就是要我远程调试啊,问题是好多实验室不能上网的……
妖哥的建议确实我当时疏忽了,以前都是直接删除的没粉碎,客户要恢复,估计能找到,还好好多客户不聪明,汗啊,以后注意!

你不是已经带了电脑过去了吗?把你的电脑连接到客户的机器不就好了?

明白,就将客户端的数据采集过来然后转给我,那就需要在客户端做一个采集转发的程序,是吧?方法可行就是有点麻烦,呵呵!

以上的各位意见让我的思路开阔了很多,还有更好更新颖的思路么?奇怪的也行呵呵!

出差的时候,我的设置是一分钟进入屏保,起身之后稍稍消磨一会,电脑就进入保护状态。

写些别人看不懂的代码..
把自己的文件全部隐藏起来,

代码在u盘里或者移动硬盘中调试,人离开,就拔掉,或者u盘、移动硬盘加密。

我看你不如做个加解密程序:
  自己要用时运行你的加解密程序解密你的代码到内存文件中,保存时再从内存中加密到磁盘中。就算被COPY了也是加过密的文件,打不开;而已加密的文件是在内存中,只要不是那种永久性内存,你说,还用进行文件粉碎吗?

两种方案:
(1)用移动硬盘或大U盘,随身带,最简单了.
(2)用PGP软件加密
以前我们经常用pg8.1,现在应该有更新的版本了吧.
这个软件可以建立一个加密文件,你所有的资料可以保存在其中,需要
时候由PGP加载这个文件,输入密码,它就变为一个虚拟的硬盘,你可以
像本地硬盘一样使用它们,由于所有的文件保存在这个虚拟盘上,不用担心
资料的安全.调试完后,把这个文件拷回去就行了.
虽然客户也能拷走这个文件,但没有密码和证书,是无法解开的,据说军方
的加密用的就有这个系统.

呵呵,一夜之间,多了这么多建议,很不错啊,感谢大家!
楼上的那位说的PGP软件似乎很不错,我去搜搜看,谢谢了!

客户也窃取源码?

:-)

看来要多留心啦

to geochway:
  我找了半天找到的都是关于PGP的教程,软件还没找到,麻烦你发一个过来吧,要免费的(破解),如果顺带发一下你那个版本的教程,就更好了,呵呵,谢谢!
  plyx300@sohu.com
 

通常我只把EXE文件给对方,调试都是在自己的电脑中完成的,关键是程序编写完了,要仔细查看代码,确实代码无误;至于在对方机器上试验程序,那只能自己小心点了,或象我以前的程序把HPP文件都改写了,或用自己的HPP文件,对方拿到了也不明白这些代码的具体含义,就象WMP组件,我用的是FULLSCREEN=3来实现全屏,就是告诉对方,他也不明白是如何得到的,因为我改动了WMP的HPP文件

楼上的,呵呵,我调试的地方和工作地点很远,去一次差不多要一天的时间,好多东西没有真实的板卡采集信息是不可能调试的,所以调试的过程中是必须改代码的,呵呵。至于你说修改HPP文件,到还不错,呵呵,可以试试。
另:HPP文件好像是delphi写的吧,呵呵,那个东西我的熟练度还不够,惭愧啊!

推荐一下这个帖子,呵呵。

呵呵,如果以后自己碰到了 也可以解决下的哦 ,呵呵

刚开会回来,呵呵,帖子受到妖哥老大的推荐,荣幸啊,哈哈

现场调试带自己的电脑,锁屏。其它好像没有办法。

1、远程调试
2、自己写个加密软件,多代码加密
3、禁止使用U盘
4、禁止使用网络

5、代码多用不容易找到和不容易安装的控件

关键的地方最好做成dll

把代码存储在U盘里,工作时插上,其他时间拿下,可要小心U盘丢失或损坏。

C++代码量不大,可以将输出(.obj等)均指向磁盘。

周末上不了,早上来公司又掉线,现在终于能上网了。呵呵大家都很积极啊,U盘存代码我以前也常用,但是U盘很慢啊,大一点的工程编译起来就很费时间了,呵呵。
31楼的兄弟你什么都禁止了,代码如何拷贝到调试的机器上?呵呵!

场调试?
要那样的话,把代码关键部分都用lib dll什么的来做。只调试有问题地方的代码

要不干脆去两个人得了。

  程序写好了,也就参数不一样吧。把参数写到一个文件,然后调试的时候改文件。

引用 35 楼 xinghongyang 的回复:
场调试?
要那样的话,把代码关键部分都用lib dll什么的来做。只调试有问题地方的代码

要不干脆去两个人得了。


两个人去和一个人去,成本是完全不一样的。

用個U盤就好了,將編譯的中間文件及結果文件放在本地硬盤上,編譯速度並不慢。

做lib或dll只能分開模塊,當你不知道哪個模塊出問題時,調試時還是得要全部源碼。
如果知道問題出在哪個模塊,用LIB與DLL可以只調試某一模塊,從而保護其他代碼。

另一種辦法是做偵錯模式,偵錯模式中開啟log日志,龐大的日志中記錄了所有的內容,讓用戶開啟偵錯模式來運行,然後將日志傳回分析。一般情況下根本就不用做現場調試。

这么多保护源码的方法,都有一些作用。不过值得提醒的是,用软件加密容易丢失文件,一旦你的加密软件出现问题可能导致你被加密的文件再也打不开。

提醒各位对源码有保护意识的朋友,在想着保护源码不被他人拷贝的同时,也要保证源码能够给自己正常使用,避免出现意外而使源码被破坏(一旦自己都用不了了,带来的损失恐怕不比被他人拷贝小)。

伤和气怎么地?? 难道不改伤和气??

感觉只有磨时间,设个1分钟屏保,想出去的时候先磨会时间,到屏保时间再出去。。。。

也有这样的透明加密软件,好像"铁卷"就是
安装之后,把cpp h hpp加密, 指定CPP和.h,.hpp只能由CB打开.
别人如果复制, 都是加密的, 你自己用的都是临时解密后的.

to PPower:
    兄弟,没想到你也来我的帖子逛逛了,呵呵,昨天没上班,在外面跑了一天,累哦。
to cczlp:
    你说的这个东西感觉也不错哦,我找找啊。呵呵

看来以后要注意这些了,我一般是离开久一点就锁屏

昨天朋友给我一个帖,感觉和这个也有点联系,贴出来给大家分享下!

晕,竟然没贴上,重发下,看来对这个插入链接不太会用,老土了……
http://bbs.pediy.com/showthread.php?t=66743

代码放移动硬盘里,人走把硬盘带身上。。快向你老总申请经费买移动硬盘吧。。。

需要2个人,保证每秒钟都至少有一个人是在电脑旁的

人在电脑在,人不在电脑锁。

哈哈,楼主还是没得经验。我的代码从来不怕他们拷贝。写代码尽量保证复杂,即使他们拿到也看不懂,复杂但结构一定要好,复杂只是在调用过程中。尽量用些多线程,做一份带注释的 自己用 一份不带注释的,外出用。
另外就是编程技巧的应用,编程技巧上用好了,细微之处才显真功夫。我读研学习期间,把自己代码给了同事,给他讲了好几遍结构,结果过了一年我回去时,他突然问我一个小问题,一个开关变量他没看懂,我为了避免线程访问数据冲突,设了一个变量进行访问的切换,就这一点 搞得他等了一年!!

楼主一定要写得多一点啊

关注!

我的电脑一般都是不会锁的,锁了感觉也没有什么。

此贴要顶  此贴要顶

大家顶起来

呵呵早上来一看,竟然发现帖子又有好多人回复,昨天看没什么回复率,还在考虑是否结贴呢,但是又怕结贴后好多人想看的却看不到,所以又忍了一天。希望有奇妙想法的人,踊跃回复哦,我再继续找方法。

关注下,,,,

引用 5 楼 ccrun 的回复:
人在电脑在,人不在电脑锁。
Win + L才是王道。

这个不错

不过,话说回来了,你写的那点破代码有什么技术含量,还保护什么?有技术含量的让他看又怎么着,他能懂里面的意思?
更何况,你用的架构,个人开发习惯,别人懒的要

引用 5 楼 ccrun 的回复:
人在电脑在,人不在电脑锁。
Win + L才是王道。

up

看情况把 我觉得
要源代码的客户毕竟少 如果想要何不和你说 还偷偷摸摸的拷贝 不厚道

关注,学习!

关注!要保护好自己的电脑

人在电脑在,人不在电脑锁。

管好自己的计算机就好了,呵呵

可以用那种加密狗,就想u盘一样,插上的时候,才能把你的模块,显示成正常的字符,负责就是乱码

关组

只能管好自己的计算机

代码很重要,保管是关键,感觉只能靠人来处理。

呵呵,实在不行少用成型函数,所有代码全部放在主程序下面,不怕代码太长
其实一般的客户不至于这样的,即便对方这样做(或不这样做),他下次也不会再因为同一样程序找你,而他出去卖这个程序的可能性不太大,多数可能也是一种爱好,想看看你是如何写的,也有可能想自己维护省点钱:(

我们以前做现场开发,也是在客户的工控机上,所有的东西都在客户机器上,只是不定期地往自己公司备份一下

该回复于2008-07-02 18:15:41被版主删除

我觉得吧,刚去的时候可以在聊天这余让客户们知道拷贝别人的代码有多么严重,再些例子来吓唬一下。

把代码关键部分做成dll即可。

引用 50 楼 wq_quake 的回复:
哈哈,楼主还是没得经验。我的代码从来不怕他们拷贝。写代码尽量保证复杂,即使他们拿到也看不懂,复杂但结构一定要好,复杂只是在调用过程中。尽量用些多线程,做一份带注释的 自己用 一份不带注释的,外出用。
另外就是编程技巧的应用,编程技巧上用好了,细微之处才显真功夫。我读研学习期间,把自己代码给了同事,给他讲了好几遍结构,结果过了一年我回去时,他突然问我一个小问题,一个开关变量他没看懂,我为了避免线程访…

同意一下
一般开发的软件,因为是不同的团队,有不同的开发思路
如果没有开发文档,估计研究也要好一段时间吧
拷了源码应该没什么用

不知道你的客户水平到什么程度,有空的时候试他一下

关注下。。。。。。

该回复于2008-07-02 18:16:25被版主删除

我想还是自己小心点为好

pgp是没有免费的了. 而且这东西还挺贵.
gnupg是个开源的PGP的说, 不过, 这东西是命令行的, 可能有界面的但没见过.

不过, 关于加密盘有个更好的选择的说.
TrueCrypt 开源,免费. 一切都很完美, 建议楼主考虑.
www.truecrypt.org

引用 66 楼 hurry281 的回复:
可以用那种加密狗,就想u盘一样,插上的时候,才能把你的模块,显示成正常的字符,负责就是乱码

对移动硬盘或大U盘进行加密。

代码加密有可能对源代码造成破坏的,毕竟代码加密方面还有很多不足。

关键代码放在网络上,给客户调试的时候从网络上读取代码。
不知道这样行不行。

这两天有点事要处理,而且是周末没时间来,今天上来发现一下子多了好多回复哦,大家都挺热情的哦!谢谢了!
to coolstar14:
  谢谢你的建议,我去看看啊!呵呵!

赞同一下win+L是最节约成本的方法
我们公司也存在这个问题,源代码能直接看到,现在也开始转成用可编译的重写.安全很多
关注20楼的方法,有意思.

另外帖子刚加到200分了,现在已经是85楼了,看来有希望突破100楼哦!呵呵!

刚试了下,TrueCrypt 是个不错的东西,很好用,也很简单。我给大家推荐下!

人在电脑在,人不在电脑锁。

经一事,长一智

顶一下,突破90楼,这两天怎么没人了?如果没人的话,100楼就结贴了!

ddddddddddddddddddd

楼主结帖时注意一下,这个帖子里有太多的人灌水,灌水的回复就不要给分了,不然回头我还得处理。

楼上的好心肠啊

行,我会着情考虑的,不会淹没了那些有功劳的人的,特殊情况我会另外开贴给分的。

行,我会着情考虑的,不会淹没了那些有功劳的人的,特殊情况我会另外开贴给分的。

直接休眠吧。真的,其实你搞太多,则可能漏洞更多。
本子的话,直接合机好了。

安全不一定要加密

技术上永远不能完美解决,需要的是一个合理的行为,比如两个人。

引用 50 楼 wq_quake 的回复:
哈哈,楼主还是没得经验。我的代码从来不怕他们拷贝。写代码尽量保证复杂,即使他们拿到也看不懂,复杂但结构一定要好,复杂只是在调用过程中。尽量用些多线程,做一份带注释的 自己用 一份不带注释的,外出用。
另外就是编程技巧的应用,编程技巧上用好了,细微之处才显真功夫。我读研学习期间,把自己代码给了同事,给他讲了好几遍结构,结果过了一年我回去时,他突然问我一个小问题,一个开关变量他没看懂,我为了避免线程访…

我赞成这种做法

TrueCrypt这个东西怎么用啊?有不有说明啊?

TrueCrypt支持各国语言,有汉化包,你把它汉化了就知道怎么用了,还有如果还不会你可以直接搜索教程,这个东西有教程的,网上很多。
好了,100楼了要结贴了!

帖子结完,按照信息的可用信程度分别给了20,10,8,5,3,1分,纯粹灌水没分!有意见的可以提!呵呵!

我从来不担心自己的代码泄漏,因为现在用的架构都是通过代码+数据库动态产生,即使他拿去了也很难看懂。别人买了我的系统后要源代码的到现在都不敢改。

最核心的东西全部写成控件,而且几乎没有注释,控件的保密性就不用说了吧,出去的电脑上根本就没有源代码。

后台核心部分用存储过程,提交的时候删除所有注释,让他们慢慢看吧。曾经出现过加密存储过程被破打开的情况,但是对方打印出来发现A4纸横向有40多爷,没有注释,不得不放弃。

不过,简单保密最好:

1、全部用自己的设备,不允许对方访问自己的电脑
2、传给对方电脑上的都是EXE、OBJ、DCU等文件,最多HPP文件
3、电脑要保证物理安全,否则没戏,艳照门就是这样的例子

Form1->Image1->Left=10;这样后线程就挂掉了,不知怎么回事?请指教。
我把这句放在Synchronize也是不行

是按上面的方法做的,一执行到Synchronize(UpdateImage);
就没动静了,程序挂掉了。

楼上的是正规做法。

谢谢ccrun (妖哥)的回答,我又试了下。
void __fastcall TTestThread::UpdateImage()
{
    Form1->Image1->Left = 10;
}
这样可以。
我是这样做的
void __fastcall TTestThread::UpdateImage(void)
{
    Form1->Image1->Left = 10;
}
加了个void,这样不行,不知道什么问题?

用于线程同步的函数是不能有任何参数的,void算是一个参数,当然,也可能VCL没有处理好这种情况

想用ADOQuery1检查ACCESS表的存在,然后drop。使用"SELECT count(*) FROM MSysObjects WHERE name = 'MyTab'",该语句在ACCESS2007内可执行,但在CB2007内出错:“不能读取记录,在MSysObjects上没有读取数据的权限。”,现问:
1、我的ADOConnection1->ConnectionString为"Provider=Microsoft.Jet.OLEDB.4.0;Jet OLEDB:Database Password=123;Data Source=d:\MyDBF.mdb",应怎样改?
2、有别的办法用SQL来先检查表的存在,后DROP吗?

基于TCP/IP的报文通讯,具体为异步长连接方式
通讯协议格式如下:

报文字段   类型与长度         字段说明
length   DWORD         包的总长度,为包控制信息和实际传送内容长度之和
factory   BYTE                 厂商编码
morePkt   BYTE                 是否还有后续包,’1’有,’0’无
cmdId   CHAR[10]         命令字,长度为10的数字串,必须10位,右补\0
recordSep  CHAR[2]         ” ~”。
datastr    CHAR[不定长]          数据内容

报文为string
假设 length=34
      factory=10
      morepkt=0
      cmdid=1234
      recordsep=” ~”
      datastr=”123456789“
请问怎样组织这个报文呢?请大家不吝赐教

请教楼上的:
datastr    CHAR[不定长]怎样定义呢?好象bcb里不能这样定义吧CHAR[] datastr , 定义成一个CHAR的指针呢还是定义成string?
我用的是tclientsocket控件,用它怎样发送这个结构呢? 
如果应答报文不是结构体,我怎样去解析报文呢?比如报文长度是四个字节。应该怎样取这四个字节呢?

谢谢您,我刚做通讯,希望你别介意。

这样的结构顶多算是报文的数据体。报文起码要有特定的报文头,报文长度,报文结束位。
还有帧校验位,控制位、标志位等等。

我想楼主所说的报文应该是应用层的通信协议而不是报文交换方式里的报文吧:-)
对于最后那个不定长的CHAR,你可以看我上面给出的结构体最后一个成员CHAR szData[1]; 它的作用是让szData紧跟在结构体之后,尽管定义成szData[1],但它不是只是放一位,我后面写的代码里演示了往里放"123456789"的方法。
这种设计方法在Windows编程里会见到,是MS先用的,可以放心了吧:-)

引用 4 楼 Waiting4you 的回复:
我想楼主所说的报文应该是应用层的通信协议而不是报文交换方式里的报文吧:-)
对于最后那个不定长的CHAR,你可以看我上面给出的结构体最后一个成员CHAR szData[1]; 它的作用是让szData紧跟在结构体之后,尽管定义成szData[1],但它不是只是放一位,我后面写的代码里演示了往里放"123456789"的方法。
这种设计方法在Windows编程里会见到,是MS先用的,可以放心了吧:-)

^_^

请教,下面用#c写的组包和发送程序
它是先把每一个类的函数成员转化成字节数组存到一个字节可变字节数组里,然后就直接sendmessagebyte了。如果按你方法我直接用个结构来存放数据,把数据写入后我能直接发送结构体?用socket那个发送命令?而且我感觉那样整个结构体解析出来长度对不上。所以我还是打算用它这个办法,还是定义个类或结构体,然后把函数成员写如后组包,但我应该组成个字节数组包呢还是字符串包?如果组成字节包用socket哪个命令发送呢?请帮帮忙。压力大,在试用期啊。
我现在是定义了个类,函数成员就是下面这些,然后用_length=42+类->DataTrans.Length();memcp(result,&_length,4);
我本意是拷贝&_length 到result中,memcp(result+6,&CmdId,10);这是把CmdId拷贝到result的第7个位置开始;请问我这样行吗?而且运行的时候(类->DataTrans.Length())提示错误。看看吧。
        /// <summary>
        /// 取得发送的数据与信息.
        /// </summary>
        public byte[] SendMessageByte
        {
            get
            {
                int _length = 42 + Encoding.Default.GetByteCount(em.DataTrans);
                byte[] result = new byte[_length];
                byte[] tmp = null;
                //length DWORD 包的总长度,为包控制信息和实际传送内容长度之和
                tmp = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(em.Length));
                Array.Copy(tmp, 0, result, 0, 4);
                //factory BYTE 厂商编码(暂不处理)
                result[4] = em.Factory;
                //morePkt BYTE 是否还有后续包,’1’有,’0’无
                result[5] = em.MorePkt;
                //cmdId CHAR[10] 命令字,长度为10的数字串,必须10位,右补\0
                tmp = null;
                tmp = Encoding.Default.GetBytes(em.CmdId);
                Array.Copy(tmp, 0, result, 6, 10);
                //requestId DWORD 请求流水号,为异步通讯的标识,客户端生成,服务端在应答包中原样返回。说明:如果服务端返回的报文大于一个包,则这一组包的流水号相同
                tmp = null;
                tmp = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(em.RequestId));
                Array.Copy(tmp, 0, result, 16, 4);
                //answerId DWORD 应答流水号,EOC在回送包中将RequestId填写在此字段回送。说明:如果服务端返回的报文大于一个包,则这一组包的应答流水号相同
                tmp = null;
                tmp = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(em.AnswerId));
                Array.Copy(tmp, 0, result, 20, 4);
                //packetNo DWORD 包序号,从1开始
                tmp = null;
                tmp = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(em.PacketNo));
                Array.Copy(tmp, 0, result, 24, 4);
                //recordSep CHAR[2] 记录分隔符。目前暂不使用,EOC在回送包直接填” ~”。
                tmp = null;
                tmp = Encoding.Default.GetBytes(recordSep);
                Array.Copy(tmp, 0, result, 28, 2);
                //fieldSep CHAR[2] 字段分隔符。目前暂不使用,EOC在回送包直接填” ;”。
                tmp = null;
                tmp = Encoding.Default.GetBytes(fieldSep);
                Array.Copy(tmp, 0, result, 30, 2);
                //reserved DWORD[2] 保留字段
                tmp = null;
                tmp = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(em.Reserved[0]));
                Array.Copy(tmp, 0, result, 32, 4);
                tmp = null;
                tmp = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(em.Reserved[1]));
                Array.Copy(tmp, 0, result, 36, 4);
                //errCode SHORT 返回码0表示成功,其它表示失败。表示请求是否被成功地处理,与具体的业务无关。当网络、应用通讯、数据库访问正常时,errorcode 应该为0。请求包中的errorcode可以随便填充。注意此处表示系统级的成功与失败(如报文实际长度与字段len中表示的不一致)。对数据的实际操作结果放在datatrans中
                tmp = null;
                tmp = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(em.ErrCode));
                Array.Copy(tmp, 0, result, 40, 2);
                //dataTrans CHAR[不定长] 传送内容,从datatrans开始依次为数据内容,实际使用时取其地址作为指针使用
                tmp = null;
                tmp = Encoding.Default.GetBytes(em.DataTrans);
                Array.Copy(tmp, 0, result, 42, Encoding.Default.GetByteCount(em.DataTrans));

                return result;

            }

        public bool SendMessage(ref string receiveStr)
        {
            string msg = Encoding.Default.GetString(SendMessageByte);
            DataRow rw = dt.NewRow();
            rw["ServerIP"] = SvrIP;
            rw["ServerPort"] = SvrPort;
            rw["Message"] = msg;
            byte[] receiveMessage = new byte[4096];
            SocketHelper.SendOnTcp(SvrIP, SvrPort, SendMessageByte,ref receiveMessage, 3);length,4)

        /// <summary>
        /// 取得发送的数据与信息.
        /// </summary>
        public byte[] SendMessageByte
        {
            get
            {
                int _length = 42 + Encoding.Default.GetByteCount(em.DataTrans);
                byte[] result = new byte[_length];
                byte[] tmp = null;
                //length DWORD 包的总长度,为包控制信息和实际传送内容长度之和
                tmp = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(em.Length));
                Array.Copy(tmp, 0, result, 0, 4);
                //factory BYTE 厂商编码(暂不处理)
                result[4] = em.Factory;
                //morePkt BYTE 是否还有后续包,’1’有,’0’无
                result[5] = em.MorePkt;
                //cmdId CHAR[10] 命令字,长度为10的数字串,必须10位,右补\0
                tmp = null;
                tmp = Encoding.Default.GetBytes(em.CmdId);
                Array.Copy(tmp, 0, result, 6, 10);
                //requestId DWORD 请求流水号,为异步通讯的标识,客户端生成,服务端在应答包中原样返回。说明:如果服务端返回的报文大于一个包,则这一组包的流水号相同
                tmp = null;
                tmp = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(em.RequestId));
                Array.Copy(tmp, 0, result, 16, 4);
                //answerId DWORD 应答流水号,EOC在回送包中将RequestId填写在此字段回送。说明:如果服务端返回的报文大于一个包,则这一组包的应答流水号相同
                tmp = null;
                tmp = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(em.AnswerId));
                Array.Copy(tmp, 0, result, 20, 4);
                //packetNo DWORD 包序号,从1开始
                tmp = null;
                tmp = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(em.PacketNo));
                Array.Copy(tmp, 0, result, 24, 4);
                //recordSep CHAR[2] 记录分隔符。目前暂不使用,EOC在回送包直接填” ~”。
                tmp = null;
                tmp = Encoding.Default.GetBytes(recordSep);
                Array.Copy(tmp, 0, result, 28, 2);
                //fieldSep CHAR[2] 字段分隔符。目前暂不使用,EOC在回送包直接填” ;”。
                tmp = null;
                tmp = Encoding.Default.GetBytes(fieldSep);
                Array.Copy(tmp, 0, result, 30, 2);
                //reserved DWORD[2] 保留字段
                tmp = null;
                tmp = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(em.Reserved[0]));
                Array.Copy(tmp, 0, result, 32, 4);
                tmp = null;
                tmp = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(em.Reserved[1]));
                Array.Copy(tmp, 0, result, 36, 4);
                //errCode SHORT 返回码0表示成功,其它表示失败。表示请求是否被成功地处理,与具体的业务无关。当网络、应用通讯、数据库访问正常时,errorcode 应该为0。请求包中的errorcode可以随便填充。注意此处表示系统级的成功与失败(如报文实际长度与字段len中表示的不一致)。对数据的实际操作结果放在datatrans中
                tmp = null;
                tmp = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(em.ErrCode));
                Array.Copy(tmp, 0, result, 40, 2);
                //dataTrans CHAR[不定长] 传送内容,从datatrans开始依次为数据内容,实际使用时取其地址作为指针使用
                tmp = null;
                tmp = Encoding.Default.GetBytes(em.DataTrans);
                Array.Copy(tmp, 0, result, 42, Encoding.Default.GetByteCount(em.DataTrans));

                return result;

            }

        public bool SendMessage(ref string receiveStr)
        {
            string msg = Encoding.Default.GetString(SendMessageByte);
            DataRow rw = dt.NewRow();
            rw["ServerIP"] = SvrIP;
            rw["ServerPort"] = SvrPort;
            rw["Message"] = msg;
            byte[] receiveMessage = new byte[4096];
            SocketHelper.SendOnTcp(SvrIP, SvrPort, SendMessageByte,ref receiveMessage, 3);

    解析报文长度不对,那是因为你的length这个值是随便设置的,实际上这个值发送时是要计算出来的。length  DWORD 这个值,你要的是一帧报文的长度,而不是一包的长度。一包跟一帧是不同的,每发送一次就叫一包,有时候由于网络等原因,一包可能含有多帧,一帧也有可能分成两包发送。所以必须要有报文头,报文长度,报文结束位,才能判断数据的合法性完整性,以及解析报文时计算长度。例如我现在做的一套电力系统里面就是规定以68H开头,然后跟着4个字节的LL再跟一个68H,这就是个报文头,一个L就是报文长度,要重复两次。报文长度是用来计算数据长度的,特别是不定长的数组之类。按照你上面的定义,length=25字节才对。
  我做这类开发的时候,将整个报文写到流里面,再发出去。
  解析报文的时候,将收到的数据写到流里面,指针移到头部,先做合法性判断。如果前两个字节就定义成是长度,每个报文的长度都不固定,能进行判断吗?只有合法了才有做解析的必要。流可以使用TMemoryStream,用个PByte来保存当前指针,用Move函数将指针的内容移到自己的结构、或者变量里面,Inc函数来向后移指针。