Socket编程(UDP),为何接收不到服务器返回结果 ( 积分: 100 )

  • 主题发起人 主题发起人 YinZu
  • 开始时间 开始时间
Y

YinZu

Unregistered / Unconfirmed
GUEST, unregistred user!
采用UDP通讯,服务器处于一个具有公网IP的环境中,
客户端在一个内网中,通过网关访问外网
如下方式:
Server S (18.181.0.31:1235)
|
|
|
NAT A (外网IP:202.187.45.3) 网关
|
|
Client A (192.168.100.20:4000)

在SERVER端起动一个SOCKET,监听客户端的请求,客户端发一个数据报文到SERVER,
当SERVER收到客户端的数据后经过处理给客户端返回一个结果。
现在我的情况,SERVER端能收到客户端的数据,也向客户端发出了返回结果,可客户
端无法接收到结果。

网上找到这样一文章《P2P之UDP穿透NAT的原理与实现》,以下是文章里部分内容,
本人也是按这样的思路去做的,为何客户端接收不到服务端返回结果,请高人给出
一点意见,谢谢!!
//========================================================================

Server S1
18.181.0.31:1235
|
^ Session 1 (A-S1) ^ |
| 18.181.0.31:1235 | |
v 155.99.25.11:62000 v |
|
NAT
155.99.25.11
|
^ Session 1 (A-S1) ^ |
| 18.181.0.31:1235 | |
v 10.0.0.1:1234 v |
|
Client A
10.0.0.1:1234
有一个私有网络10.*.*.*,Client A是其中的一台计算机,这个网络的网关(一个NAT设备)的外网IP是155.99.25.11(应该还有一个内网的IP地址,比如10.0.0.10)。如果Client A中的某个进程(这个进程创建了一个UDP Socket,这个Socket绑定1234端口)想访问外网主机18.181.0.31的1235端口,那么当数据包通过NAT时会发生什么事情呢?
首先NAT会改变这个数据包的原IP地址,改为155.99.25.11。接着NAT会为这个传输创建一个Session(Session是一个抽象的概念,如果是TCP,也许Session是由一个SYN包开始,以一个FIN包结束。而UDP呢,以这个IP的这个端口的第一个UDP开始,结束呢,呵呵,也许是几分钟,也许是几小时,这要看具体的实现了)并且给这个Session分配一个端口,比如62000,然后改变这个数据包的源端口为62000。所以本来是(10.0.0.1:1234->18.181.0.31:1235)的数据包到了互联网上变为了(155.99.25.11:62000->18.181.0.31:1235)。
一旦NAT创建了一个Session后,NAT会记住62000端口对应的是10.0.0.1的1234端口,以后从18.181.0.31发送到62000端口的数据会被NAT自动的转发到10.0.0.1上。(注意:这里是说18.181.0.31发送到62000端口的数据会被转发,其他的IP发送到这个端口的数据将被NAT抛弃)这样Client A就与Server S1建立以了一个连接。
//========================================================================
 
采用UDP通讯,服务器处于一个具有公网IP的环境中,
客户端在一个内网中,通过网关访问外网
如下方式:
Server S (18.181.0.31:1235)
|
|
|
NAT A (外网IP:202.187.45.3) 网关
|
|
Client A (192.168.100.20:4000)

在SERVER端起动一个SOCKET,监听客户端的请求,客户端发一个数据报文到SERVER,
当SERVER收到客户端的数据后经过处理给客户端返回一个结果。
现在我的情况,SERVER端能收到客户端的数据,也向客户端发出了返回结果,可客户
端无法接收到结果。

网上找到这样一文章《P2P之UDP穿透NAT的原理与实现》,以下是文章里部分内容,
本人也是按这样的思路去做的,为何客户端接收不到服务端返回结果,请高人给出
一点意见,谢谢!!
//========================================================================

Server S1
18.181.0.31:1235
|
^ Session 1 (A-S1) ^ |
| 18.181.0.31:1235 | |
v 155.99.25.11:62000 v |
|
NAT
155.99.25.11
|
^ Session 1 (A-S1) ^ |
| 18.181.0.31:1235 | |
v 10.0.0.1:1234 v |
|
Client A
10.0.0.1:1234
有一个私有网络10.*.*.*,Client A是其中的一台计算机,这个网络的网关(一个NAT设备)的外网IP是155.99.25.11(应该还有一个内网的IP地址,比如10.0.0.10)。如果Client A中的某个进程(这个进程创建了一个UDP Socket,这个Socket绑定1234端口)想访问外网主机18.181.0.31的1235端口,那么当数据包通过NAT时会发生什么事情呢?
首先NAT会改变这个数据包的原IP地址,改为155.99.25.11。接着NAT会为这个传输创建一个Session(Session是一个抽象的概念,如果是TCP,也许Session是由一个SYN包开始,以一个FIN包结束。而UDP呢,以这个IP的这个端口的第一个UDP开始,结束呢,呵呵,也许是几分钟,也许是几小时,这要看具体的实现了)并且给这个Session分配一个端口,比如62000,然后改变这个数据包的源端口为62000。所以本来是(10.0.0.1:1234->18.181.0.31:1235)的数据包到了互联网上变为了(155.99.25.11:62000->18.181.0.31:1235)。
一旦NAT创建了一个Session后,NAT会记住62000端口对应的是10.0.0.1的1234端口,以后从18.181.0.31发送到62000端口的数据会被NAT自动的转发到10.0.0.1上。(注意:这里是说18.181.0.31发送到62000端口的数据会被转发,其他的IP发送到这个端口的数据将被NAT抛弃)这样Client A就与Server S1建立以了一个连接。
//========================================================================
 
用一个现成的端口映射软件可能更方便一些:)
 
多谢china_delphi的回复,
现成的端口映射软件是不是不同客户端的网关处都有要安装,如果将来在不同局域网
有多个客户端,那样的话可能过于麻烦,没用过此类软件,能否讲解一下,
 
怎么没人回复了,请各位指点一下呀。
 
有没有你的代码,帖出来看看
 
程序总体构架很简单,在局域网中,用一台PC模拟成服务器,另一台为客户端,没有问题,
可在广域网中,把服务端程序放在具有公网IP的机器上,而客户端在一局域网中,通过网
关访问服务器,这时客户端就收不到服务端返回结果,本人断定,问题应该出在网关处,
网关没有把服务端返回的数据转发到客户端,端口映射出现了问题,不知是否是这样,请
各位给点意见,谢谢!


Server 端主要代码:采用Indy控件 TidUDPServer 控件名:UDPServer

procedure TFormMain.BtnStartClick(Sender: TObject);
begin
UDPServer.DefaultPort := 7648;
UDPServer.BufferSize := 8192;
UDPServer.Active := True;
end;

procedure TFormMain.UDPServerUDPRead(Sender: TObject; AData: TStream; ABinding: TIdSocketHandle);
var
DataStringStream: TStringStream;
RecvStr : string;
PeerIP : String;
PeerPort : integer;
strtmp: String;
protocol : string;
begin
DataStringStream := TStringStream.Create('');
try
DataStringStream.CopyFrom(AData, AData.Size);
RecvStr := Trim(DataStringStream.DataString);
PeerIP := ABinding.PeerIP;
PeerPort := ABinding.PeerPort;

protocol := copy(RecvStr,1,10);

// 接收到 Client 发来的数据
if protocol = 'C_GETS6513' then
begin
//
// 相应的处理....
//
ABinding.SendTo(PeerIP, PeerPort, strtmp[1], Length(strtmp));
end
else if protocol = 'C_DEL43218' then
begin
//
// 相应的处理....
//
ABinding.SendTo(PeerIP, PeerPort, strtmp[1], Length(strtmp));
end
//
//
// 其他的处理
//
//
else
begin
UDPMemo.Lines.Add('Receive unknow data');
strtmp := 'S_RESEND';
ABinding.SendTo(PeerIP, PeerPort, strtmp[1], Length(strtmp));
end;
finally
DataStringStream.Free;
end;

end;


Client 主要代码: 也采用Indy控件 TidUDPServer 控件名:UDPClient

procedure TFormLogin.FormCreate(Sender: TObject);
begin
UDPClient.DefaultPort := 7649;
UDPClient.BufferSize := 8192;
UDPClient.Active := True;
end;

procedure TFormLogin.btnOKClick(Sender: TObject);
var
Paswd : string;
strtmp : string;
begin
ServerIP := edtServerIP.Text;
ServerPort := 7648;

//
// 相应的处理
//
UDPClient.Send(ServerIP,ServerPort,strtmp);
end;

procedure TFormLogin.UDPClientUDPRead(Sender: TObject; AData: TStream; ABinding: TIdSocketHandle);
var
DataStringStream: TStringStream;
RecvStr : string;
protocol : string;
begin
DataStringStream := TStringStream.Create('');
try
DataStringStream.CopyFrom(AData, AData.Size);
RecvStr := Trim(DataStringStream.DataString);
protocol := copy(RecvStr,1,10);

if protocol = 'S_GETS6513' then
begin
//
//
//
end
else if
'
'
'
'
finally
DataStringStream.Free;
end;
end;
 
为何还没人给一个满意的回复,各位请帮忙呀
 
最大的可能原因是你不是电信的外网
 
不是电信的外网
这样也会导致这样的错误,能否讲解一下,多谢了!
 
比如广电的网络,广电解析IP方式和电信不一样,电信上网就有唯一IP分配给你(普通用户是动态IP),而广电是代理IP出去,SERVER返回的包,进入其DNS解析时,找不到出去的内网IP和端口的.总之就是广电的IP解析很落后.除非你的SERVER在广电的域名解析服务器上做了登记,他才会按公网IP的解析方式反向找到客户端
 
这么麻烦,怎样才能解决,有没有什么简单一些的方法
 
我对tcp/ip编程不熟,但是我也遇到了楼主同样的问题
 
我也想了解一下
 
多人接受答案了。
 
后退
顶部