我已经阅读了本网站上的许多文章,了解如何在Android中接收UDP数据包。但是,这些都不对我有用!
一些基本知识:
我正在3G(不是wifi或其他任何设备)上运行的HTC Incredible(Android 2.2)上进行测试。这里没有仿真器。
我的代码很简单:
我尝试将UDP数据包从服务器(再次在PC上)发送到Android应用程序(在手机上运行),但它不起作用。
//Server code to initialize the UDP socket (snippet)
public void init() {
datagram_server_socket = new DatagramSocket(port,local_addr);
datagram_server_socket.setSoTimeout(1000);
}
//将数据包发送到服务器的ANDROID APP上的代码片段
public void connect() {
Random r = new Random(System.currentTimeMillis());
int udp_port = 0;
while(true){
try {
udp_port = r.nextInt(1000)+8000;
udp_port = 8000;
comm_skt = new DatagramSocket(udp_port);
Log.i("ServerWrapper", "UDP Listening on port: " + udp_port);
break;
} catch(SocketException e) {
Log.e("ServerWrapper", "Could not bind to port " + udp_port);
}
}
byte[] sdata = new byte[4+tid.length];
i = 0;
sdata[i++] = (byte)(0XFF&(udp_port>>24));
sdata[i++] = (byte)(0XFF&(udp_port>>16));
sdata[i++] = (byte)(0XFF&(udp_port>>8));
sdata[i++] = (byte)(0XFF&(udp_port));
for(byte b: tid){
sdata[i++] = b;
}
DatagramPacket pkt = new DatagramPacket(sdata, sdata.length,
InetAddress.getByName(hostname), port);
comm_skt.send(pkt);
}
//Server's UDP socket listening code
public void serverUDPListener() {
try {
datagram_server_socket.receive(rpkt);
int port = 0;
byte[] rdata = rpkt.getData();
port += rdata[0]<<24;
port += rdata[1]<<16;
port += rdata[2]<<8;
port += (0XFF)&rdata[3];
byte[] tid = new byte[rdata.length];
for(int i = 4; i < rdata.length && rdata[i] > 0; i++) {
tid[i-4] = rdata[i];
}
String thread_id = new String(tid).trim();
for(int i = 0; i < threads.size(); i++) {
ClientThread t = threads.get(i);
if(t.getThreadId().compareTo(thread_id) == 0) {
t.setCommSocket(rpkt, port);
} else {
System.err.println("THREAD ID " + thread_id + " COULD NOT BE FOUND");
}
}
} catch (IOException e) {
if(!(e instanceof SocketException) && !(e instanceof SocketTimeoutException))
log.warning("Error while listening for an UDP Packet.");
}
}
//Corresponds to the setCommSocket call above to save the IP and Port of the incoming UDP packet on the server-end
public void setCommSocket(DatagramPacket pkt, int port) {
comm_ip = pkt.getAddress();
comm_port = pkt.getPort(); //Try the port from the packet?
}
//Sends an UDP packet from the SERVER to the ANDROID APP
public void sendIdle() {
if(comm_ip != null) {
System.err.println("Sent IDLE Packet (" + comm_ip.getHostAddress() + ":" + comm_port + ")");
DatagramPacket spkt = new DatagramPacket(new byte[]{1, ProtocolWrapper.IDLE}, 2, comm_ip, comm_port);
DatagramSocket skt;
try {
skt = new DatagramSocket();
skt.send(spkt);
} catch (Exception e) {
e.printStackTrace();
}
}
}
现在,我已经将应用程序使用的端口硬编码为8000。但是,奇怪的是,每次我测试程序(并查看保存在服务器上的IP
/端口)时,数据包来自的端口始终为33081我有一个线程在我的Android应用程序中不断侦听UDP流量,但是该代码从未执行过并通过“
receive(packet)”部分:
public void AndroidUDPListener() {
while(true) {
synchronized(stop) {
if(stop) return;
}
byte[] recieve_data = new byte[64];
DatagramPacket rpkt = new DatagramPacket(recieve_data, recieve_data.length);
try {
if(comm_skt == null)
continue;
comm_skt.receive(rpkt);
byte[] data = rpkt.getData();
switch(data[1]) {
case IDLE:
if(ocl != null) ocl.onCompletion(null);
break;
case KEEP_ALIVE:
break;
}
} catch (Exception e) {
if(!(e instanceof SocketException) && !(e instanceof SocketTimeoutException))
Log.w("ServerWrapper", "Error while listening for an UDP Packet.");
}
}
}
有人在我的代码中看到问题吗?还是我需要首先在应用程序上设置一些权限/设置?我已启用互联网通讯。
示例输出(使用数据包getPort()中的端口):
Android App-现在正在侦听端口8000上的UDP流量
Android App-将数据包发送到服务器
服务器-从XXXXXX:33081接收到的数据包
服务器-将IDLE数据包发送到XXXXXX:33081
示例输出(使用分组数据中的端口):
Android App-现在正在侦听端口8000上的UDP流量
Android App-将数据包发送到服务器
服务器-从XXXXXX接收到的数据包:8000
服务器-将IDLE数据包发送到XXXXXX:8000
Android应用程序从不使用任何一个端口接收任何UDP流量。
很抱歉没有尽快更新。该问题已修复如下:
我需要将DatagramSocket存储到每个线程。侦听套接字还应该是用于继续服务器与客户端之间的通信的套接字。这是更新代码的位。
线程上的新套接字注册代码:
public void setCommSocket(DatagramPacket pkt, int port, DatagramSocket skt)
{
comm_ip = pkt.getAddress();
comm_port = pkt.getPort();
synchronized(comm_pkt) {
comm_pkt = pkt;
}
comm_skt = skt;
}
新服务器侦听代码:
public void UDPListen() {
while(true) {
synchronized(stop) {
if(stop)
break;
}
byte[] recieve_data = new byte[64];
DatagramPacket rpkt = new DatagramPacket(recieve_data, recieve_data.length);
try {
datagram_server_socket.receive(rpkt);
int port = 0;
byte[] rdata = rpkt.getData();
port += rdata[0]<<24;
port += rdata[1]<<16;
port += rdata[2]<<8;
port += (0XFF)&rdata[3];
byte[] tid = new byte[rdata.length];
for(int i = 4; i < rdata.length && rdata[i] > 0; i++)
{
tid[i-4] = rdata[i];
}
String thread_id = new String(tid).trim();
for(int i = 0; i < threads.size(); i++) {
ClientThread t = threads.get(i);
if(t.getThreadId().compareTo(thread_id) == 0)
{
t.setCommSocket(rpkt, port, datagram_server_socket);
} else {
System.err.println("THREAD ID " + thread_id + " COULD NOT BE FOUND");
}
}
} catch (IOException e) {
if(!(e instanceof SocketException) && !(e instanceof SocketTimeoutException))
log.warning("Error while listening for an UDP Packet.");
} finally {
for(int i = 0; i < threads.size(); i++) {
ClientThread t = threads.get(i);
t.sendKeepAlive();
}
}
}
}
我将省略服务器/线程结构的一些更新。这里的重要部分是接收到数据包的套接字被重新用于将数据发送回客户端。此外,实际的数据包被重新用于发送数据:
public void sendIdle() {
if(comm_ip != null) {
synchronized(comm_pkt) {
try {
comm_pkt.setData(new byte[]{1, ProtocolWrapper.IDLE});
comm_skt.send(comm_pkt);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
这是我的包装器类的相关部分,显示了每个线程持有的内容:
public class PeerWrapper {
private InetAddress ipaddress;
private Integer port;
private Socket client_socket;
private InetAddress comm_ip;
private DatagramSocket comm_skt;
private DatagramPacket comm_pkt;
private int comm_port;
private byte status;
$config = [ 'corp_id' => 'xxxxxxxxxxxxxxxxx', 'secret' => 'xxxxxxxxxx', // 通讯录的 secret //... ]; $contacts = Factory::work($config); 成员管理 创建成员 $data = [ "userid" => "overtrue",
SPI通讯 OMAP芯片会使用一个串行外围接口,实现一个适合的协议,与V850芯片通讯。这个通讯包括了刷新V850芯片,执行DTC操作和发送CAN信息。实际上,这个通讯是在一个高级别上,通过各种服务实现的。在低级别上,可以通过读取和写入‘/dev/spi3’来实现直接通讯。 不过,似乎没有命令能让OMAP芯片来要求V850将数据字节发送给任意CAN ID。但是,V850内置了一系列的命令ID,多数
通用通知消息 消息体 ChannelMessage 例子 Swift: NotificationCenter.rokidsdk.addObserver(self, selector: #selector(handleChannelMsgsNotification(_:)), name: NSNotification.Name(rawValue: SDKNotificationName.Channe
application提供了千牛移动提供的原生能力,比如打开聊天窗口(openChat)、获取地址位置(location)和打开网址(openWebsite)等,点击查看api列表和具体用法 打开“千牛欢迎页” QN.application.invoke({ api: 'openPlugin', query: { appkey: 23093073 }, settings:
主要内容:GWT RPC通讯 介绍,GWT RPC通讯 组件,GWT RPC通讯 示例GWT RPC通讯 介绍 基于 GWT 的应用程序通常由客户端模块和服务器端模块组成。客户端代码在浏览器中运行,服务器端代码在 Web 服务器中运行。客户端代码必须通过网络发出 HTTP 请求才能访问服务器端数据。 RPC,远程过程调用是 GWT 使用的机制,客户端代码可以在其中直接执行服务器端方法。 GWT RPC 是基于 servlet 的。 GWT RPC 是异步的,客户端在通信过程中永远不
contacts对象提供对设备通讯录数据库的访问。 方法: contacts.create contacts.find 参数: contactFields contactSuccess contactError contactFindOptions 对象: Contact ContactName ContactField ContactAddress ContactOrganization Con