socket编程中常用函数,TcpSocket编程之Delphi与其他语言的字符串通信
socket编程中常用函数,TcpSocket编程之Delphi与其他语言的字符串通信连接按钮单击事件代码:界面中控件的设置就不再赘述,主要代码为连接按钮单击事件、发送按钮单击事件、接收线程。服务端采用 Python 语言的 Twisted 框架来开发,具体 Twisted 框架的工作原理在此不做赘述,代码如下:# coding: utf-8 from twisted.internet.Protocol import Protocol from twisted.internet.protocol import Factory from twisted.internet.endpoints import TCP4ServerEndpoint from twisted.internet import reactor class Device(Protocol): def connectionMade(self): print('Connecte
关键字:Tcp Scoket、Delphi、Indy、Python、Twisted
对于 Tcp Socket 编程,异种语言之间的通信在日常开发中经常会用到。今天,我们通过 Delphi 和 Python 语言来做一个 Socket 通信的示例。通信数据采用字符串形式来直接传输。
客户端:Delphi、Indy
服务端:Python、Twisted
7.1 服务端编程服务端采用 Python 语言的 Twisted 框架来开发,具体 Twisted 框架的工作原理在此不做赘述,代码如下:
# coding: utf-8
from twisted.internet.Protocol import Protocol
from twisted.internet.protocol import Factory
from twisted.internet.endpoints import TCP4ServerEndpoint
from twisted.internet import reactor
class Device(Protocol):
def connectionMade(self):
print('Connected from %s:%s.' % (self.transport.getPeer().host self.transport.getPeer().port))
self.transport.write('$Welcome!$'.encode('utf-8'))
def connectionLost(self reason):
print('Disconnected from %s:%s.' % (self.transport.getPeer().host self.transport.getPeer().port))
print(reason)
def dataReceived(self data):
print('Recieved from %s:%s.' % (
self.transport.getPeer().host self.transport.getPeer().port))
s = data.decode('utf-8')
print(s)
self.transport.write('$OK!$'.encode('utf-8'))
class DeviceFactory(Factory):
def buildProtocol(self addr):
print(addr) # addr为创建连接时客户端的地址
return Device()
endpoint = TCP4ServerEndpoint(reactor 9123)
endpoint.listen(DeviceFactory())
reactor.run()
代码中字符串的开头和结尾的 ”$“ 字符是数据传输的开始和结束标志。
7.2 客户端编程客户端采用 CodeTyphon 来开发,组件采用 Indy,界面如下:
界面中控件的设置就不再赘述,主要代码为连接按钮单击事件、发送按钮单击事件、接收线程。
连接按钮单击事件代码:
procedure TForm1.ConnectButtonClick(Sender: TObject);
begin
if HostEdit.Text = '' then
begin
Application.MessageBox('请设置地址!' '提示');
Exit;
end;
IdTCPClient.Host:=HostEdit.Text;
IdTCPClient.Port:=PortSpinEdit.Value;
IdTCPClient.Connect;
if IdTCPClient.Connected then
begin
Application.MessageBox('连接成功!' '提示');
ConnectButton.Enabled:=False;
DisconnectButton.Enabled:=True;
// 启动读取线程
ReadThread:=TReadThread.Create(True);
ReadThread.FreeOnTerminate:=True;
ReadThread.Start;
end
else
begin
Application.MessageBox('连接失败!' '提示');
end;
end;
发送按钮单击事件代码:
procedure TForm1.SendButtonClick(Sender: TObject);
var
s: String;
begin
if Trim(SendEdit.Text) = '' then
begin
Application.MessageBox('请输入要发送的内容!' '提示');
Exit;
end;
s:='$' SendEdit.Text '$';
IdTCPClient.IOHandler.Write(s);
RecievedMemo.Lines.Add('发送:' s);
SendEdit.Text:='';
end;
在字符串传输时,可以直接使用 IdTCPClient.IOHandler.Write 过程发送字符串数据,字符串的开头和结尾的 ”$“ 字符是数据传输的开始和结束标志。
接收线程代码:
unit unitreadthread;
{$mode ObjFPC}{$H }
interface
uses
Classes SysUtils IdGlobal;
type
TReadThread = class(TTHread)
private
protected
procedure Execute; Override;
end;
implementation
uses unitmain;
procedure TReadThread.Execute;
var
s: String;
begin
while not Self.Terminated do
begin
if not Form1.IdTCPClient.Connected then
Self.Terminate
else
try
// ReadLn
s:=Form1.IdTCPClient.IOHandler.ReadLn;
Form1.RecievedMemo.Lines.Add(s);
except
end;
end;
end;
end.
在 Delphi 中接收服务端传输的字符串可以使用 IdTCPClient.IOHandler.ReadLn 函数,其读取的结果为字符串,也可以使用先读取字节码,然后转换成字符串,代码如下:
procedure TReadThread.Execute;
var
s: String;
bytes: TIdBytes;
begin
while not Self.Terminated do
begin
if not Form1.IdTCPClient.Connected then
Self.Terminate
else
try
// ReadBytes
Form1.IdTCPClient.IOHandler.ReadBytes(bytes -1 False);
s:=BytesToString(bytes);
Form1.RecievedMemo.Lines.Add('收到:' s.Split('$')[1]);
except
end;
end;
end;
ReadBytes 过程的原型:
procedure ReadBytes(
var VBuffer: TIdBytes;
AByteCount: Integer;
AAppend: boolean = true
); virtual;
说明:
ReadBytes是一个虚拟过程,用于执行IOHandler的读取请求。
VBuffer是用于存储从IOHandler连接的数据源读取的值的变量参数。
AByteCount表示读取请求所需的字节值数。当AByteCount包含0(零)时,不会从IOHandler的数据源读取任何数据。当AByteCount包含-1时,将从数据源读取数据,直到断开连接或超过ReadTimeout值。
ReadBytes从IOHandler数据源读取数据,直到InputBuffer中累积了AByteCount中的字节数,或者CheckForDisconnect中断读取请求。
成功完成读取请求后,将值从InputBuffer提取到VBuffer中。
AAppend指示从输入缓冲区提取的值应附加到VBuffer中的现有数据。当AAppend为False时,在从InputBuffer提取数据期间,将丢弃VBuffer中的任何值。
由于我们事先不知道服务端传输的字符串长度,所以读取字节时参数 AByteCount 取值为 -1,同时将参数 AAppend 设置为 false,如果设置为 True,则会在 InputBuffer 中追加数据,这样每次取到的数据就包含前面传输的数据。
7.3 小结:
字符串数据传输:
发送字符串 |
IdTCPClient.IOHandler.Write |
接收字符串 |
IdTCPClient.IOHandler.ReadLn |
IdTCPClient.IOHandler.ReadBytes(bytes -1 False); s:=BytesToString(bytes); |