当前位置:主页>仓库管理软件> 列表

倾我所有请教:UDP 打洞的原理是对的,为什么实现起来总是 找仓库软件免费版

记账软件版1楼: 网络上有很多关于穿透NAT的文章,很多是关于UDP打洞的。
我下载了一位前辈的实现这个原理代码,可是很奇怪的是:
相同的网络环境,有时候可以通,有时候又不通。客户端代码片断如下:
发送消息:
function SendMessageTo(pSendName: pchar; pInfo: Pointer; size: integer): BOOL;
begin
for i := 0 to MAXRETRY do
begin
RecvedACK := false;
remoteAddr.sin_addr.S_addr := htonl(UserIP);
remoteAddr.sin_family := AF_INET;
remoteAddr.sin_port := htons(UserPort);
MessageHead.ord := oP2PMESSAGE;
MessageHead.iStringLen := size;
strcopy(MessageHead.Sender, userName);
err := sendto(sock, MessageHead, SizeOf(MessageHead), 0, remoteAddr, SizeOf(remoteAddr));
sendto(sock, pInfo^, MessageHead.iStringLen, 0, remoteAddr, SizeOf(remoteAddr));
// 等待接收线程将此标记修改
for j := 0 to 10 do
begin
if (RecvedACK) then
begin
result := True;


exit;
end else
Sleep(300);
end; //for
// 没有接收到目标主机的回应,认为目标主机的端口映射没有
// 打开,那么发送请求信息给服务器,要服务器告诉目标主机
// 打开映射端口(UDP打洞)
serverAddr.sin_addr.S_addr := Inet_addr(svrIP);
serverAddr.sin_family := AF_INET;
serverAddr.sin_port := htons(SERVER_PORT);
transMessage.ord := oP2PTRANS;
strcopy(transMessage.msg.translatemessage.userName, pSendName);
sendto(sock, transMessage, SizeOf(transMessage), 0, serverAddr, SizeOf(serverAddr));
Sleep(500); // 等待对方先发送信息。
end; //for
end;
接收线程代码
while True do
begin
err := recvfrom(sock, recvbuf, SizeOf(recvbuf), 0, remoteAddr, addrLen);
if err <= 0 then continue;
pData := nil;
recvtype := -100;
case recvbuf.ord of
oP2PMESSAGE:
begin
getmem(pInfo, recvbuf.iStringLen);


err := recvfrom(sock, pInfo^, recvbuf.iStringLen, 0, remoteAddr, addrLen);
if err <= 0 then continue;
pData := pInfo;
recvtype := 1;
recvsize := recvbuf.iStringLen;
sendbuf.ord := oP2PMESSAGEACK;
sendto(sock, sendbuf, SizeOf(sendbuf), 0, remoteAddr, addrLen);
//freemem(pInfo);
//break;
end; //oP2PMESSAGE接收到P2P的消息
oP2PSOMEONEWANTTOCALLYOU://收到服务器要求向某个客户端打洞的消息
begin
remoteAddr.sin_addr.S_addr := htonl(recvbuf.iStringLen);
remoteAddr.sin_family := AF_INET;
remoteAddr.sin_port := htons(recvbuf.port);
sendbuf.ord := oP2PTRASH;
sendto(sock, sendbuf, SizeOf(sendbuf), 0, remoteAddr, SizeOf(remoteAddr));
//break;
end; //接收到打洞命令,向指定的IP地址打洞
oP2PMESSAGEACK:
begin
RecvedACK := True;
end; // 发送消息的应答
...........
..............
还有一个问题:有资料上说,为了保持NAT给应用程序分配的UDP端口不被回收,应该让应用程序定时地向NAT给自己分配的地址和端口发包。
例如:CA的LAN地址是192.168.0.3:1234 经过NAT后变成218.66.101.35:8666,那么CA应该定时向218.66.101.35:8666发送UDP包来保持这个
8666的端口。但是我按照这样做只好,发现CA并不能收到这个包
while true do
begin
err := sendto(sock, msg, SizeOf(msg), 0, remoteAddr, addr);//跟踪发现err>0
Sleep(3000);
end;
有没有什么工具可以知道NAT是否抛弃了那些UDP包
请大侠指教,这会是什么问题。我已经倾我所有的分数了

2楼: 不太明白你的思路, 不过有一个您似乎弄错了
sendto 成功时返回发出的字节数, 失败返回-1 如用友财务软件

3楼: 楼上的,我的意思就是我的sendto成功了,但是收不到这个消息

4楼: UDP本来就是不可靠的, sendto成功了,对方也可能没有收到这个数据包

5楼: 我是一个循环来发,难道都收不到吗。

6楼: 基本思路是这样的
1:客户端(A)直接向对方(B)的目的地址和端口发送包。
2:如果收到B的回答(RecvdASK=true),就算成功了。
3:如果没有收到B的回答(recvedASK=false),那么就给服务器发个请求包。
这个包里有B的信息。服务器给B发包,要求B给A发一个包(也就是打洞)。
按照原理,B的NAT上将打开一个通道,让A发送的包进来。
4:此时A发的包,B就能收到了

记账软件版7楼: jamjar, 真是太谢谢你的提示.

8楼: 这个是服务端出来打洞的代码
oP2PTRANS:
begin
for i := 0 to clientList.Count - 1 do
begin
pUserListNode := clientList.Items[i];
if strcomp(pUserListNode^.UserName, Buf.msg.translatemessage.UserName) = 0 then break;
end; //for
remoteAddr.sin_family := AF_INET;
remoteAddr.sin_port := htons(pUserListNode^.port);
remoteAddr.sin_addr.s_addr := htonl(pUserListNode^.ip);
transMessage.ord := oP2PSOMEONEWANTTOCALLYOU;


transMessage.iStringLen := ntohl(SenderAddr.sin_addr.s_addr);
transMessage.port := ntohs(SenderAddr.sin_port);
sendto(sock, transMessage, sizeof(transMessage), 0, remoteAddr, addrLen);
//break;
end; //oP2PTRANS // 某个客户希望服务端向另外一个客户发送一个打洞消息

9楼: 运行后,出现的情况是
如果A向B发送消息,
那么B可以收到服务器发来的要求B向A打洞的消息,但是无法收到A的消息

10楼: 帮你顶,关注中....^_^

11楼: 打洞裡有漏洞

12楼: 楼上说的是啥意思,麻烦说明白,心里急啊 如仓库软件免费版

13楼: 主要是电信的问题,临时端口有可能被电信的路由器给丢掉,因此加个监测过程,发现端口改变就通过服务器通知对方改变端口。