Delphi Client 端数据包发送接收处理函数说明

合集下载

DelphiTObject消息的分发DisPatch和接受DefaultHandler

DelphiTObject消息的分发DisPatch和接受DefaultHandler

DelphiTObject消息的分发DisPatch和接受DefaultHandlerDelphi TObject消息的分发DisPatch和接受DefaultHandler Posted on 2011-07-12 11:02 ╰★张志峰★╮ 阅读(1029) 评论(0) 编辑收藏在TObject类中,有一个Dispatch()方法和一个DefaultHandler()方法,它们都是与消息分发机制相关的。

Dispatch()负责将特定的消息分发给合适的消息处理函数。

首先它会在对象本身类型的类中寻找该消息的处理函数,如果找到,则调用它;如果没有找到而该类覆盖了TObject的DefaultHandler(),则调用该类的DefaultHandler();如果两者都不存在,则继续在其基类中寻找,直至寻找到TObject这一层,而TObject已经提供了默认的DefaultHandler()方法。

unit Unit_MessageDispatch;interfaceuses Dialogs, Messages;typeTMyMSG = recordmsg : Cardinal;msgText: string; //描述消息的类型end;TMSGAccepter = class //接受消息类privateprocedure AccepterMsg2000(var msg: TMyMSG); message 2000;procedure AccepterMsg2002(var msg: TMyMSG); message 2002;publicprocedure defaultHandler(var message); override;end;implementation{ TMSGAccepter }procedure TMSGAccepter.AccepterMsg2000(var msg: TMyMSG);beginShowMessage('嗨,我收到了编号为2000 的消息,它的描述是:' + msg.MsgText);end;procedure TMSGAccepter.AccepterMsg2002(var msg: TMyMSG);beginShowMessage('嗨,我收到了编号为2002 的消息,它的描述是:' + msg.MsgText);end;procedure TMSGAccepter.defaultHandler(var message);beginShowMessage('嗨,这个消息我不认识,无法接收,它的描述是:' + TMyMsg(message).MsgText);end;end.unit UFrom_MessageDispatch;interfaceusesWindows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs, StdCtrls, Unit_MessageDispatch;typeTForm_MessageDispatch = class(TForm)Button1: TButton;Button2: TButton;Button3: TButton;procedure FormCreate(Sender: TObject);procedure FormDestroy(Sender: TObject);procedure Button1Click(Sender: TObject);procedure Button2Click(Sender: TObject);procedure Button3Click(Sender: TObject);private{ Private declarations }public{ Public declarations }end;varForm_MessageDispatch: TForm_MessageDispatch;MsgAccept : TMsgAccepter; // 自定义的消息接收类implementation{$R *.dfm}procedure TForm_MessageDispatch.FormCreate(Sender: TObject);beginMsgAccept := TMsgAccepter.Create;end;procedure TForm_MessageDispatch.FormDestroy(Sender: TObject);beginMsgAccept.Free;MsgAccept := nil;end;procedure TForm_MessageDispatch.Button1Click(Sender: TObject);varMsg : TMyMsg;begin// 将值为2000的消息分发给MsgAccept对象,观察其反应Msg.Msg := 2000;Msg.MsgText := 'Message 2000'; // 消息的文字描述MsgAccept.Dispatch(Msg); // 分发消息end;procedure TForm_MessageDispatch.Button2Click(Sender: TObject);varMsg : TMyMsg;begin// 将值为2001的消息分发给MsgAccept对象,观察其反应Msg.Msg := 2001;Msg.MsgText := 'Message 2001'; // 消息的文字描述MsgAccept.Dispatch(Msg); // 分发消息end;procedure TForm_MessageDispatch.Button3Click(Sender: TObject);varMsg : TMyMsg;begin// 将值为2002的消息分发给MsgAccept对象,观察其反应Msg.Msg := 2002;Msg.MsgText := 'Message 2002'; // 消息的文字描述MsgAccept.Dispatch(Msg); // 分发消息end;end.分类: Delphi。

delphisocket发送和接受tcp信息包

delphisocket发送和接受tcp信息包

delphisocket发送和接受tcp信息包展开全文最近有个项目用到delphi 以前学过但是网络通讯这块不懂以前是直接接受字符串现在改用传递信息包希望大侠帮忙写下接受和发送特定信息包的代码下面为信息包的格式和内容数据包格式如下图所示,所包含的内容从左到右进行传输:包头中的信息全部为网络字节顺序!包头信息中,开始标识(head),版本信息(version)为固定格式;包体长度(length),提示整个包体(包括包头)的长度,接收方据此来完成一个业务数据包的接收和解析;命令号(command),为客户端和服务器约定的业务命令,从0到65535,具体定义详见下表:应答状态(status),请求时总设置为0;应答时,由SP应用服务程序返回相应的操作结果或错误原因;任务流水号(taskid)由自行定义,SP应用程序在响应包中必须返回,SP应用程序可以将此作为数据包一段时间内的唯一序列号。

发送方标识1(sender)、发送方标识2(sessionid)、时间戳(timestamp)以及保留字段(reserved),可以为发送方保留一些私有信息,返回包时原样返回。

包头信息中,除了包体长度(length)以外,其他的字段,包括开始标识(head),版本信息(version),任务流水号(taskid),发送方标识1(sender),发送方标识2(sessionid),时间戳(timestamp),以及数据加密标识(flag),需要在响应包中原样返回;流程1、通用网关在连接建立之后,根据刚才加密的字节流,加上信息包头,组合成信息包,然后发送(Send)信息包,发送的字节数为加密后的字节流字节数+24(24信息包头的字节长度);在上述的例子中,信息包大约如ffff0200 00001100 00004e5f 00114b3f 00000000 0100 0038 2fd65329e2770074791503c2dab1d209fe0225636dd07f7277bd2 91209e1a498df28f7af2f0eb4f1be2831f0fa8987b7f9;其中业务加密字节流的长度这里是56,体现在网络字节中是0x0038,如果是x86系列的PC,需要做主机到网络(ntohs)字节顺序转换;2、 SP应用服务程序接收(Recv)该信息包,根据包头信息截取对应的字节流,然后进行解密处理,得到加密前的业务字符串,另外还需要把其他的包头标识、两个包头保留字,存储在本地;3、SP应用服务程序根据流程开发人员与之协商好的格式对接收的字符串进行解析,然后进行响应的处理4、SP应用服务程序在发送之前,同样根据密匙对该返回字符串进行加密处理,然后对加密字节流长度进行计算,加上刚才发送过来的包头标识和版本号以及保留字等,组合成信息包;注意这时,字节流的长度是返回加密字节流的长度,而且是网络字节的以下是自己接受字符串的时的代码procedure TForm1.ServerSocketClientRead(Sender: TObject;Socket: TCustomWinSocket);varlmsg:String;vflag,i,j:Integer;larriveDate:TarriveDate;ip:String;islimit:Boolean;resData:String;//返回数据buff:array[0..255]of byte;beginip:=Socket.RemoteAddress;islimit:=True;For j:=0 to ips.Count-1 DoBeginif (ip=ips[j]) thenbeginislimit:=False;end;End;if not islimit thenBeginCoInitialize(nil);Socket.ReceiveBuf(buff,4);//应该就在这里修改吧lmsg:=Socket.ReceiveText;SendTo();Memo1.Lines.Add(DateTimeTostr(now)+'来自主机'+ip+'的请求数据:'+lmsg );saveToLog(DateTimeTostr(now)+'来自主机'+ip+ ' 的请求数据:'+ lmsg);if lmsg<>'' thenBegintrysaveToLog(DateTimeTostr(now)+'开始处理接受数据'+lmsg);larriveDate:=analyecmdData(lmsg);vflag:=exChange(larriveDate);Memo1.Lines.Add('*'+Socket.ReceiveText+'*'+lmsg);Memo1.Lines.Add(DateTimeTostr(now)+'数据处理完毕:处理结果:'+inttostr(vflag));saveToLog(DateTimeTostr(now)+'数据处理完毕:处理结果:'+inttostr(vflag));exceptbeginvflag:=1;Memo1.Lines.Add(DateTimeTostr(now)+'数据处理异常:'+inttostr(vflag));saveToLog(DateTimeTostr(now)+'数据处理异常:'+inttostr(vflag));end;//vflag:=1;end;for i:=0 to sessions dobegin //取得匹配的客户端if session[i].CHandle = Socket.SocketHandle thenbegincase vflag of0: resData:=inttostr(vflag)+'$'+erID+'$'+larriv eDate.TelNo+'$'+inttostr(larriveDate.inPutKey);1: resData:='1'+'$'+'系统繁忙请稍后冲值';2: resData:='2'+'$'+'平台用户ID不存在';end;session[i].CSocket.SendText(resData);Memo1.Lines.Add(DatetimeT ostr(now)+'向客户端发送处理完毕命令'+resData);saveToLog(DatetimeTostr(now)+'向客户端发送处理完毕命令'+resData);end;end;end;CoUninitialize;endelseBeginCoInitialize(nil);CoUninitialize;// saveToLog(DatetimeTostr(now)+'非法访问Ip'+ip+'访问被阻止');End;end;。

delphi tcpclient 用法

delphi tcpclient 用法

delphi tcpclient 用法As a Delphi developer, you may find yourself needing to use the TCPClient component in your projects. TCPClient is a powerful component that allows you to establish and manage TCP connections with remote servers. It provides a simple and easy-to-use interface for sending and receiving data over the network.作为一名Delphi开发人员,你可能会发现自己需要在项目中使用TCPClient组件。

TCPClient是一个强大的组件,允许你与远程服务器建立和管理TCP连接。

它提供了一个简单易用的界面,用于在网络上发送和接收数据。

When using TCPClient in Delphi, you can easily establish a connection to a remote server by setting the Host and Port properties of the component. Once the connection is established, you can use methods like SendData and ReceiveData to send and receive data over the network. It's important to handle errors and exceptions properly when working with TCPClient to ensure the stability and reliability of your application.在Delphi中使用TCPClient时,你可以通过设置组件的Host和Port属性轻松地建立与远程服务器的连接。

delphi用IdTCPServer和IdTCPClient传输文件

delphi用IdTCPServer和IdTCPClient传输文件

delphi用IdTCPServer和IdTCPClient传输文件以下代码相比网上其它某些文件传输代码精练很多,传输的文件大小任意,个人建议:写网络文件传输程序时最好用Indy的控件(因为其默认即阻塞模式,Server端已封装了多线程,没有数据包大小限制),ClientSocket VS ServerSocket传输文件很麻烦,要自定通信协议,并且有个8KB的瓶颈,实现大文件传输比较麻烦,服务端发送:variFileHandle:integer;iFileLen,cnt:integer;buf:array[0..4096] of byte;beginiFileHandle:=FileOpen('E:\Study\深入Delphi6网络编程.rar',fmOpenRead);iFileLen:=FileSeek(iFileHandle,0,2);FileSeek(iFileHandle,0,0);AThread.Connection.WriteInteger(iFileLen);while true dobegincnt:=FileRead(iFileHandle,buf,4096);AThread.Connection.WriteBuffer(buf,cnt);if cnt<4096 thenbreak;end;FileClose(iFileHandle);end;====================================== =================客户端接收:procedure TForm1.Button1Click(Sender: TObject);varrbyte:array[0..4096] of byte;sFile:TFileStream;iFileSize:integer;begintryIdTcpClient1.Connect(5000);exceptexit;end;iFileSize:=IdTCPClient1.ReadInteger;sFile:=TFileStream.Create('e:\bb.tmp',fmCreate);While iFileSize>4096 dobeginIdTCPClient1.ReadBuffer(rbyte,4096);// .ReadBuffer(rbyte,iLe n);sFile.Write(rByte,4096);inc(iFileSize,-4096);end;IdTCPClient1.ReadBuffer(rbyte,iFileSize);// .ReadBuffer(rbyte, iLen);sFile.Write(rByte,iFileSize);sFile.Free;ShowMessage('file get ok!');end;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 具体代码:Server(Receive):procedure TFrmServer.FormCreate(Sender: TObject);beginIdTCPServer1.DefaultPort:=5616;IdTCPServer1.Active:=True;end;procedure TFrmServer.IdTCPServer1Execute(AThread: TIdPeerThread);varrbyte:array[0..4096] of byte;sFile:TFileStream;cnt,cmd,FileSize:integer;str,FileName:string;beginstr:=AThread.Connection.ReadLn; //接收文件大小及文件名cmd:=pos('|',str); //查找分隔符FileName:=copy(str,1,cmd-1); //提取文件名FileSize:=StrT oInt(copy(str,cmd+1,Length(str)-cmd+1)); //提取文件大小if MessageBox(0,Pchar('用户'+AThread.Connection.Socket.Binding.PeerIP+'要给您传送文件"'+FileName+'" 您是接受还是拒绝?'),'文件接受',MB_YesNo or MB_ICONQUESTION)=ID_Yes then //询问是否接收beginProgressBar1.Max:=FileSize; //初始化进度条ProgressBar1.Position:=0;SaveDialog1.FileName:=FileName; //指定保存的默认文件名,一定要在 SaveDialog1.Execute;之前,不然文件名为空SaveDialog1.Execute;sFile:=TFileStream.Create(SaveDialog1.FileName,fmCreate);//创建待写入的文件流While FileSize>4096 dobeginAThread.Connection.ReadBuffer(rbyte,4096);// 读取文件流sFile.Write(rByte,4096); //写入文件流cnt:=AThread.Connection.ReadInteger; //从发送端接收最新的进度位置信息ProgressBar1.Position:=ProgressBar1.Position+cnt; //更新显示进度Label1.Caption:='当前接收进度..';StatusBar1.Panels[0].Text:='正在接收文件中...';inc(FileSize,-4096);end;AThread.Connection.ReadBuffer(rbyte,FileSize);// .ReadBuffe r(rbyte,iLen);sFile.Write(rByte,FileSize);sFile.Free;StatusBar1.Panels[0].Text:='文件接收完成!';Label1.Caption:='文件接收完成!';end;END;procedure TFrmServer.FormDestroy(Sender: TObject);beginIdTCPServer1.Active:=False;Application.Terminate;end;Client(Send):procedure TFrmClient.SpeedButton1Click(Sender: TObject);beginOpenDialog1.Execute;edtFileName.Text:=OpenDialog1.FileName;end;procedure TFrmClient.btnSendClick(Sender: TObject);variFileHandle:integer;iFileLen,cnt:integer;buf:array[0..4096] of byte;beginif (edtAddress.Text<>'')and (edtFileName.Text<>'') thenbeginIdTCPClient1.Host:=edtAddress.Text;IdTCPClient1.Port:=5616;tryIdTCPClient1.Connect(5000);exceptStatusBar1.Panels[0].Text:='连接接受方失败!';exit;end;if IdTCPClient1.Connected thenbeginiFileHandle:=FileOpen(edtFileName.T ext,fmOpenRead);iFileLen:=FileSeek(iFileHandle,0,2);FileSeek(iFileHandle,0,0);ProgressBar1.Max:=iFileLen;ProgressBar1.Position := 0;IdTCPClient1.WriteLn(ExtractFileName(edtFileName.T ext)+'|' +IntToStr(iFileLen));while true dobeginApplication.ProcessMessages;cnt:=FileRead(iFileHandle,buf,4096); IdTCPClient1.WriteBuffer(buf,cnt);IdTCPClient1.WriteInteger(cnt);ProgressBar1.Position:=ProgressBar1.Position + cnt; StatusBar1.Panels[0].Text:='正在传送文件...';if cnt<4096 thenbreak;end;FileClose(iFileHandle);Label2.Caption:='文件传送完成!';StatusBar1.Panels[0].Text:='文件传送完成!';end;endelseShowMessage('请选择要传送的文件和或接受方地址'); end;。

Delphi Client 端数据包发送接收处理函数说明

Delphi Client 端数据包发送接收处理函数说明

Delphi Client端数据包发送接收处理说明1>自定义报文简介以不定长字符流方式设计。

报文结构大致可理解为报文头+报文体,最小单位以“NAME:VALUE”对的型式, NAME、V ALUE都以各自的长度为前缀;一条典型的发送报文如下所示:009MessageID:00574606:013TransactionID:005BOKFS:003///:0011:003ROW:0011:003COL:0014:010Packeduser:003LHY:010packedtime:0192006-06-0 6 10:29:37:004flag:001Y:009accessory:0011:003///:0012:003ROW:0011:003COL:0017:009IMPRESTNO:0130606163005721:008inittime:019 2006-06-16 15:30:04:009CompanyID:003ITC:011Companytype:001A:009payamount:0041936:012actualamount:0041936:008category:006进帐单:003$$$解析说明:一条典型的返回报文如下所示:009MessageID:00573936:013TransactionID:013COMSQL_SELECT:006Err_ID:003000:00 8Err_DESC:004正确:008Err_DESE:002OK:003///:0011:003ROW:0013:003COL:0012:008CTN_TYPE:002GS:020CTN_TYPE_DESCR IPTION:009普通箱[3]:008CTN_TYPE:002TN:020CTN_TYPE_DESCRIPTION:006罐状箱:008CTN_TYPE:002UT:020CTN_TYPE_DESCRIPTION:006开顶箱:003$$$★请解析说明?注意:返回报文必须要带有错误信息Err_ID、Err_DESC、Err_DESE。

Delphi中消息机制的使用

Delphi中消息机制的使用

Delphi消息处理机制Delphi中的消息消息是Windows发出的一个通知,它告诉应用程序某个事件发生了。

在Delphi中,大多数情况下Windows的消息被封装在VCL的事件中,我们只需处理相应的VCL事件就可以了,但如果我们需要编写自己的控件、截获或过滤消息就必须深入研究Win32的消息处理机制。

在Delphi中消息以TMessage记录的方式定义。

打开Message.pas文件,我们可以看到Tmessage是这样定义的:typeTMessage = packed recordMsg: Cardinal;case Integer of0: ( WParam: Longint;LParam: Longint;Result: Longint);1: ( WParamLo: Word;WParamHi: Word;LParamLo: Word;LParamHi: Word;ResultLo: Word;ResultHi: Word);end;其中,Msg是区别于其他消息的常量值,这些常量值可以是Windows单元中预定义的常量,也可以是用户自己定义的常量。

Wparam通常是一个与消息有关的常量值,也可以是窗口或控件的句柄。

LParam通常是一个指向内存中数据的指针。

Result是消息处理的返回值。

Wparam、Lparam和Result都是32位的,如果想访问其中的低16位或高16位可以分别使用WparamLo、WparamHi、LParamLo、LparamHi、ResultLo和ResultHi。

在Delphi中除了通用的Tmessage外,还为每个Windows定义了一个特殊的消息记录。

我们可以浏览Message.pas文件,下面是键盘的消息记录:TWMKey = packed recordMsg: Cardinal;CharCode: Word;Unused: Word;KeyData: Longint;Result: Longint;与键盘相关的消息如:WM_KEYDOWN、WM_KEYUP、WM_CHAR、WM_SYSKEYDOWN WM_SYSKEYUP、WM_SYSCHAR的记录也被定义为TWMkey。

Delphi多线程及消息发送传递结构体参数

Delphi多线程及消息发送传递结构体参数

Delphi多线程及消息发送传递结构体参数1、Unit2:unit Unit2;interfaceuses windows,classes,NMICMP,SysUtils,StdCtrls,messages;const WM_MY_PING = WM_USER +1024;type//要传递的消息记录.TPingMsg = recordmsg : array[0..1023] of char;id : integer;Handled : boolean;msg2 : string; //建议如果需要动态管理,⽐如采⽤List,采⽤字符数组的⽅式会⽐较好,//因为在动态使⽤结构时,如过没有处理好,采⽤string就可能会造成内存泄露.//当然在这⾥例⼦中没关系.end;pPingMsg = ^TPingMsg;//定义结构体指针.OnPinging = procedure(Context: integer;Msg : string) of object;ThreadEnd = procedure(Context: integer;Msg:string) of object;TMyPingThread = class(TThread)privateFPingEvent : OnPinging;FEndEvent : ThreadEnd;FMsg : string;FSequenceID : integer;FWinHandl : Hwnd;procedure OnPing(Sender: TObject; Host: String; Size, Time: Integer);procedure HandlingEnd;procedure HandlingPing;protectedprocedure Execute;override;procedure DoTerminate;override;public//采⽤函数指针的⽅式,因为传递过来如果是UI控件类的⽅法,该⽅法需要访问UI元素,则需要做同步处理,//否则可能会导致错误.constructor Create(WinHandl : Hwnd; SequenceID : integer;OutPut: OnPinging;EndEvent: ThreadEnd);overload;end;implementation{ TMyPingThread }constructor TMyPingThread.Create(WinHandl : Hwnd;SequenceID : integer;OutPut: OnPinging; EndEvent: ThreadEnd);beginself.FPingEvent := OutPut;self.FEndEvent := EndEvent;FSequenceID := SequenceID;FWinHandl := WinHandl;inherited Create(true);end;procedure TMyPingThread.DoTerminate;begininherited;Synchronize(HandlingEnd);end;procedure TMyPingThread.HandlingEnd();beginif Assigned(self.FEndEvent) thenself.FEndEvent(FSequenceID,FMsg);end;procedure TMyPingThread.HandlingPing();beginif assigned(self.FPingEvent) thenFPingEvent(FSequenceID,FMsg);end;procedure TMyPingThread.Execute;varPingObj : TNMPing;beginself.FreeOnTerminate := true;PingObj := TNMPing.Create(nil);PingObj.OnPing := OnPing;tryPingObj.Pings := 30;PingObj.Host := '';PingObj.Ping;finallyPingObj.Free;end;end;procedure TMyPingThread.OnPing(Sender: TObject; Host: String; Size,Time: Integer);varpMsg : pPingMsg;Msg : TPingMsg;begin//不能直接定义结构体,因为是局部变量,如果是PostMessage,不会等待,会释放的.//但如果采⽤如下的new⽅式,程序不会主动释放内存,需要配合Dispose⽅法⽤.new(pmsg);//这种情况下,消息接收⽅不⼀定能获取到正确的值.FMsg := host+':'+ inttostr(size)+':'+inttostr(Time);strcopy(@(pmsg.msg),pchar(FMsg));pmsg.id := self.FSequenceID;pmsg.Handled := false;pmsg.msg2 := FMsg+'xxx';//注意,这⾥增加字符,并不能增加sizeof(pmsg^)Msg.msg2 := FMsg+'xxxx';//注意,这⾥增加字符,并不能增加sizeof(Msg)strcopy(@(Msg.msg),pchar(FMsg));//postmessage(FWinHandl,WM_MY_PING, self.FSequenceID,LPARAM(@Msg));//因此我觉得采⽤SendMessage⽐较好,这样内存的释放可以在这⾥进⾏,不会造成内存泄露. Sendmessage(FWinHandl,WM_MY_PING, self.FSequenceID,LPARAM(@Msg));//这种⽅法是让线程等待消息处理,实际上等效于SendMessage⽅法调⽤.{while (pmsg.Handled=false) dobeginsleep(10);end;}//采⽤等待⽅法则在这⾥释放空间。

delphi 进程间通信方法

delphi 进程间通信方法

delphi 进程间通信方法Delphi是一种现代的编程语言,它在Windows平台上被广泛使用。

在Delphi中,在不同进程之间进行通信是一项需要的技能。

进程间通信(IPC)是指两个或多个进程之间的相互通信,以便它们可以共同完成任务。

进程间通信支持许多应用程序技术,例如多线程编程、远程过程调用、网络编程、系统编程等。

本文将介绍一些Delphi进程间通信的常用方法。

1. 内存映射内存映射是一种允许多个进程访问相同内存映射区域的机制。

几个进程可以在相同区域的内存中存储数据,而且它们可以访问和操作这些数据。

Delphi中的内存映射技术可以通过TMemoryMapFile类实现。

这个类提供了对内存映射文件的访问。

下面是一些Delphi代码示例:``` procedure TForm1.Button1Click(Sender: TObject); var MemFile: TMemoryMappedFile; MemMap: TMemoryMapHandle; Data: PByte; begin MemFile := TMemoryMappedFile.Create(1024,'MyDataFile'); try MemMap := MemFile.Map;try Data := MemMap.Access; try// 处理数据 Data^ := 65; finally MemMap.Unaccess; end; finallyMemFile.Unmap(MemMap); end; finally MemFile.Free; end; end; ```这个代码片段创建了一个大小为1024字节的内存映射文件,并将其分配给Handle变量“MemMap”。

然后,可以使用“Access”方法来访问这个映射区,使用“Unaccess”方法来退出访问。

可以使用“Unmap”方法来卸载映射区。

2. 共享文件共享文件是允许多个进程同时访问同一文件的机制。

DELPHI下的Winsock编程,游戏封包发送接收

DELPHI下的Winsock编程,游戏封包发送接收

DELPHI下的Winsock编程一、定址要通过Winsock建立通信,必须了解如何利用指定的协议为工作站定址。

Winsock 2引入了几个新的、与协议无关的函数,它们可和任何一个地址家族一起使用;但是大多数情况下,各协议家族都有自己的地址解析机制,要么通过一个函数,要么作为一个投给getsockopt的选项。

因为目前网络编程中用的最多最普遍的也许就是TCP/IP协议了,所以这里主要介绍此协议下的WinSock编程。

1、IP网际协议(Internet Protocol, IP)是一种用于互联网的网络协议,已经广为人知。

它可广泛用于大多数计算机操作系统上,也可用于大多数局域网LAN(比如办公室小型网络)和广域网WAN(比如说互联网)。

从它的设计看来,IP是一个无连接的协议,不能保证数据投递万无一失。

两个比它高级的协议(TCP和UDP)用于依赖IP 协议的数据通信。

2、TCP面向连接的通信是通过“传输控制协议”(Transmission Control Protocol, TCP)来完成的。

TCP提供两台计算机之间的可靠无错的数据传输。

应用程序利用TCP进行通信时,源和目标之间会建立一个虚拟连接。

这个连接一旦建立,两台计算机之间就可以把数据当作一个双向字节流进行交换。

3、UDP无连接通信是通过“用户数据报协议”(User Datagram Protocol, UDP)来完成的。

UDP不保障可靠数据的传输,但能够向若干个目标发送数据,接收发自若干个源的数据。

简单地说,如果一个客户机向服务器发送数据,这一数据会立即发出,不管服务器是否已准备接收数据。

如果服务器收到了客户机的数据,它不会确认收到与否。

数据传输方法采用的是数据报。

TCP和UDP两者都利用IP来进行数据传输,一般称为TCP/IP和UDP/IP。

Winsock 通过AF_INET地址家族为IP通信定址。

4、定址IP中,计算机都分配有一个IP地址,用一个32位数来表示,正式的称呼是“IPv4地址”。

delphi clientsocket 用法

delphi clientsocket 用法

delphi clientsocket 用法Delphi的ClientSocket组件是一个非常有用的网络通信组件,它允许你创建一个TCP/IP客户端,与远程服务器进行通信。

以下是使用Delphi的ClientSocket组件的基本步骤:1. 首先,在你的Delphi项目中添加一个TClientSocket组件。

你可以在工具箱中找到ClientSocket组件,然后将它拖放到你的窗体上。

2. 在TClientSocket的属性中,设置好连接的服务器地址和端口号。

你可以通过修改`Host`和`Port`属性来实现。

3. 添加事件处理程序来处理连接和通信过程中的事件。

TClientSocket有一些重要的事件,比如`OnConnect`,`OnDisconnect`,`OnRead`等等。

你可以在这些事件中编写你自己的代码来实现特定的功能。

例如,当连接成功建立时,`OnConnect`事件会触发,你可以在事件中执行相关操作。

下面是一个简单的示例代码,展示了如何使用Delphi的ClientSocket组件来连接服务器并进行通信:```delphiunit Unit1;interfaceuses// 导入所需的单元typeTForm1 = class(TForm)ClientSocket1: TClientSocket;Button1: TButton;Memo1: TMemo;procedure ClientSocket1Connect(Sender: TObject;Socket: TCustomWinSocket);procedure ClientSocket1Disconnect(Sender: TObject;Socket: TCustomWinSocket);procedure ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);procedure Button1Click(Sender: TObject);private{ Private declarations }public{ Public declarations }end;varForm1: TForm1;implementation{$R *.dfm}procedure TForm1.ClientSocket1Connect(Sender: TObject; Socket: TCustomWinSocket);beginMemo1.Lines.Add('Connected to server.');end;procedure TForm1.ClientSocket1Disconnect(Sender: TObject;Socket: TCustomWinSocket);beginMemo1.Lines.Add('Disconnected from server.');end;procedure TForm1.ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);beginMemo1.Lines.Add('Received: ' + Socket.ReceiveText);end;procedure TForm1.Button1Click(Sender: TObject);beginif not ClientSocket1.Active thenClientSocket1.Open; // 打开与服务器的连接end;end.```在上面的示例中,当点击Button1按钮时,会尝试与在TClientSocket的属性中指定的服务器建立连接。

DELPHI数据控件TclientDataSet的详细说明

DELPHI数据控件TclientDataSet的详细说明

DELPHI数据控件TclientDataSet的详细说明与TTable、TQuery一样,TClientDataSet也是从TDataSet继承下来的,它通常用于多层体系结构的客户端。

TClientDataSet最大的特点是它不依赖于BDE(Borland Database Engine),但它需要一个动态链接库的支持,这个动态链接库叫DBCLIENT.DLL。

在客户端,也不需要用TDatabase构件,因为客户端并不直接连接数据库。

由于TClientDataSet是从TDataSet继承下来的,所以,它支持诸如编辑、搜索、浏览、纠错、过滤等功能。

由于TClientDataSet 在内存中建立了数据的本地副本,上述操作的执行速度很快。

也正是由于TClientDataSet并不直接连接数据库,因此,客户程序必须提供获取数据的机制。

在Delphi 4中,TClientDataSet有三种途径获取数据:.从文件中存取数据。

.从本地的另一个数据集中获取数据。

.通过IProvider接口从远程数据库服务器获取数据。

在一个客户程序中,可以同时运用上述三种机制获取数据。

1、浏览和编辑数据和其他数据集构件一样,可以用标准的数据控件显示由TClientDataSet引入的数据集,当然,这需要借助于TDataSource 构件。

由于TClientDataSet是从TDataSet继承下来的,所以,凡是其他数据集构件支持的功能,TClientDataSet构件也大致具备。

不同的是,TClientDataSet能够在内存中建立数据的副本,因此,TClientDataSet比其他数据集构件增加了一些特殊的功能。

1.1、浏览数据可以用标准的数据控件显示由TClientDataSet引入的数据集。

在运行期,可以调用诸如First、GotoKey、Last、Next和Prior等函数来浏览数据。

TClientDataSet也支持书签功能,可以用书签来标记某条记录,以后就可以方便地找到这条记录。

用TTcpClient和TTcpServer进行文件的传输-[Delphi编程]

用TTcpClient和TTcpServer进行文件的传输-[Delphi编程]

用TTcpClient和TTcpServer进行文件的传输-[Delphi编程]2010-01-27用TTcpClient和TTcpServer进行文件的传输 - [Delphi编程] 版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明客户端:定义了一个常量:const BLOCK_SIZE = 1024;//把文件分开来传,每一次传送1024个字节然后在Form上放一个TTcpClient和一个按钮,为按钮的点击写处理过程:procedure TForm1.Button1Click(Sender: TObject);varsFileFullName, sFileName : string; //带路径的文件名,文件名iFileLen : LongInt; //文件大小sMsg : string; //接收到的消息i, cyc : Integer; //循环传送次数FileStem : TMemoryStream; //文件数据PBuf : Pointer;acBlockSize, tmpSize, LastBlockSize : Integer; //实际读取的数据大小 ,从Stream中际读取的大小,最后一个数据块的大小beginif dlgOpen1.Execute thenbeginsFileFullName := dlgOpen1.FileName;end;if sFileFullName = '' thensFileName := ExtractFileName(sFileFullName); //从带路径的文件名中提取文件名FileStem := TMemoryStream.Create;tryFileStem.LoadFromFile(sFileFullName);iFileLen := FileStem.Size;sMsg := sFileName + '^' + IntToStr(iFileLen); //拼装消息:文件名+^+文件大小TcpClient1.RemoteHost := edt1.Text; //从Edit中取服务器地址TcpClient1.RemotePort := '32765'; //要连接的端口TcpClient1.Open; //连接服务器if TcpClient1.Connected thenbeginwith TcpClient1 dobeginSendln(sMsg); //发送拼装好的消息sMsg := Receiveln(CRLF);if iFileLen mod BLOCK_SIZE = 0 thencyc := iFileLen div BLOCK_SIZE //把文件分块进行传输,如果文件大小能被定义好的BLOCK_SIZE整除,就循环iFileLen 除以BLOCK_SIZE那么多次就行了elsecyc := iFileLen div BLOCK_SIZE + 1; //把文件分块进行传输,如果文件大小不能被定义好的BLOCK_SIZE整除,要多传一次,把剩下的数据块传完if sMsg = 'OK' then //服务器已经准备好,下面开始发送数据beginGetMem(PBuf,BLOCK_SIZE); //分配内存for i := 1 to cyc dobeginif i = cyc thenbeginLastBlockSize := iFileLen - FileStem.Position; //如果已经传到最后一块了,计算好最后一块的大小tmpSize := FileStem.Read(PBuf^,LastBlockSize);acBlockSize := SendBuf(PBuf^,LastBlockSize);endelsebegintmpSize := FileStem.Read(PBuf^,BLOCK_SIZE); //发送正常的数据块acBlockSize := SendBuf(PBuf^,BLOCK_SIZE);end; //}end;finallyFreeMem(PBuf);end;end;end;end;TcpClient1.Close;finallyFileStem.Free;end;end;服务器端:同样也要定义一个常量:const BLOCK_SIZE = 1024;//把文件分开来传,每一次传送1024个字节在Form上放一个按钮,Caption为“开始监听”procedure TForm1.Button1Click(Sender: TObject);beginTcpServer1.LocalPort := '32765';TcpServer1.Open;Button1.Enabled := False;end;在Form上放一个TTcpServer,为它的OnAccept编写事件:procedure TForm1.TcpServer1Accept(Sender: TObject;ClientSocket: TCustomIpClient);varMsgList : TStringList; //消息列表FileStem: TMemoryStream; //文件流sFileName : string; //文件名iFileLen : LongInt; //文件大小,最大为2GsMsg : string; //接收的消息,用于商量传输过程PBuf : Pointer; //内存块指针i, cyc : Integer; //cyc是计算出来的,一个文件要循环传送多少次acBlockSize,tmpSize,LastBlockSize : Integer; //实际读取的数据大小beginMsgList := TStringList.Create;FileStem := TMemoryStream.Create;trywith ClientSocket dobeginsMsg := Receiveln(CRLF);//接收消息maText := StringReplace(sMsg,'^',',',[rfReplaceAll]); //折分消息,如果文件名上有空格,Delphi会把空格也作为分隔符,这好像是Delphi中的一个BUG。

DELPHI中两个UDP控件的用法

DELPHI中两个UDP控件的用法

DELPHI中有两个UDP控件:TIdUDPServer和TIdUDPClient控件,可用于传输UDP数据;用法都很简单,主要是一些细微的特性,弄清楚了对正确使用这两种控件有很大的好处;下面分别介绍:一、TIdUDPServer:代表一个UDP的服务端,接收UDP客户端发过来的数据;在FORM上放置一个TIdUDPServer控件,命名为UDPSvr,在FormCreate 事件中编写如下代码:UDPSvr.Bindings.Add;UDPSvr.Bin dings[0].IP := ‘192.168.2.117’;UDPSvr.Bindings[0].Port := 1812;UDPSvr.Active := True;在UDPSvr控件的OnUDPRead事件中编写如下代码:varBuffer: array[0..1024] of Char;iSize: integer;sData: string;beginZeroMemory(@Buffer,sizeof(Buffer));iSize := AData.Size;if iSize > 1024 thenbeginiSize := 1024;end;AData.Seek(0,soFromBeginning);iSize := AData.Read(Buffer,iSize);。

{对接收数据的处理}end;这样就完成了一个可以接收数据的UDP应用程序;其实TIdUDPServer有发送数据的方法:Send和SendBuffer,是继承自TIdUPDBase,所以只要利用TIdUDPServer控件就可完成数据的收发,在FORM 上添加一个Tbutton控件,在Click事件中添加如下代码;varBuffer: array[0..1024] of Char;sText: string;iLen: integer;beginsText := ‘12345678’ZeroMemory(@Buffer,sizeof(Buffer));StrPCopy(Buffer,sText);iLen := Length(sText);UDPSvr.SendBuffer(‘192.168.2.117’,1814,Buffer,iLen);end;这样就可以向另一UDP应用程序发送数据;一个TIdUDPServer控件可以打开多个端口,如下的代码打开了两个端口:UDPSvr.Bindings.Add;UDPSvr.Bindings[0].IP := GetLocalIP;UDPSvr.Bindings[0].Port := 1812;UDPSvr.Bindings.Add;UDPSvr.Bindings[1].IP := GetLocalIP;UDPSvr.Bindings[1].Port := 1813;UDPSvr.Active := True;当打开多个端口时,发送数据是从哪个端口发送出去呢?根据测试结果是:最近收到数据的那个端口;如果还没有收到过数据,则为Bindings[0].Port;在接收数据的事件中,有一个TidSocketHandle类型的参数:Abinding;这个参数有两对属性:IP 、Port:代表本地IP地址和端口;PeerIP、PeerPort:代表远端IP地址和端口;其中PeerIP、PeerPort在交复发送数据的UDP应用中是很有用的,因为UDP服务端可以向PeerIP和PeerPort回应数据,而不用再去设置UDP客户端的IP地址和端口号(这种方法应用不当,会产生问题,下面会说到);二、TIdUDPClient:代表一个UDP的客户端,专门用于发送UDP数据,不能接收数据,因为没有相应的事件和方法;前面已经说过,利用TIdUDPServer 控件就可以完成UDP数据的收发,所以一直怀疑TIdUDPClient控件存在的必要性;除非有一个UDP的客户端只发送数据,而从不接收数据,这样的客户端应该很少;后来我想,可能可以用TIdUDPClient控件来分担TIdUDPServer控件的负载,在一个需要收发大量UDP数据的服务端中,TIdUDPServer控件只接收数据,另外专门用一个TIdUDPClient控件发送数据,也许可以提高应用程序的性能(没有经过验证);利用TIdUDPClient发送数据有两种方式:1、利用TIdUDPClient控件本身的Send和SendBuffer方法,这时需要设置Host和Port属性,在FORM上放置一个TIdUDPClient控件,命名为:UDPClt;分别设置Host和Port属性值为:192.168.2.117和1814;再编写如下代码:varBuffer: array[0..1024] of Char;sText: string;iLen: integer;beginsText := ‘12345678’;ZeroMemory(@Buffer,sizeof(Buffer));StrPCopy(Buffer,sText);iLen := Length(sText);UDPClt.SendBuffer(Buffer,iLen);end;2、不需要设置Host和Port属性,而直接利用从TIdUPDBase继承来的Send和SendBuffer方法,也可发送数据,代码如下所示:UDPClt.SendBuffer(‘192.168.2.117’,1814,Buffer,iLen);TIdUDPClient控件发送数据时是通过哪个端口发出去的呢?根据测试的结果:是随机的;这样就给上面说过的UDP服务端可以向PeerIP和PeerPort回应数据造成了麻烦,也就是说如果UDP服务端收到的数据是通过TIdUDPClient控件发过来的,就不能通过PeerIP和PeerPort回应回去,而应设定客户端的IP地址和端口号;在具体应用中是哪种情况,要根据测试结果而定。

DELPHI网络文件传输控制例程

DELPHI网络文件传输控制例程

【程序说明】P2P(点对点)的流行产生了大批网络传输软件,这里我们要介绍的就是自己写一个简单的P2P 文件传输,一方发送文件,一方接受,直到传输完整个文件。

程序运行效果如图所示。

服务器端:图8.5.1客户端:图8.5.2由服务器端负责发送文件,客户端接受。

【编程思路】利用TCP协议连接双方,服务器端建立文件流读入待发送文件进入监听状态,客户端发送信号开始传输,服务器根据客户端发送的当前文件流传输位置按接收缓冲区大小一块一块的发送给客户端,客户端接受后再保存到接收文件流,直到整个文件流发送完毕,这里服务器端使用TIdTCPServer组件,客户端对应的使用TIdTCPClient组件。

【编程步骤】1.启动Delphi7,建立一个标准的Application,首先我们来做服务器端,。

2.按图放置如下组件:图8.5.3将项目保存Server目录下,取名为Server.dpr,单元取名为U_Server.pas。

3.然后我们再来看看客户端,这里由于我们实际上是做了两个程序(服务器端和客户端),因而引入一个新的概念:项目组(Project Group),使用项目组我们很方便的同时调试两个以上的程序,也因为如此,我们上面才需要更改项目名,单元名以区分服务端和客户端,使用项目组功能首先我们找到DELPHI的IDE菜单的View项,打开Project Manager(Ctrl+Alt+F11)即可看到一个项目组管理窗口,其中已经有我们刚才建立的Server.exe了,现在我们New新建一个标准的Application项目,按照下图放置组件:图8.5.4将项目保存在Client目录下,取名Client.dpr,单元名U_Client.pas,现在我们可以看到,项目组窗口中多了一个Client.exe项目,其中项目名黑色加粗表示当前激活的项目。

以上组件除了Tlabel组件、Tbutton组件修改标题和StatusBar1修改SimplePanel为True外全部使用默认属性,属性列表我们这里就省略了。

Delphi7网络通信控件ServerSocket ClientSocket步步学(3)

Delphi7网络通信控件ServerSocket ClientSocket步步学(3)

Delphi7网络通信控件ServerSocket 和ClientSocket步步学(3) 这一讲,有多个客户端联接服务端的处理;1.界面如下图所示:2.Serversocket 和clientsocket 的属性及事件设置1.发送字符串程序如下varForm1: TForm1;client_x:array[1..10] of integer; //用来保存10个客户端的句抦cx:integer; //全局变量implementation{$R *.dfm}procedure TForm1.FormShow(Sender: TObject);var i:integer;beginfor i:=1 to 10 doclient_x[i]:=-1; //数据初始化ServerSocket1.ThreadCacheSize:=10; //最多允许10个客户端访问ServerSocket1.Open; //打开服务端memo1.Clear;memo1.Lines.Add('工作流程:');memo1.Lines.Add('首先是客户端申请联接服务器,');memo1.Lines.Add('联接上以后, 客户端发送数据给服务器,');memo1.Lines.Add('然后,服务器接收到客户端发送来的数据,');memo1.Lines.Add('而且,服务器将根据客户句柄,查询出数据是哪一个客户发来的,');memo1.Lines.Add('最后,服务器给发数据的这个客户端回送应答数据!');memo1.Lines.Add('注意,该程序只给出了一个客户端,其他的客户端依此类推!');end;procedure TForm1.Button3Click(Sender: TObject);beginClientSocket1.Address:='127.0.0.1'; //客户的IP地址ClientSocket1.Port:=1234; //客户的端口号ClientSocket1.Open; //打开客户端申请联接end;procedure TForm1.Button13Click(Sender: TObject);beginClientSocket1.Close; //断开客户端联接end;procedure TForm1.Button1Click(Sender: TObject);beginclientsocket1.Socket.SendText(edit1.text); //客户向服务器发送数据end;procedure TForm1.ServerSocket1ClientConnect(Sender: TObject; Socket: TCustomWinSocket); //有客户端联接上事件var i:integer;begini:=serversocket1.Socket.ActiveConnections; //目前服务器客户端个数client_x[i]:=socket.SocketHandle; //存储刚刚联接的客户端句柄end;procedure TForm1.ServerSocket1ClientDisconnect(Sender: TObject; Socket: TCustomWinSocket); //有客户端断开联接--事件var i,t:integer;ax:array[1..10] of integer;beginfor i:=1 to 10 do ax[i]:=-1;for i:=1 to 10 dobeginif client_x[i]=socket.SocketHandle then//注消刚刚断开联接的客户端句柄client_x[i]:=-1;end;t:=0;for i:=1 to serversocket1.Socket.ActiveConnections dobeginif (client_x[i]<>-1) then //从新计数客户端,begin //因为ServerSocket1.Socket.Connections[i]inc(t,1); //i 是从0.1.2.....n 个客户端ax[t]:=client_x[i]end;end;for i:=1 to 10 do client_x[i]:=ax[i];end;procedure TForm1.ServerSocket1ClientRead(Sender: TObject;Socket: TCustomWinSocket); //服务器刚刚接收到客户的数据var s:string;i:integer;beginmemo1.Lines.Add('客户的主机名:'+Socket.RemoteHost);memo1.Lines.Add('客户的IP地址:'+Socket.RemoteAddress);cx:=socket.SocketHandle; //刚刚接收到的客户的句柄for i:=1 to 10 doif (cx=client_x[i]) then break; //循环查询是哪个客户发来的数据s:=inttostr(i)+'#客户端发送---->服务器接收的数据: '+socket.ReceiveText;memo1.Lines.Add(s);end;procedure TForm1.Button2Click(Sender: TObject); //服务器发送应答数据给客户var i:integer;beginfor i:=1 to 10 dobeginif client_x[i]=cx then //跟据刚才接收的客户的句柄break; //循环查询应该回答哪一个客户end;if (i=11) then exit; //如果没有客户联接ServerSocket1.Socket.Connections[i-1].SendText(edit1.Text);end;procedure TForm1.ClientSocket1Read(Sender: TObject;Socket: TCustomWinSocket); //客户接收服务端应答的数据var s:string;begins:='服务器发送---->客户端接收的数据: '+socket.ReceiveText;memo1.Lines.Add(s);end;procedure TForm1.ClientSocket1Connecting(Sender: TObject;Socket: TCustomWinSocket); //客户端申清联接事件beginmemo1.Lines.Add('正在申清联接....')end;procedure TForm1.ClientSocket1Connect(Sender: TObject;Socket: TCustomWinSocket); //客户端联接上事件beginmemo1.Lines.Add('已经联接上服务端')end;procedure TForm1.ClientSocket1Disconnect(Sender: TObject;Socket: TCustomWinSocket); //客户端断开联接事件beginmemo1.Lines.Add('已经断开服务端联接')end;procedure TForm1.ServerSocket1ClientError(Sender: TObject;Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;var ErrorCode: Integer);beginshowmessage('服务器端出错!'); //显示程序员自定义的错误提示信息ErrorCode:=$00; //不再显示系统的错误提示信息end;procedure TForm1.ClientSocket1Error(Sender: TObject;Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;var ErrorCode: Integer);beginshowmessage('客户端出错!'); //显示程序员自定义的错误提示信息ErrorCode:=$00; //不再显示系统的错误提示信息end;end.2.发送十六进制数varForm1: TForm1;client_x:array[1..10] of integer; //用来保存10个客户端的句抦cx:integer; //全局变量implementation{$R *.dfm}procedure TForm1.FormShow(Sender: TObject);var i:integer;beginfor i:=1 to 10 doclient_x[i]:=-1; //数据初始化ServerSocket1.ThreadCacheSize:=10; //最多允许10个客户端访问ServerSocket1.Open; //打开服务端memo1.Clear;memo1.Lines.Add('工作流程:');memo1.Lines.Add('首先是客户端申请联接服务器,');memo1.Lines.Add('联接上以后, 客户端发送数据给服务器,');memo1.Lines.Add('然后,服务器接收到客户端发送来的数据,');memo1.Lines.Add('而且,服务器将根据客户句柄,查询出数据是哪一个客户发来的,');memo1.Lines.Add('最后,服务器给发数据的这个客户端回送应答数据!');memo1.Lines.Add('注意,该程序只给出了一个客户端,其他的客户端依此类推!');end;procedure TForm1.Button3Click(Sender: TObject);beginClientSocket1.Address:='127.0.0.1'; //客户的IP地址ClientSocket1.Port:=1234; //客户的端口号ClientSocket1.Open; //打开客户端申请联接end;procedure TForm1.Button13Click(Sender: TObject);beginClientSocket1.Close; //断开客户端联接end;procedure TForm1.Button1Click(Sender: TObject);var date:array[1..5] of byte;begindate[1]:=$18;date[2]:=$DA;date[3]:=$EF; //发送数据18 DA EF 95 6Bdate[4]:=$95;date[5]:=$6B;clientsocket1.Socket.SendBuf(date,5); //客户向服务器发送数据end;procedure TForm1.ServerSocket1ClientConnect(Sender: TObject;Socket: TCustomWinSocket); //有客户端联接上事件var i:integer;begini:=serversocket1.Socket.ActiveConnections; //目前客户端个数client_x[i]:=socket.SocketHandle; //存储刚刚联接的客户端句柄end;procedure TForm1.ServerSocket1ClientDisconnect(Sender: TObject;Socket: TCustomWinSocket); //有客户端断开联接事件var i,t:integer;ax:array[1..10] of integer;beginfor i:=1 to 10 do ax[i]:=-1;for i:=1 to 10 dobeginif client_x[i]=socket.SocketHandle then //注消刚刚断开联接的客户端句柄client_x[i]:=-1;end;t:=0;for i:=1 to serversocket1.Socket.ActiveConnections dobeginif (client_x[i]<>-1) then //从新计数客户端,begin //因为ServerSocket1.Socket.Connections[i]inc(t,1); //i 是从0.1.2.....n 个客户端ax[t]:=client_x[i]end;end;for i:=1 to 10 do client_x[i]:=ax[i];end;procedure TForm1.ServerSocket1ClientRead(Sender: TObject;Socket: TCustomWinSocket); //服务器刚刚接收到客户的数据var s,s1:string;i,t,L:integer;date:array[1..10] of byte;begins1:='';memo1.Lines.Add('客户的主机名:'+Socket.RemoteHost);memo1.Lines.Add('客户的IP地址:'+Socket.RemoteAddress);cx:=socket.SocketHandle; //刚刚接收到的客户的句柄for i:=1 to 10 doif (cx=client_x[i]) then break; //循环查询是哪个客户发来的数据L:=socket.ReceiveLength; //查询接收字节的长度Lsocket.ReceiveBuf(date,L); //接收L个字节数据for t:=1 to L dos1:=s1+inttohex(date[t],2)+' ';s:=inttostr(i)+'#客户端发送---->服务器接收的数据: '+s1;memo1.Lines.Add(s);end;procedure TForm1.Button2Click(Sender: TObject); //服务器发送应答数据给客户var i:integer;date:array[1..5] of byte;beginfor i:=1 to 10 dobeginif client_x[i]=cx then //跟据刚才接收的客户的句柄break; //循环查询应该回答哪一个客户end;if (i=11) then exit; //如果没有客户联接date[1]:=$18;date[2]:=$DA;date[3]:=$EF; //发送数据18 DA EF 95 6Bdate[4]:=$95;date[5]:=$6B;ServerSocket1.Socket.Connections[i-1].SendBuf(date,5);end;procedure TForm1.ClientSocket1Read(Sender: TObject;Socket: TCustomWinSocket); //客户接收服务端应答的数据var s,s1:string;t,L:integer;date:array[1..10] of byte;beginL:=socket.ReceiveLength;socket.ReceiveBuf(date,L); //接收字节的长度for t:=1 to L dos1:=s1+inttohex(date[t],2)+' ';s:='服务器发送---->客户端接收的数据: '+s1;memo1.Lines.Add(s);end;procedure TForm1.ClientSocket1Connecting(Sender: TObject; Socket: TCustomWinSocket); //客户端申清联接事件beginmemo1.Lines.Add('正在申清联接....')end;procedure TForm1.ClientSocket1Connect(Sender: TObject; Socket: TCustomWinSocket); //客户端联接上事件beginmemo1.Lines.Add('已经联接上服务端')end;procedure TForm1.ClientSocket1Disconnect(Sender: TObject; Socket: TCustomWinSocket); //客户端断开联接事件beginmemo1.Lines.Add('已经断开服务端联接')end;procedure TForm1.ServerSocket1ClientError(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;var ErrorCode: Integer);beginshowmessage('服务器端出错!'); //显示程序员自定义的错误提示信息ErrorCode:=$00; //不再显示系统的错误提示信息end;procedure TForm1.ClientSocket1Error(Sender: TObject;Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;var ErrorCode: Integer);beginshowmessage('客户端出错!'); //显示程序员自定义的错误提示信息ErrorCode:=$00; //不再显示系统的错误提示信息end;end.。

Delphi中ComPort通信中的数据处理

Delphi中ComPort通信中的数据处理

Delphi中ComPort通信中的数据处理1.串口通信的基本原理:一般计算机与外部设备通讯有两种方式:并行传送(Parallel ):一次的传输量为8个位(1字节),通过并行端口,如打印机串行传送(Serial ):一次只传输1个位,通过串行端口,如RS-232位与字节的概念:二进制中的每一位0和1,被叫做一个位,每8个位构成一个字节一个字节中最右面的位被称为第0位,最左面的位被称为第7位。

传输过程中的字节类型:一般有两种。

1.文本(字符字母、标点符号等)在计算机中存储时,每个不同的字符都用不同的数值来表示。

这些数值的范围通常在0-127或0-255范围。

7位:ASCII码,每个字节留一个备用位8位:前128个遵循ASCII码规则,其余的128个用来做扩展字符、数字符号、图形字符等编码。

2.二进制数据:某些可执行指令文件和图形图像文件就是以二进制形式而不是ASCII码形式存储的。

一个数据可用二进制形式存储,可以占多个字节。

在通信领域,常常把这种类型的资料叫做二进制数据。

今天要讲的就是有关二进制数据的处理方法。

几个概念:波特率:每秒所能产生的最大电压状态改变率(一秒钟可以振荡的次数)bps 通信双方必须要取得一样的通信速度。

原始信号经过不一样的波特率取样后,所得的结果完全不一样,如取样速度只有原来一半时,信号被跳着取样,数据因此错误。

数据位:有5,6,7,8四种停止位:在奇偶位(选择有奇偶校验)或数据位(选择无奇偶校验)之后发送或接收的停止位。

停止位的长度可在1、1.5或2位三者中选择)。

奇偶校验位:数据传输之后是可供选择的奇偶校验位发送和接收。

奇偶位的状态取决于选择的奇偶校验类型。

如果选择奇校验,则该字符数据中为1的位数与校验位相加,结果应为奇数。

可选奇,偶或无。

如果要保证通讯畅通。

通讯双方以上4项设置必须一致。

一个字节是8位,数据位可以7位,然后一位校验位就8位了。

这些参数可以自己设置。

但是如果要保证通讯畅通。

Delphi中参数的传递和函数值的返回

Delphi中参数的传递和函数值的返回

Delphi中参数的传递和函数值的返回关于Delphi中参数的传递和函数值的返回前⾔:⾼⼿们应该早知道了,不屑于写出来⽽已。

真正的⾼⼿⼀个⽐⼀个潜的深,只剩下偶这样的⼩菜写些菜⽂给更⼩的菜。

⾼⼿看时还请捂好⼤⽛,多多指点。

不知各位⼩菜同胞对破解DELPHI程序有什么看法,反正我的感觉就⼀个字:怪。

各位最先遇到的问题恐怕都是:我下了GetDlgItemInt、GetDlgItemText、GetWindowText....怎么什么也断不下来,甚⾄连Hmemcpy都不起作⽤?呵呵,从这⾥就能看出宝蓝的那批⼈成⼼想跟M$对着⼲,⾮搞出些新鲜的东东不可。

这回我们就来看看DLEPHI中对函数(过程)参数的传递是如何进⾏的。

我们知道WinAPI采⽤的调⽤约定是StdCall,也就是调⽤⼀个函数Func(arg1,agr2,agr3,arg4),你需要push arg4,push arg3,push arg2,push arg1,call Func 。

在VC++⾥也是这种形式,所以⼀个函数有⼏个参数,可以⾮常直观地看出来。

可是在DELPHI中就很奇怪了,在⼀个CALL前⾯你可能⼀个PUSH也看不到,怎么回事呢?听我慢慢道来。

DELPHI中的调⽤约定有StdCall,Cdecl,Safecall,Pascal和Register等⼏种⽅式,⽽DELPHI的默认⽅式是Register(为什么不是Pascal?)Register⽅式就是尽可能地使⽤寄存器来传递参数,减少堆栈的操作来提⾼速度。

具体情况是怎样呢,看个例⼦先:在FORM上放⼀个BUTTON,双击写代码如下:代码:function add1(a:Integer):Integer; //⼀个参数beginadd1:=a+a;end;function add2(a,b:Integer):Integer; //两个参数beginadd2:=a+b;end;function add3(a,b,c:Integer):Integer; //三个参数beginadd3:=a+b+c;end;function add4(a,b,c,d:Integer):Integer; //四个参数beginadd4:=a+b+c+d;end;function add5(a,b,c,d,e:Integer):Integer; //五个参数beginadd5:=a+b+c+d+e;end;function add6:Integer; //加⼊⼀些局部变量var local1,local2,local3,local4,local5:Integer;beginlocal1:=1;local2:=2;local3:=3;local4:=4;local5:=5;add6:=local1+local2+local3+local4+local5;end;function add7(a,b,c,d,e:Integer):Integer; //利⽤result来返回beginresult:=a+b+c+d+e;end;function add8(a,b,c,d,e:Integer):Integer;StdCall;//StdCall调⽤⽅式beginadd8:=a+b+c+d+e;end;procedure TForm1.Button1Click(Sender: TObject);var a,b,c,d,e:Integer;s1,s2,s3,s4,s5,s6,s7,s8,s:Integer;begina:=1; b:=2; c:=3; d:=4; e:=5;s1:=add1(a);s2:=add2(a,b);s3:=add3(a,b,c);s4:=add4(a,b,c,d);s5:=add5(a,b,c,d,e);s6:=add6;s7:=add7(a,b,c,d,e);s8:=add8(a,b,c,d,e);s:=s1+s2+s3+s4+s5+s6+s7+s8; //必须要有这么⼏句MessageDlg(IntToStr(s),mtConfirmation,[mbOK],0); //不然编译器根本不去处理返回值end;⽤DEDE反⼀下看看,这个Button1Click的内容:代码:004403EC 55 push ebp004403ED 8BEC mov ebp, esp004403EF 83C4D8 add esp, -$28 ;空出地⽅放局部变量004403F2 53 push ebx004403F3 56 push esi004403F4 57 push edi004403F5 33C9 xor ecx, ecx004403F7 894DD8 mov [ebp-$28], ecx004403FA 33C0 xor eax, eax004403FC 55 push ebp* Possible String Reference to: '関-?腽_^[嬪]?|004403FD 68E9044400 push $004404E9***** TRY|00440402 64FF30 push dword ptr fs:[eax] ;这是DELPHI的例⾏公事00440405 648920 mov fs:[eax], esp ;据我观察只要调⽤VCL库的都要SEH00440408 BB01000000 mov ebx, $00000001 ;a:=10044040D BE02000000 mov esi, $00000002 ;b:=200440412 BF03000000 mov edi, $00000003 ;c:=300440417 C745FC04000000 mov dword ptr [ebp-$04], $00000004 ;d:=40044041E C745F805000000 mov dword ptr [ebp-$08], $00000005 ;e:=5可以看出DELPHI的确不⼀样,把EBX,ESI,EDI能⽤的寄存器全都⽤上了,实在不⾏了才⽤[ebp-xx],从下⾯的分析中也能看出这⼀点,DELPHI在能⽤寄存器时决不⽤堆栈。

Delphi中ComPort通信中的数据处理范文

Delphi中ComPort通信中的数据处理范文

Delphi中ComPort通信中的数据处理范文在Delphi中使用ComPort进行通信时,数据处理是一个非常重要的步骤。

本文将详细介绍如何在Delphi中进行ComPort通信的数据处理。

首先,我们需要使用Delphi的ComPort组件来建立与外部设备的通信。

在使用ComPort组件之前,我们需要在Delphi的工具箱中添加ComPort组件。

添加完成后,我们可以在Delphi的窗体上放置一个ComPort组件。

接下来,我们需要在代码中对ComPort进行配置。

首先,我们需要设置ComPort的端口号和波特率。

例如,我们可以将端口号设置为COM1,波特率设置为9600。

可以通过以下代码实现:```ComPort1.Port := 'COM1';ComPort1.BaudRate := br9600;```然后,我们需要打开ComPort以建立与外部设备的连接。

可以使用以下代码打开ComPort:```ComPort1.Open;```在建立了与外部设备的连接后,我们就可以开始进行数据的发送和接收了。

数据的发送可以通过ComPort的WriteStr方法实现。

例如,我们可以发送一个字符串“Hello”到外部设备:```ComPort1.WriteStr('Hello');```数据的接收可以通过ComPort的OnRxChar事件来处理。

在该事件中,我们可以读取接收到的数据并进行相应的处理。

例如,我们可以将接收到的数据显示在一个文本框中:```procedure Port1RxChar(Sender: TObject; Count: Integer);varData: string;beginData := ComPort1.ReadStr(Count);Edit1.Text := Data;end;```在上面的代码中,我们使用了ComPort的ReadStr方法来读取接收到的数据,并将其赋值给一个字符串变量Data。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Delphi Client端数据包发送接收处理说明
1>自定义报文简介
以不定长字符流方式设计。

报文结构大致可理解为报文头+报文体,最小单位以“NAME:VALUE”对的型式, NAME、V ALUE都以各自的长度为前缀;一条典型的发送报文如下所示:
009MessageID:00574606:013TransactionID:005BOKFS:
003///:0011:003ROW:0011:003COL:0014:010Packeduser:003LHY:010packedtime:0192006-06-0 6 10:29:37:004flag:001Y:009accessory:0011:
003///:0012:003ROW:0011:003COL:0017:009IMPRESTNO:0130606163005721:008inittime:019 2006-06-16 15:30:04:009CompanyID:003ITC:
011Companytype:001A:009payamount:0041936:012actualamount:0041936:008category:006进帐单:003$$$
解析说明:
一条典型的返回报文如下所示:
009MessageID:00573936:013TransactionID:013COMSQL_SELECT:006Err_ID:003000:00 8Err_DESC:004正确:008Err_DESE:002OK:
003///:0011:003ROW:0013:003COL:0012:008CTN_TYPE:002GS:020CTN_TYPE_DESCR IPTION:009普通箱[3]:008CTN_TYPE:002TN:020CTN_TYPE_DESCRIPTION:006罐状箱:008CTN_TYPE:002UT:020CTN_TYPE_DESCRIPTION:006开顶箱:003$$$
★请解析说明?
注意:返回报文必须要带有错误信息Err_ID、Err_DESC、Err_DESE。

2>报文收发流程
3>发送接收报文关键函数介绍:
发送Select型简单Sql函数:
Send_ComSql_Select(const Comsql:string; //要发送的SQL查询语句
AForm:TForm; //当前发送的窗口
var ResultGrid:TstringGrid; //返回的错误信息(1行3列)
var ADASGrid: TDASG; //返回的查询结果集
const ExecuteNo:integer); // Execute () 执行序号
ResultGrid的结构:
一次发送多条Select型Sql函数:
Send_ComSql_Select(const Comsql: TDAS; //要发送的SQL查询语句(String数组)
AForm: TForm;
var ResultGrid: TstringGrid;
var ADASGrid: TDASG; //查询结果集(StringGrid数组)
const ExecuteNo: integer;
var ACmb_FieldName: TCombobox); // ComboBox可以不用
发送Update型简单Sql(执行update ,delete,insert类型的SQL语句):
Send_ComSql_Update(const Comsql:string;
AForm:TForm;
var ResultGrid:TstringGrid; //返回的错误信息(1行3列)000
const ExecuteNo:integer);
发送Transaction数据包(执行有事务性控制的交互如:存储过程、多表更新、批量更新)Send_Transaction_Package(const TransactionID: string; //交易ID
AForm: TForm; //当前发送的窗口
var ResultGrid: TstringGrid; // 返回的错误信息(1行3列)
var FdataGrid: TDASG; //返回的查询结果集
const ExecuteNo: integer; //Execute () 执行序号
const TransactionStr: string = 'Null'); //发送字符串(报文体)(从003///到003$$$的报文体)
发送Transaction数据包(不带结果集)
Send_Transaction_Package(const TransactionID: string;
AForm: TForm;
var ResultGrid: TstringGrid;
const ExecuteNo: integer;
const TransactionStr: string);
典型的Transaction介绍
TransactionID : COMSP (调用存储过程,使用第一种Send Transaction)
TransactionStr : 003///:0011:003ROW:0011:003COL:00213:
006SPNAME:025SP_SHP_TRANSRF_VESSELLIST:
005PARA1:001T:009PARA1TYPE:008V ARCHAR2:
005PARA2:003N/A:009PARA2TYPE:008V ARCHAR2:
005PARA3:005ERRID:009PARA3TYPE:008V ARCHAR2:
005PARA4:007ERRDESC:009PARA4TYPE:008V ARCHAR2:
005PARA5:007ERRDESE:009PARA5TYPE:008V ARCHAR2:
005PARA6:004DATA:009PARA6TYPE:004CLOB:
TransactionID : COMSQL_UPDATETRANS(多表/批量更新,使用第二种Send Transaction) TransactionStr : 003///:0011:003ROW:0013:003COL:0011:
009SQLUPDATE: [ Length + SQL ] :
009SQLUPDATE: [ Length + SQL ] :
009SQLUPDATE: [ Length + SQL ] :
把当前界面上Tag标记大于0的StringGrid内容组织成发送报文
FormSend (const Form1: TForm;
const De: boolean): string; // 返回组织好的发送报文(报文体)
接收返回数据函数
Execute(var ResultGrid: TStringGrid; // 对应的返回的错误信息集
var ADateGrid: TDASG; //对应的查询结果集(StringGrid数组)
const No: integer) // 执行序号
每个功能子窗体都应有此函数,声明成public ,供主窗体解析返回报文后调用;
4>代码命名规范
窗体名:必须以“Form”开头后跟该窗体功能的缩略英文描述
单元名:必须以“Unit”开头后跟窗体名(有窗体的)或功能的缩略英文描述常用控件名:必须前缀+”_”+缩略英文描述(前缀名见《Delphi 4 code chinese》)
5> 练习
说明:
完成对指定单表的增、删、改、查操作。

要求:
1.严格遵照编码设计规范命名。

2.灵活运用<3>中多种手段实现。

相关文档
最新文档