首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Android UDP孔-在第二个插座(Python+Java)上打孔失败

Android UDP孔-在第二个插座(Python+Java)上打孔失败
EN

Stack Overflow用户
提问于 2017-07-13 03:05:43
回答 1查看 177关注 0票数 0

我正在开发一款安卓手机应用程序(H),它可以通过UDP打孔与一个名为RPi 3 (P)的同龄人对话。我在H上有两个套接字(ss_vid),由于主服务器(M),这两个套接字都会被穿孔;在P上有一个套接字(S3表示清楚,但在代码中是's‘)。H在移动网络上,P在我的wifi上,M在Google引擎上。

程序流程:

H使用s来ping MMP发送addr/port信息。

H使用s_vid来ping MMP发送addr/port信息。

P使用S3来ping MMH发送addr/port信息。

(我们现在应该被打洞了)

H使用sS3的端口上向P发送定期数据包。

P使用S3s的端口上向H发送定期数据包。

(在没有issues...below不工作的情况下,所有这些都很好)

P使用S3s_vid的端口上向H发送定期数据包。(确切地说,应该是这样)。

因此,我们应该有3个数据包流: H@s -> P@S3、P@S3 -> H@s和P@S3 -> H@s_vid,但出于某种原因,只有前两项工作。最后一个挂在s_vid.receive()行上(参见代码)。

以下是H的(相关)代码:

代码语言:javascript
复制
public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback, MediaPlayer.OnPreparedListener, SensorEventListener{

    public String messageStr;
    public String masterMessageStr;
    public int master_msg_length;
    public int msg_length;
    public String masterMessageVidStr;
    public int master_msg_vid_length;

    public DatagramPacket p_peer;
    public DatagramPacket p_master;
    public DatagramPacket p_master_vid;
    public DatagramPacket p_rec;
    public DatagramPacket p_rec_vid;
    public DatagramSocket s;
    public DatagramSocket s_vid;

    public InetAddress return_peer_addr;
    public int return_peer_port;
    public InetAddress master_addr;
    public int master_port;


    @Override
    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

    }

    @Override
    public void onStart() {
        super.onStart();
    }

    @Override
    public void onStop() {
        super.onStop();
    }

    @Override
    protected void onResume() {
        super.onResume();

        //Define Sockets
        try {
            s = new DatagramSocket();
            s.setReuseAddress(true);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        try {
            s_vid = new DatagramSocket();
            s_vid.setReuseAddress(true);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        try {
            master_addr = InetAddress.getByName("xx.xxx.xxx.xxx");//hardcoded server address
        } catch (Exception e)
        {
            e.printStackTrace();
        }
        master_port = 1111;//hardcoded server port


        //listen for server or peer packets.
        Runnable receive_thread_run = new Runnable() {
            @Override
            public void run() {
                while(true){
                    byte[] buf = new byte[1024];
                    p_rec = new DatagramPacket(buf,buf.length);
                    try {
                        s.receive(p_rec);

                        //Do stuff...
                        //this works fine.
                    }
                    catch (Exception e)
                    {
                        e.printStackTrace();
                    }
                }
            }
        };

        //listen for peer packets. PROBLEM IS HERE.
        Runnable receive_thread_run_vid = new Runnable() {
            @Override
            public void run() {

                byte[] buf_vid = new byte[1024];
                p_rec_vid = new DatagramPacket(buf_vid,buf_vid.length);

                try {
                    s_vid.receive(p_rec_vid);//this is reached, but never receives...

                    //Do stuff...never reached.

                }
                catch (Exception e)
                {
                    e.printStackTrace();
                }
            }
        };

        //Start the threads
        Thread receive_thread_vid = new Thread(receive_thread_run_vid);
        receive_thread_vid.start();

        Thread receive_thread = new Thread(receive_thread_run);
        receive_thread.start();

        //Send out pings to master server for hole-punching.
        TimerTask return_master = new TimerTask(){
            @Override
            public void run() {

                masterMessageStr = "someping";

                master_msg_length = masterMessageStr.length();
                byte[] msg = masterMessageStr.getBytes();

                p_master = new DatagramPacket(msg,master_msg_length,master_addr,master_port);

                try {
                    s.send(p_master);
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                }

            }
        };

        Timer return_master_timer = new Timer();
        return_master_timer.scheduleAtFixedRate(return_master,1000,1000);

        //Send out pings to master server for hole-punching (2nd socket).
        TimerTask return_master_vid = new TimerTask(){
            @Override
            public void run() {

                masterMessageVidStr = "someotherping";

                master_msg_vid_length = masterMessageVidStr.length();
                byte[] msg_vid = masterMessageVidStr.getBytes();

                p_master_vid = new DatagramPacket(msg_vid,master_msg_vid_length,master_addr,master_port);

                try {
                    s_vid.send(p_master_vid);
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                }

            }
        };

        Timer return_master_timer_vid = new Timer();
        return_master_timer_vid.scheduleAtFixedRate(return_master_vid,1000,1000);

        //Talk directly to the peer.
        TimerTask return_peer = new TimerTask(){
            @Override
            public void run() {

                //Do stuff...

                messageStr = "some peer-directed message";

                msg_length = messageStr.length();
                byte[] msg = messageStr.getBytes();

                p_peer = new DatagramPacket(msg,msg_length,return_peer_addr,return_peer_port);

                //check we know where to send it
                if (return_peer_addr != null && return_peer_port != 0) {
                    try {
                        s.send(p_peer);
                    }
                    catch (Exception e)
                    {
                        e.printStackTrace();
                    }
                }
            }
        };

        Timer return_peer_timer = new Timer();
        return_peer_timer.scheduleAtFixedRate(return_peer,500,500);//time in milliseconds
    }
}

以下是M的(相关)代码:

代码语言:javascript
复制
import socket
import sys
import time
import threading

## peer-Master UDP Comms
def receive_peer():#gets peer addr and sends it to phone.
    global peer_addr
    global peer_port

    while 1:
        data, addr = s_peer.recvfrom(1024)

        #figure out who is talking (should only be peer)
        if data == 'somepeerping':
            peer_addr = addr[0]
            peer_port = addr[1]

            #send it to phone
            if phone_addr is not None and peer_addr is not None and peer_port is not None:
                phone_ret_data = '{\"return_addr\":\"'+peer_addr+'\",\"return_port\":\"'+str(peer_port)+'\"}'
                s_phone.sendto(phone_ret_data,(phone_addr,phone_port))

## Phone-Master UDP Comms
def receive_phone():#gets phone addr (and phone vid addr) and sends it to peer.
    global phone_addr
    global phone_port
    global phone_addr_vid
    global phone_port_vid
    global peer_ret_data
    global peer_ret_data_vid

    while 1:
        data, addr = s_phone.recvfrom(1024)

        #figure out who is talking (whih of the two sockets)
        if data == 'someping':
            phone_addr = addr[0]
            phone_port = addr[1]

            if peer_addr is not None and phone_addr is not None and phone_port is not None:
                peer_ret_data = '{\"return_addr\":\"'+phone_addr+'\",\"msg_type\":\"novid\",\"return_port\":\"'+str(phone_port)+'\"}'
                s_peer.sendto(peer_ret_data,(peer_addr,peer_port))
        elif data == 'someotherping':
            phone_addr_vid = addr[0]
            phone_port_vid = addr[1]

            if peer_addr is not None and phone_addr_vid is not None and phone_port_vid is not None:
                peer_ret_data_vid = '{\"return_addr\":\"'+phone_addr_vid+'\",\"msg_type\":\"vid\",\"return_port\":\"'+str(phone_port_vid)+'\"}'
                s_peer.sendto(peer_ret_data_vid,(peer_addr,peer_port))

HOST = ''
PORT_peer = 2222
PORT_phone = 1111

peer_addr = None
peer_port = None
phone_addr = None
phone_port = None
phone_addr_vid = None
phone_port_vid = None

peer_ret_data = None
peer_ret_data_vid = None
phone_ret_data = None

## peer socket
try:
    s_peer = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s_peer.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    print("Socket created.")
except socket.error, msg:
    print("Failed. Error: " + str(msg))
    sys.exit()

try:
    s_peer.bind((HOST,PORT_peer))
    print("Socket binding complete.")
except socket.error, msg:
    print("Bind failed. Error: " + str(msg))
    s_peer.close()
    sys.exit()

## Phone socket
try:
    s_phone = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s_phone.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    print("Socket created.")
except socket.error, msg:
    print("Failed. Error: " + str(msg))
    sys.exit()

try:
    s_phone.bind((HOST,PORT_phone))
    print("Socket binding complete.")
except socket.error, msg:
    print("Bind failed. Error: " + str(msg))
    s_phone.close()
    sys.exit()


## Initiate threads
threading.Thread(target=receive_peer).start()
threading.Thread(target=receive_phone).start()

以下是P的(相关)代码:

代码语言:javascript
复制
import socket
import sys
import time
import threading
import json
import time
import subprocess

## UDP Comms - thread to receive incoming packets.
def receive_thread():
    global master_addr
    global master_port
    global return_phone_addr
    global return_phone_port
    global return_phone_vid_addr
    global return_phone_vid_port
    global phone_packet_count

    while 1:
        data, addr = s.recvfrom(1024)

        if addr[0] == master_addr and addr[1] == master_port:#message from master server, update return addresses
            master_msg_received = json.loads(data)
            master_msg_received = {str(key):str(value) for key,value in master_msg_received.items()}#to remove unicode

            if master_msg_received['msg_type'] == 'novid':
                return_phone_addr = master_msg_received['return_addr']
                return_phone_port = int(master_msg_received['return_port'])
            elif master_msg_received['msg_type'] == 'vid':
                return_phone_vid_addr = master_msg_received['return_addr']
                return_phone_vid_port = int(master_msg_received['return_port'])
        elif addr[0] == return_phone_addr and addr[1] == return_phone_port and return_phone_addr is not None:#message from phone
            phone_packet_count = phone_packet_count + 1
            msg_received = json.loads(data)
            msg_received = json.dumps(msg_received)#to remove unicode

            #Do stuff...no problems here or above.


## UDP Comms - threads to send out packets.
#send our address to master.
def ping_master():
    global master_addr
    global master_port

    s.sendto('somepeerping',(master_addr,master_port))
    threading.Timer(1,ping_master).start()

#return data to phone (for now packet count).
def return_phone():
    global return_phone_addr
    global return_phone_port
    global phone_packet_count

    if return_phone_addr is not None:
        s.sendto(str(phone_packet_count),(return_phone_addr,return_phone_port))

    threading.Timer(0.5,return_phone).start()

#send other data to phone on its second socket. POSSIBLE PROBLEM.
def return_phone_vid():
    global return_phone_addr
    global return_phone_port
    global return_phone_vid_addr
    global return_phone_vid_port

    if return_phone_vid_addr is None:
        threading.Timer(0.7,return_phone_vid).start()
    else:
        s.sendto('some second socket test ping',(return_phone_vid_addr,return_phone_vid_port))
        threading.Timer(0.7,return_phone_vid).start()


HOST = ''
PORT_phone = 0 #this is where phone comms arrive.

phone_packet_count = 0
return_phone_addr = None #this is where phone comms go.
return_phone_port = None #this is where phone comms go.
return_phone_vid_addr = None #this is where phone comms go.
return_phone_vid_port = None #this is where phone comms go.

master_addr = 'xx.xxx.xxx.xxx'#this is where master comms go. hardcoded.
master_port = 2222#this is where master comms go.
PORT_master = 0 #this is where master comms arrive.

## UDP Comms - initialize sockets.
try:
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    print("Socket created.")
except socket.error, msg:
    print("Failed. Error: " + str(msg))
    sys.exit()

try:
    s.bind((HOST,PORT_phone))
    print("Socket binding complete.")
except socket.error, msg:
    print("Bind failed. Error: " + str(msg))
    s.close()
    sys.exit()

## Initiate threads
threading.Thread(target=receive_thread).start()
ping_master()
return_phone()
return_phone_vid()

有什么原因吗?我已经确认P正在接收ss_vid的两个不同端口(相同的地址)。我希望这两个套接字都会失败,或者没有,而不仅仅是一个。可能是防火墙问题?但是,为什么只有一个套接字失败?谢谢你的帮助!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-07-14 05:51:07

这是我的一个打孔错误。穿孔的插座需要直接交谈。所以,按照我的提问风格,我有:

P@S3 -> H@s_vid而不是H@s_vid -> P@S3 (我在另一个套接字上有两个方向)。修复程序将这个方向添加到手机应用程序中,类似于

代码语言:javascript
复制
TimerTask return_peer_vid = new TimerTask(){
            @Override
            public void run() {

                retMessageVidStr = "test";

                ret_msg_vid_length = retMessageVidStr.length();
                byte[] msg = retMessageVidStr.getBytes();

                p_peer_vid = new DatagramPacket(msg,ret_msg_vid_length,return_peer_addr,return_peer_port);

                //check we know where to send it
                if (return_peer_addr != null && return_peer_port != 0) {
                    try {
                        s_vid.send(p_peer_vid);
                    }
                    catch (Exception e)
                    {
                        e.printStackTrace();
                    }
                }
            }
        };

        Timer return_peer_timer_vid = new Timer();
        return_peer_timer_vid.scheduleAtFixedRate(return_peer_vid,500,500);//time in milliseconds
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45070755

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档