对TServerSocket实行IP绑定之一(辗转方式,只用于演示,除非必要不推荐使用)
来源:互联网 发布:索尼爱立信w980 软件 编辑:程序博客网 时间:2024/04/29 06:58
BDS(Delphi/C++Builder)当中的TServerSocket估计是基于简单应用或者学习的目的考虑,所以直接就绑定了泛地址,而不支持针对性的IP地址绑定,这也就使得一些特殊的环境让人感觉有点不舒服,甚至有点无奈。本文就简单介绍一种“曲线破解”法来解决这个绑定的问题。本示例主要是基于BDS2007的TServerSocket,其它版本请根据实际情况进行调整未必都能实现。
//简单演示
unit Unit3;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ScktComp, StdCtrls;
type
TForm3 = class(TForm)
Button1: TButton;
ServerSocket1: TServerSocket;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
FBindAddr: String;
OldSocketEvent: TSocketEventEvent;
procedure ServerSocketEvent(Sender: TObject; Socket: TCustomWinSocket;
SocketEvent: TSocketEvent);
public
{ Public declarations }
property Address: String read FBindAddr write FBindAddr;
end;
var
Form3: TForm3;
implementation
Uses
Winsock;
{$R *.dfm}
function IsIP(const AHost:String):Boolean;
var
iLen
, I
, TestDigit
, DotCount: Integer;
TestIP: String;
begin
Result := false;
TestIP := AHost + '.';
iLen := Length(AHost);
if(iLen<7) or (iLen>15) then Exit;
TestDigit := 0;
DotCount := 0;
for i := 1 to iLen + 1 do
begin
if(((TestIP[i] < '0') or (TestIP[i] > '9')) and ((TestIP[i] <> '.') or (i = 0))) then Exit;
if(TestIP[i] = '.') then
begin
if (TestDigit > 255) or (TestDigit < 0) then Exit;
if(TestIP[i-1] = '.') then Exit;
TestDigit := 0;
Inc(DotCount);
end
else
TestDigit := TestDigit * 10 + (ord(TestIP[i]) - 48);
end;
Result := DotCount = 4;
end;
function LocalGetHostByName(const AHost:String):String;
var
WSAData: TWSADATA;
Host: PHostEnt;
begin
Result := AHost;
if(WSAStartup(MakeWord(1,1), WSAData) <> 0) then Exit;
try
Host := gethostbyname(PChar(AHost));
Result := IntToStr(Byte(Host^.h_addr_list^[0])) + '.' +
IntToStr(Byte(Host^.h_addr_list^[1])) + '.' +
IntToStr(Byte(Host^.h_addr_list^[2])) + '.' +
IntToStr(Byte(Host^.h_addr_list^[3]));
if Not IsIP(Result) then Result:=AHost;
finally
WSACleanup;
end;
end;
function ResolveHost(const AHost: String): String;
begin
Result := AHost;
if AnsiSameText(AHost, 'LOCALHOST') or AnsiSameText(AHost, '(Local)') or AnsiSameText(AHost, '.') then // this computer
Result := '127.0.0.1'
else if Not IsIP(Result) then
Result := LocalGetHostByName(AHost);
end;
//拦载LookupState为lsIdle状态,替代为 lsLookupAddress,从而使用自定义的地址替代原来的INADDR_ANY
procedure TForm3.ServerSocketEvent(Sender: TObject; Socket: TCustomWinSocket;
SocketEvent: TSocketEvent);
var
Addr: TSockAddrIn;
LookupState: TLookupState;
begin
case SocketEvent of
seLookup:
begin
if Socket.LookupState = lsIdle then
begin
if FBindAddr <> '' then //Hack Bind Address
begin
Addr := Socket.Addr;
Addr.sin_addr.S_addr := inet_addr(PChar(ResolveHost(FBindAddr)));
LookupState := lsLookupAddress;
move( PChar(@Addr)^,
PChar( Integer(Socket) //首地址 (4字节对齐)
+ sizeof(Pointer) //虚函数表
+ sizeof(TSocket)//FSocket: TSocket; //占4字节
+ sizeof(Pointer)//FConnected: Boolean; //注意字节对齐,由于后续为4字节,虽只有1字节,但是占4字节
+ sizeof(TStream)//FSendStream: TStream; //占4字节
+ sizeof(Pointer)//FDropAfterSend: Boolean; //注意字节对齐,由于后续为4字节,虽只有1字节,但是占4字节
+ sizeof(HWnd)//FHandle: HWnd; //占4字节
)^,
sizeof(TSockAddrIn));
move( PChar(@LookupState)^,
PChar( Integer(Socket)
+ sizeof(Pointer)
+ sizeof(TSocket)//FSocket: TSocket;
+ sizeof(Pointer)//FConnected: Boolean; //注意字节对齐
+ sizeof(TStream)//FSendStream: TStream;
+ sizeof(Pointer)//FDropAfterSend: Boolean; //注意字节对齐
+ sizeof(HWnd)//FHandle: HWnd;
+ sizeof(TSockAddrIn)//FAddr: TSockAddrIn;
+ sizeof(TASyncStyles)//FAsyncStyles: TASyncStyles; //注意字节对齐
)^,
sizeof(TLookupState));
end;
end;
end;
end;
OldSocketEvent(Sender,Socket,SocketEvent);
end;
procedure TForm3.Button1Click(Sender: TObject);
begin
ServerSocket1.Open;
end;
procedure TForm3.FormCreate(Sender: TObject);
begin
ServerSocket1.Port := 9999;
Address := '192.168.10.121';
OldSocketEvent := ServerSocket1.Socket.OnSocketEvent;
ServerSocket1.Socket.OnSocketEvent := ServerSocketEvent;
if ServerSocket1.Active then
begin
ServerSocket1.Close;
ServerSocket1.Active := False;
end;
end;
end.
- 对TServerSocket实行IP绑定之一(辗转方式,只用于演示,除非必要不推荐使用)
- 对TServerSocket实行IP绑定之二(继承方式,只用于演示,除非必要不推荐使用)
- 为什么 接口只用于定义类型,不应该使用常量接口 ?
- 字符谜题之6还是关于unicode转义字符:除非必要,不要使用Unicode转义字符
- TServerSocket和TClientSocket的使用
- TServerSocket和TClientSocket的使用
- nginx中对指定的IP不使用密码对区域外IP使用密码访问
- 转载(只用于学习)
- p->a[只用于指针]
- keepalived 只用于心跳测试
- 接口只用于定义类型。
- 接口只用于定义类型。
- SpringMVC的参数绑定方式之一
- android应用程序对System.gc()的使用必要
- 下载使用ip绑定测试
- 简述基于V4L2驱动框架的UVC摄像头驱动(只用于获取数据,不具备控制功能)
- 版本控制案例之一使用win32svn简单搭建svn服务器(svn://ip/projectName方式)
- 只用于块级元素的css
- String类和StringBuffer类的区别
- GAE(Google App Engine Datastore API)翻译(2)
- CScrollBar控件的使用方法:
- C/C++返回内部静态成员的陷阱
- Building a Master Image - Part 1: VMware
- 对TServerSocket实行IP绑定之一(辗转方式,只用于演示,除非必要不推荐使用)
- CListCtrl的简单使用 Zz
- 现代企业信息化的设计原则
- Building A Master Image - Part 2: Preparing Windows XP
- 中国的大学生很累
- Apache与IIS共存80端口
- C语言系列--内存管理
- TimerTask在遇到修改系统时间不能正常工作,自己写一个简单的TimerTask和Timer
- 对TServerSocket实行IP绑定之二(继承方式,只用于演示,除非必要不推荐使用)