Delphi的Indy ICMP封装在DLL之后 PING一个不存在的主机时程序会崩溃

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Delphi的Indy ICMP封装在DLL之后 PING一个不存在的主机时程序会崩溃相关的知识,希望对你有一定的参考价值。

function getIPAddress(sURL :PChar):PChar; stdcall;
var
ICMP:TIdIcmpClient;
R:TReplyStatus;
begin
ICMP:=TIdIcmpClient.Create(nil);
ICMP.ReceiveTimeout := 1000;
ICMP.Host := sURL;
try
ICMP.Ping;
R:=ICMP.ReplyStatus;
result:=PChar(Format('%d,',[R.MsRoundTripTime])+R.FromIpAddress);
// except
// ICMP.Free;
// result:='error';
finally
ICMP.free;
if result='' then result:='error';
end;
// ICMP.Free;
end;

代码是这样的,调用它ping一个存在的地址没问题,但是如果getIPAddress('aaaaa') 这个程序就会崩溃,请问该如何解决?

参考技术A 1、Indy是个很垃圾的玩意,这个错误是Indy控件本身的问题,你自身无法解决,除非自己写API或调用OCX控件。
2、你的函数本身也有问题,Dll里的字符串不能这样传递。你看看Windows的API函数就知道,没有一个是以PChar为返回值的(字符串函数除外)。你这个程序能正常运行,真是奇迹。
3、下面这个函数是我给你改的,sURL是地址;Buffer是一个缓冲区,用来接收IP地址;BufferLength是缓冲区长度,当Buffer为 nil 时它返回需要的空间大小;函数返回值为IP地址的长度。
function getIPAddress(sURL, Buffer: PChar; var BufferLength: Longint): Longint; stdcall;
var
ICMP: TIdIcmpClient;
R: TReplyStatus;
s: string;
begin
Result := 0;
ICMP := TIdIcmpClient.Create(nil);
ICMP.ReceiveTimeout := 1000;
ICMP.Host := sURL;
ICMP.Ping;
R := ICMP.ReplyStatus;
s := Format('%d,', [R.MsRoundTripTime]) + R.FromIpAddress;
if Buffer = nil then
BufferLength := Length(s) + 1
else begin
StrLCopy(Buffer, PChar(s), BufferLength - 1);
Result := StrLen(Buffer);
end;
ICMP.free;
end;
4、在主程序中,这个函数这样调用
var
len: Longint;
buf: PChar;
begin
getIPAddress(sURL, nil, len);
GetMem(buf, len);
getIPAddress(sURL, buf, len);
ShowMessage(buf);
FreeMem(buf);
end;本回答被提问者采纳

delphi indy10 无法接收中文

我用delphi XE的INDY10 TCP来写个简单的通信,不过发送中文字体在接收后会变成问号,
我在网上查了很多,好像是解码的问题。后来用流来做,可以接收中文不过发送文字后要断开一次才能接收到,我晕死。不知道要怎么做,哪位高手帮帮忙、。
例子如下
var
bufSend: TMemoryStream;
发送。。。。。
bufSend:=TMemoryStream.Create;
try
ClientLog.Lines.SaveToStream(bufSend);
IdTCPClient1.IOHandler.Write(bufSend); //发送流
finally
IdTCPClient1.Disconnect; //关闭连接
bufSend.Free;
end;

接收。。。
if Not(AContext.Connection.Connected) then Exit; //未连接时退出
bufRecv:=TMemoryStream.Create;
try
//一直接收 直到连接断开
while AContext.Connection.Connected do
begin
AContext.Connection.IOHandler.ReadStream(bufRecv, -1, True);
end;
//数据接收完毕
bufRecv.Seek(0, soFromBeginning);
ServerLog.Lines.LoadFromStream(bufRecv);
finally
bufRecv.Free;
IdTCPClient1.Connect;
end;

以我10年delphi经验来看,绝对不能用indy,这是一套华而不实,从头烂到脚的控件。编程的时候觉得还好,一旦实际使用,会发现根本无法胜任工作。只适合当当教学工具。

你要做发送和接收,给你推荐2个方法是我平常用的

1. 直接用api,网上有类似代码,阻塞模式很简单也很实用,要非阻塞就用线程。
2. 用自带的TServerSocket 和 TClientSocket,这套控件简单、实用。做简单的收发很有效。

中文乱码问题处理也很简单。
看你是用的什么编码类型,不要直接发送string,应该转换成连续内存块再发送。

Ansi、UTF8、Unicode,这些处理方式不一样
Ansi可以直接转换成pchar,
UTF8的话,要先用UTF8toString函数转换成Ansi,然后再转换成pchar发送
unicode也同样如此。

另外,你用的delphi版本也很重要,Delphi7以下的,只支持ansi,不用特别转换

从delphi2009开始,所有string都默认是unicode长度会有变化。

再者,我看到你的代码里面,发送和接收都没有实际长度,都是 -1,这是很不科学的做法。不能把长度交给系统去判断,这样只会是错误的。必须要提供实际的接收长度。只有这样才能避免被系统聪明的分包和组包。追问

弄了一个下午,成功的用了记录类型来发送和接收中文,然而看到你留言说INDY 是华而不实,从头烂到脚的控件,我感到真无语,我对INDY只认识了两天的时间,如果真像你说的这么不实用的话,那我确实应该换。你所说的2个方法,1是用自带的控件。这个我已经用过了。至于直接用API,我倒是有兴趣来学习。不知道你是否可以提供这方面的代码或者在网上要怎么查,用什么关键字才能查到此的例子.谢谢

追答

用记录类型是个通用方法,和我说的转换成pchar是一样的。google上搜 delphi socket 就能搜到很多。

indy会让你的传输产生莫名其妙的错误,根本找不到原因,而且内存管理一塌糊涂,线程同步也做得一团糟,稍微多点连接就崩溃了

追问

哈哈,你回得太慢了,你说的我都做了。SOCKET API 也做了个简单的通信

追答

做了就赶快结贴了

参考技术A encrystrhex() 加密,接收过来再解密。 参考技术B 找微软问问 参考技术C 转别人的
delphi2010以上版本字符串中的汉字用length获取的长度每个汉字是1,而delphi7中用length获取的长度每个汉字是2,参考如下一个newstr转换函数,通过字符串流StringStream,转换为正常显示汉字字符串。

function newstr(oldstr:string):string;
var
stream: TStringStream;
i:integer;
begin
stream := TStringStream.Create;
stream.Size := length(oldstr);
for I := 1 to length(oldstr) do
stream.Bytes[i-1] := ord(char(oldstr[i])) ;
newstr:=stream.DataString;
stream.Free;
end;

以上是关于Delphi的Indy ICMP封装在DLL之后 PING一个不存在的主机时程序会崩溃的主要内容,如果未能解决你的问题,请参考以下文章

delphi 如何用ssleay32.dll

Delphi 中的DLL 封装和调用对象技术(刘艺,有截图)

delphi indy10 无法接收中文

delphi 7 下安装 indy 10.5.8 教程

在 Delphi 2009 中逐步升级 Indy 10

使用Delphi创建的DLL在其他Delphi版本中运行良好,应该遵循哪些原则?