如何处理TCPClient中收到的数据? (Delphi – Indy)
当我从TCPClient发送消息到TCPServer时,它将使用服务器中的OnExecute事件处理.现在我想处理客户端中收到的消息,但TCPClient没有任何事件.所以我必须做一个线程来手动处理它们.我该怎么做 ?
解决方法
正如其他人所说的回应你的问题,TCP不是面向消息的协议,而是一个流.我会告诉你如何写和阅读一个非常简单的回显服务器(这是一个稍微修改版本的服务器我本周做的回答其他问题)
服务器OnExecute方法如下所示: procedure TForm2.IdTCPServer1Execute(AContext: TIdContext); var aByte: Byte; begin AContext.Connection.IOHandler.Writeln('Write anything,but A to exit'); repeat aByte := AContext.Connection.IOHandler.ReadByte; AContext.Connection.IOHandler.Write(aByte); until aByte = 65; AContext.Connection.IOHandler.Writeln('Good Bye'); AContext.Connection.Disconnect; end; 该服务器以欢迎消息开始,然后只读取每个字节的连接字节.服务器回复相同的字节,直到收到的字节为65(断开命令)65 = 0x41或$41.然后服务器以一个好的再见消息结束. 您可以在客户端执行此操作: procedure TForm3.Button1Click(Sender: TObject); var AByte: Byte; begin IdTCPClient1.Connect; Memo1.Lines.Add(IdTCPClient1.IOHandler.ReadLn); //we know there must be a welcome message! Memo1.Lines.Add('');// a new line to write in! AByte := 0; while (IdTCPClient1.Connected) and (AByte <> 65) do begin AByte := NextByte; IdTCPClient1.IOHandler.Write(AByte); AByte := IdTCPClient1.IOHandler.ReadByte; Memo1.Lines[Memo1.Lines.Count - 1] := Memo1.Lines[Memo1.Lines.Count - 1] + Chr(AByte); end; Memo1.Lines.Add(IdTCPClient1.IOHandler.ReadLn); //we know there must be a goodbye message! IdTCPClient1.Disconnect; end; 下一个字节的过程可以是您要提供的任何字节.例如,要从用户获取输入,您可以将窗体的KeyPreview转换为true,并写入OnKeyPress事件处理程序和NextByte函数,如下所示: procedure TForm3.FormKeyPress(Sender: TObject; var Key: Char); begin FCharBuffer := FCharBuffer + Key; end; function TForm3.NextByte: Byte; begin Application.ProcessMessages; while FCharBuffer = '' do //if there is no input pending,just waint until the user adds input begin Sleep(10); //this will allow the user to write the next char and the application to notice that Application.ProcessMessages; end; Result := Byte(AnsiString(FCharBuffer[1])[1]); //just a byte,no UnicodeChars support Delete(FCharBuffer,1,1); end; 用户在表单中写入的内容将被发送到服务器,然后从那里读取并添加到备忘录1.如果输入焦点已经在Memo1中,您将看到每个字符两次,一个来自键盘,另一个来自服务器. 因此,为了编写一个从服务器获取信息的简单客户端,您必须知道服务器的期望.是字符串吗?多个字符串?整数?阵列?一个二进制文件?编码文件?连接的结束是否有标记?如果您正在创建一个自定义服务器/客户端对,这些东西通常在协议或您定义. 要编写一个通用的TCP,而不必事先知道从服务器获取什么可能,但是复杂的是由于在协议层次上没有通用的消息抽象. 不要因为传输消息而感到困惑,但单个服务器响应可以分为几个传输消息,然后重新组合客户端,您的应用程序不会控制这一点.从应用的角度来看,套接字是传入字节的流(流).您将此解释为邮件,命令或来自服务器的任何类型的响应的方式取决于您.同样适用于服务器端…例如,onExecute事件是一个白皮书,您也没有消息抽象. 也许你正在将消息抽象与命令抽象混合在基于命令的协议上,客户端发送包含命令的字符串,服务器回复包含响应的字符串(然后可能是更多的数据).看看TIdCmdTCPServer / Client组件. 编辑 在评论OP中,他/他希望通过一个线程来完成这项工作,我不知道他/他有什么问题,但我在添加一个线程示例.服务器与之前所示的相同,只是这个简单服务器的客户端部分: 首先,我使用的线程类: type TCommThread = class(TThread) private FText: string; protected procedure Execute; override; //this will hold the result of the communication property Text: string read FText; end; procedure TCommThread.Execute; const //this is the message to be sent. I removed the A because the server will close //the connection on the first A sent. I'm adding a final A to close the channel. Str: AnsiString = 'HELLO,THIS IS _ THRE_DED CLIENT!A'; var AByte: Byte; I: Integer; Client: TIdTCPClient; Txt: TStringList; begin try Client := TIdTCPClient.Create(nil); try Client.Host := 'localhost'; Client.Port := 1025; Client.Connect; Txt := TStringList.Create; try Txt.Add(Client.IOHandler.ReadLn); //we know there must be a welcome message! Txt.Add('');// a new line to write in! AByte := 0; I := 0; while (Client.Connected) and (AByte <> 65) do begin Inc(I); AByte := Ord(Str[I]); Client.IOHandler.Write(AByte); AByte := Client.IOHandler.ReadByte; Txt[Txt.Count - 1] := Txt[Txt.Count - 1] + Chr(AByte); end; Txt.Add(Client.IOHandler.ReadLn); //we know there must be a goodbye message! FText := Txt.Text; finally Txt.Free; end; Client.Disconnect; finally Client.Free; end; except on E:Exception do FText := 'Error! ' + E.ClassName + '||' + E.Message; end; end; 然后,我将这两个方法添加到窗体中: //this will collect the result of the thread execution on the Memo1 component. procedure TForm3.AThreadTerminate(Sender: TObject); begin Memo1.Lines.Text := (Sender as TCommThread).Text; end; //this will spawn a new thread on a Create and forget basis. //The OnTerminate event will fire the result collect. procedure TForm3.Button2Click(Sender: TObject); var AThread: TCommThread; begin AThread := TCommThread.Create(True); AThread.FreeOnTerminate := True; AThread.OnTerminate := AThreadTerminate; AThread.Start; end; (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |