// 接收到打洞命令,向指定的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

解决方案 »

  1.   

    p2p啊,这里有完整的delphi源码例子
    http://2ccc.com/article.asp?articleid=1993
      

  2.   


    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;
      

  3.   

    这个是改为delphi的Client的主要代码,你看看,不过是用socket的