【发布时间】:2017-12-17 15:40:58
【问题描述】:
我正在开发一个 Android 手机应用程序 (H),该应用程序通过 UDP 打孔与 Peer、RPi 3 (P) 对话。我在 H 上有两个套接字(s 和 s_vid),这要归功于主服务器(M)和一个套接字(S3 为清楚起见,但 's' 在代码)在P。 H 在移动网络上,P 在我的 wifi 上,M 在 Google Cloud Engine 上。
程序流程:
H 使用s ping M,M 将地址/端口信息发送到P。
H 使用s_vid ping M,M 将地址/端口信息发送到P。
P 使用S3 ping M,M 将地址/端口信息发送到H。
(我们现在应该被打孔了)
H 使用s 在S3 的端口上定期向P 发送数据包。
P 使用S3 在s 的端口上定期向H 发送数据包。
(所有这些都可以正常工作,没有任何问题...下面不工作)
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 接收2 个不同的端口(相同的地址)。我希望两个套接字都失败或没有,而不仅仅是一个。也许是防火墙问题?但同样,为什么只有一个套接字失败?感谢您的帮助!
【问题讨论】:
标签: java android python sockets udp