// 接收到打洞命令,向指定的IP地址打洞
printf("Recv p2someonewanttocallyou from %s:%ld\n", inet_ntoa( remote.sin_addr), htons(remote.sin_port) ); sockaddr_in remote;
remote.sin_addr.S_un.S_addr = htonl(recvbuf.iStringLen);
remote.sin_family = AF_INET;
remote.sin_port = htons(recvbuf.Port); // UDP hole punching
stP2PMessage message;
message.iMessageType = P2PTRASH;
sendto(PrimaryUDP, (const char *)&message, sizeof(message), 0, (const sockaddr*)&remote, sizeof(remote));
printf("Send p2ptrash to %s:%ld\n", inet_ntoa( remote.sin_addr), htons(remote.sin_port) );
break;关键是:sendto这行 需要实现 打通 端口参考文章:
http://www.ppcn.net/n1306c2.aspx
printf("Recv p2someonewanttocallyou from %s:%ld\n", inet_ntoa( remote.sin_addr), htons(remote.sin_port) ); sockaddr_in remote;
remote.sin_addr.S_un.S_addr = htonl(recvbuf.iStringLen);
remote.sin_family = AF_INET;
remote.sin_port = htons(recvbuf.Port); // UDP hole punching
stP2PMessage message;
message.iMessageType = P2PTRASH;
sendto(PrimaryUDP, (const char *)&message, sizeof(message), 0, (const sockaddr*)&remote, sizeof(remote));
printf("Send p2ptrash to %s:%ld\n", inet_ntoa( remote.sin_addr), htons(remote.sin_port) );
break;关键是:sendto这行 需要实现 打通 端口参考文章:
http://www.ppcn.net/n1306c2.aspx
http://2ccc.com/article.asp?articleid=1993
function UDPsend(s: TSocket; var Buf; len, flags: Integer; var addrto: TSockAddr;
tolen: Integer): Integer;
var
echo:integer;
begin
result:=sendto(s,Buf,len,flags,addrto,tolen);
recvfrom(s,echo,4,0,addrto,tolen);
end;
function UDPrecv(s: TSocket; var Buf; len, flags: Integer;
var from: TSockAddr; var fromlen: Integer): Integer;
var
echo:integer;
begin
result:=recvfrom(s,Buf,len,flags,from,fromlen);
echo:=88;
sendto(s,echo,4,0,from,fromlen);
end;
function SendMessageTo(pSendName,pInfo:pchar):bool;
var
realmessage:string[255];
UserIP:dword;
UserPort:dword;
FindUser:boolean;
i,j:integer;
remoteAddr,serverAddr:sockaddr_in;
MessageHead:_stP2PMessage;
transMessage:_stMessage;
begin
result:=false;
FindUser:=false;
for i:=0 to clientList.Count-1 do
begin
pUserListNode:=clientList.Items[i];
if strcomp(pUserListNode^.userName,pSendName)=0 then
begin
UserIP := pUserListNode^.ip;
UserPort := pUserListNode^.port;
FindUser := true;
break;
end;
end;//for
if not FindUser then exit;
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:=strlen(pInfo);
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(ServerIP);
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(100);// 等待对方先发送信息。 end;//for
end;
procedure ParseCommand(const ord:string);
var
sendbuf:_stMessage;
serverAddr:sockaddr_in ;
command:integer;
begin
if ord='exit' then
begin
sendbuf.ord:=oLOGOUT;
strcopy(sendbuf.msg.logoutmember.userName, UserName);
serverAddr.sin_addr.S_addr:= inet_addr(ServerIP);
serverAddr.sin_family := AF_INET;
serverAddr.sin_port := htons(SERVER_PORT);
sendto(sock,sendbuf,sizeof(sendbuf), 0,serverAddr, sizeof(serverAddr));
shutdown(sock,2);
closesocket(sock);
exit;
end;//exit;
if ord='send' then
begin
SendMessageTo(@sendname,@Info);
end;
if ord='getu' then
begin
command:=integer(oGETALLUSER);
serverAddr.sin_addr.S_addr := inet_addr(ServerIP);
serverAddr.sin_family := AF_INET;
serverAddr.sin_port := htons(SERVER_PORT);
sendto(sock,command, sizeof(integer), 0,serverAddr, sizeof(serverAddr));
end;
end;
procedure RecvThreadProc();stdcall;
var
remoteAddr:sockaddr_in;
recvbuf,sendbuf:_stP2PMessage;
err,i:integer;
pInfo:pchar;
//Info:string;
begin
//addrLen:=sizeof(sockaddr_in);
while true do
begin
sendmessage(hform,0,0,0);
err:=recvfrom(sock, recvbuf, sizeof(recvbuf), 0, remoteAddr, addrLen);
if err<=0 then continue;
case recvbuf.ord of
oP2PMESSAGE:
begin
getmem(pInfo,recvbuf.iStringLen);
err:=recvfrom(sock, pInfo^, recvbuf.iStringLen, 0, remoteAddr, addrLen);
if err<=0 then continue;
//显示信息******************************************
std.ord:=oP2PMESSAGE;
std.port:=remoteAddr.sin_port;
strcopy(std.Ip,inet_ntoa(remoteaddr.sin_addr));
strcopy(std.text,pInfo);
sendmessage(hform,wm_Recv,0,0);
//Info:=pInfo^;
//**************************************************
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;
//显示信息******************************************
std.ord:=oP2PSOMEONEWANTTOCALLYOU;
std.port:=recvbuf.Port;
strcopy(std.Ip,inet_ntoa(remoteAddr.sin_addr));
sendmessage(hform,wm_Recv,0,0);
//strcopy(std.text,pInfo^);
//Info:=pInfo^;
//**************************************************
sendto(sock, sendbuf, sizeof(sendbuf), 0, remoteAddr, sizeof(remoteAddr));
//break;
end;//接收到打洞命令,向指定的IP地址打洞
oP2PMESSAGEACK:
begin
RecvedACK := true;
//显示信息******************************************
std.ord:=oP2PMESSAGEACK;
//std.port:=remoteAddr.sin_port;
//strcopy(std.Ip,inet_ntoa(remoteaddr.sin_addr));
strcopy(std.text,'发送消息的应答');
sendmessage(hform,wm_Recv,0,0);
//Info:=pInfo^;
//**************************************************
//break;
end;// 发送消息的应答
oP2PTRASH:
begin
//显示信息******************************************
std.ord:=oP2PTRASH;
//std.port:=remoteAddr.sin_port;
//strcopy(std.Ip,inet_ntoa(remoteaddr.sin_addr));
strcopy(std.text,'对方发送的打洞消息,忽略掉。');
sendmessage(hform,wm_Recv,0,0);
//Info:=pInfo^;
//**************************************************
//break;
end;// 对方发送的打洞消息,忽略掉。
oGETALLUSER:
begin
err:=recvfrom(sock,clientListCount, sizeof(integer), 0, remoteAddr, addrLen);
if err<=0 then continue;
clientList.Clear;
for i:=0 to clientListCount-1 do
begin
new(pUserListNode);
err:=UDPrecv(sock, pUserListNode^, sizeof(_stUserListNode), 0, remoteAddr, addrLen);
if err<=0 then continue;
clientList.Add(pUserListNode);
end;//for
//显示信息******************************************
std.ord:=oGETALLUSER;
//std.port:=remoteAddr.sin_port;
//strcopy(std.Ip,inet_ntoa(remoteaddr.sin_addr));
strcopy(std.text,'获取用户列表');
//Info:=pInfo^;
sendmessage(hform,wm_Recv,0,0);
//**************************************************
end;//
end;//case
end;//while
end;