我正在开发一款安卓手机应用程序(H),它可以通过UDP打孔与一个名为RPi 3 (P)的同龄人对话。我在H上有两个套接字(s和s_vid),由于主服务器(M),这两个套接字都会被穿孔;在P上有一个套接字(S3表示清楚,但在代码中是's‘)。H在移动网络上,P在我的wifi上,M在Google引擎上。
程序流程:
H使用s来ping M,M向P发送addr/port信息。
H使用s_vid来ping M,M向P发送addr/port信息。
P使用S3来ping M,M向H发送addr/port信息。
(我们现在应该被打洞了)
H使用s在S3的端口上向P发送定期数据包。
P使用S3在s的端口上向H发送定期数据包。
(在没有issues...below不工作的情况下,所有这些都很好)
P使用S3在s_vid的端口上向H发送定期数据包。(确切地说,应该是这样)。
因此,我们应该有3个数据包流: H@s -> P@S3、P@S3 -> H@s和P@S3 -> H@s_vid,但出于某种原因,只有前两项工作。最后一个挂在s_vid.receive()行上(参见代码)。
以下是H的(相关)代码:
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的(相关)代码:
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的(相关)代码:
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正在接收s和s_vid的两个不同端口(相同的地址)。我希望这两个套接字都会失败,或者没有,而不仅仅是一个。可能是防火墙问题?但是,为什么只有一个套接字失败?谢谢你的帮助!
发布于 2017-07-14 05:51:07
这是我的一个打孔错误。穿孔的插座需要直接交谈。所以,按照我的提问风格,我有:
P@S3 -> H@s_vid而不是H@s_vid -> P@S3 (我在另一个套接字上有两个方向)。修复程序将这个方向添加到手机应用程序中,类似于
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 millisecondshttps://stackoverflow.com/questions/45070755
复制相似问题