J
jamjar
Unregistered / Unconfirmed
GUEST, unregistred user!
网络上有很多关于穿透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包
请大侠指教,这会是什么问题。我已经倾我所有的分数了
我下载了一位前辈的实现这个原理代码,可是很奇怪的是:
相同的网络环境,有时候可以通,有时候又不通。客户端代码片断如下:
发送消息:
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包
请大侠指教,这会是什么问题。我已经倾我所有的分数了