1. android udp接收不到数据
1、可先在oncreate()方法里面实例化一个WifiManager.MulticastLock 对象lock;具体如下:
WifiManager manager = (WifiManager) this
.getSystemService(Context.WIFI_SERVICE);
WifiManager.MulticastLock lock= manager.createMulticastLock("test wifi");
2、在调用广播发送、接收报文之前先调用lock.acquire()方法;
3、用完之后及时调用lock.release()释放资源,否决多次调用lock.acquire()方法,程序可能会崩,详情请见
Caused by: java.lang.UnsupportedOperationException: Exceeded maximum number of wifi locks
注;记得在配置文件里面添加如下权限:
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
经过这样处理后,多数手机都能正常发送接收到广播报文。
本小点转载自Android手机接收不到UDP报文
二、在UDP通信中,android端发送UDP广播包没有问题。至于接收的话,有时候不能接收到包。
在UDP通信中,android端发送UDP广播包没有问题。至于接收的话,有时候不能接收到包。但是如果UDP包中指定了目标主机的地址的话,那么android端就能正常接收。
下面上一段代码,大家可用这段代码进行测试。
1、在一个Service里面,我们创建一个线程
public void onCreate() {//用于创建线程
WifiManager manager = (WifiManager) this
.getSystemService(Context.WIFI_SERVICE);
udphelper = new UdpHelper(manager);
//传递WifiManager对象,以便在UDPHelper类里面使用MulticastLock
udphelper.addObserver(MsgReceiveService.this);
tReceived = new Thread(udphelper);
tReceived.start();
super.onCreate();
}
2、弄一个UDP帮助类,这个类主要用于发送和接收数据
package com.example.com.ihome.bang.util;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Observable;
import com.example.com.ihome.bang.tool.SendThread;
import android.net.wifi.WifiManager;
import android.util.Log;
/**
*
* UdpHelper帮助类
*
* @author 陈喆榕
*
*/
public class UdpHelper implements Runnable {
public Boolean IsThreadDisable = false;//指示监听线程是否终止
private static WifiManager.MulticastLock lock;
InetAddress mInetAddress;
public UdpHelper(WifiManager manager) {
this.lock= manager.createMulticastLock("UDPwifi");
}
public void StartListen() {
// UDP服务器监听的端口
Integer port = 8903;
// 接收的字节大小,客户端发送的数据不能超过这个大小
byte[] message = new byte[100];
try {
// 建立Socket连接
DatagramSocket datagramSocket = new DatagramSocket(port);
datagramSocket.setBroadcast(true);
DatagramPacket datagramPacket = new DatagramPacket(message,
message.length);
try {
while (!IsThreadDisable) {
// 准备接收数据
Log.d("UDP Demo", "准备接受");
this.lock.acquire();
datagramSocket.receive(datagramPacket);
String strMsg=new String(datagramPacket.getData()).trim();
Log.d("UDP Demo", datagramPacket.getAddress()
.getHostAddress().toString()
+ ":" +strMsg );this.lock.release();
}
} catch (IOException e) {//IOException
e.printStackTrace();
}
} catch (SocketException e) {
e.printStackTrace();
}
}
public static void send(String message) {
message = (message == null ? "Hello IdeasAndroid!" : message);
int server_port = 8904;
Log.d("UDP Demo", "UDP发送数据:"+message);
DatagramSocket s = null;
try {
s = new DatagramSocket();
} catch (SocketException e) {
e.printStackTrace();
}
InetAddress local = null;
try {
local = InetAddress.getByName("255.255.255.255");
} catch (UnknownHostException e) {
e.printStackTrace();
}
int msg_length = message.length();
byte[] messageByte = message.getBytes();
DatagramPacket p = new DatagramPacket(messageByte, msg_length, local,
server_port);
try {
s.send(p);
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
StartListen();
}
}
希望能帮到你。
2. android:udp广播
首先手机作为终端 可以不必要知道终端的数量、 还有就是我建议你多学习下基础,android的广播机制不是把广播在终端之间传输,广播是在应用程序里面发送,在应用程序进行接收。个人建议基础才是王道。 对于你现在这个问题,不妨采用发送消息的方式 实现该功能。一个终端发送消息 其他终端接收消息,当然也相当于写一个socket通信。通信建立之后 ,可以取得各个连接的终端的IP 然后怎么逻辑就看你怎么写算法了。还有就是,这个功能也可以用消息推送的方式(建议采用此方法)、android系统内置有消息推送,逻辑都和上述的差不多,至于具体用那些方法 那些内置类,个人建议多查API。软件开发必须靠自学。。。。
3. (三)Android局域网内语音对讲 基于UDP语音传输
之前研究了基于UDP的文字传输 点击打开链接 ,以及Android端的语音录制 点击打开链接 ,这篇文章就记录一下Android端局域网内的语音传输,简单的实现语音对讲,当然里面还存在着很多问题,包括语音不清晰啊、杂音多啊,不管了,先听见声音就行了。测试的时候两部手机,上图:
程序写了两个线程,一个用于录制AudioRecordThread,一个用于播放AudioTrackThread.
(一)录制与发送
@Override
public void run() {
if (mSocket == null)
return;
try {
mStartTime = System.currentTimeMillis();
audioRec.startRecording();
while (flag) {
try {
byte[] bytes_pkg = buffer.clone();
if (mRecordQueue.size() >= 2) {
int length = audioRec.read(buffer, 0, minBufferSize);
//获取音量大小
mVolume = getAudioColum(buffer);
System.out.println(TAG + "= " + mVolume);
Message message = mHandler.obtainMessage();
message.arg1 = (int) mVolume;
mHandler.sendMessage(message);
DatagramPacket writePacket;
InetAddress inet = InetAddress.getByName(inetAddressName);
writePacket = new DatagramPacket(buffer, length, inet, PORT);
writePacket.setLength(length);
System.out.println("AudioRTwritePacket = " + writePacket.getData().toString());
mSocket.send(writePacket);
}
mRecordQueue.add(bytes_pkg);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
audioRec.stop();
} catch (Exception e) {
e.printStackTrace();
}
}
里面包含了获取音量大小,便于在页面上面展示,方法参考了 点击打开链接
private double getAudioColum(byte[] buffer) {
double sumVolume = 0.0;
double avgVolume = 0.0;
double volume = 0.0;
for (int i = 0; i < buffer.length; i += 2) {
int v1 = buffer[i] & 0xFF;
int v2 = buffer[i + 1] & 0xFF;
int temp = v1 + (v2 << 8);// 小端
if (temp >= 0x8000) {
temp = 0xffff - temp;
}
sumVolume += Math.abs(temp);
}
avgVolume = sumVolume / buffer.length / 2;
volume = Math.log10(1 + avgVolume) * 10;
return volume;
}
(二)接收与播放
@Override
public void run() {
if (mSocket == null)
return;
//从文件流读数据
audioTrk.play();
while (flag) {
DatagramPacket recevPacket;
try {
recevPacket = new DatagramPacket(buffer, 0, buffer.length);
mSocket.receive(recevPacket);
audioTrk.write(recevPacket.getData(), 0, recevPacket.getLength());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
audioTrk.stop();
}
(三)主页面 接收按钮事件
@OnClick({R.id.btn_receive})
public void onViewClicked(View view) {
switch (view.getId()) {
case R.id.btn_receive:
if (btnReceive.getText().toString().equals("开始接收")) {
btnReceive.setText("停止接收");
try {
if (audioTrackThread == null) {
audioTrackThread = new AudioTrackThread();
}
new Thread(audioTrackThread).start();
} catch (SocketException e) {
e.printStackTrace();
}
} else {
btnReceive.setText("开始接收");
audioTrackThread.setFlag(false);
}
break;
}
}
(四)发送按钮事件
ivSpeak.setOnTouchListener(new View.OnTouchListener() {
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//按下按钮开始录制
ivSpeak.setText("正在说话");
//显示录音提示
relativeLayout.setVisibility(View.VISIBLE);
try {
if (audioRecordThread == null) {
audioRecordThread = new AudioRecordThread(handler);
}
audioRecordThread.setInetAddressName(tvReceiveIp.getText().toString());
audioRecordThread.setFlag(true);
new Thread(audioRecordThread).start();
} catch (SocketException e) {
e.printStackTrace();
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
//松开按钮结束录制
ivSpeak.setText("按住说话");
relativeLayout.setVisibility(View.GONE);
audioRecordThread.setFlag(false);
mStopTime = audioRecordThread.getmStopTime();
mStartTime = audioRecordThread.getmStartTime();
creatMessageBean((mStopTime - mStartTime) / 1000, true);
break;
}
return true;
}
});
4. Android UDP通讯(简单demo)
本章节 比较简单
直接上code了
首先创建一个UDP class 构造方法如下
通过newFixedThreadPool 创建一个线程池
然后
一个startUdp scoket 重要步骤
startSocketThread是一个 接收消息的子线程
内部是一个接收消息的循环
BROADCAST_IP 是通信对方的地址
利用广播 把接收到的消息打印到前台
再然后创建一个发送message的方法
文章所有code 地址---> github
https://github.com/hanjole/Udpscoket_demo
5. android 如何定时发udp
定时执行任务可以考虑使用AlarmManager配合BroadcastReceiver实现
AlarmManager定时发出intent,BroadCastReceiver收到这个intent后进行发送UDP的操作
6. Android 手机上能通过DatagramSocket收到PC端的UDP广播吗
在PC端直接用tcp调试助手发送数据,我另一台电脑能收到的,但是android的却是有时可以收到有时收不到,平均几十次收到10次左右,丢包不可能这么严重吧。,android的代码如下,
ds = new DatagramSocket(1234, InetAddress.getByName(“192.168.1.3”));
dp = new DatagramPacket(content, content.length);
ds.receive(dp);
如果我在pc端发送绑定了IP的UDP数据包,android可以收到数据,但是PC端发送255的广播UDP,android就收不到了。。查了一些资料,说是要加入权限,加入以下的代码,但实测发现效果一样。
WifiManager manager = (WifiManager) this.getSystemService(Context.WIFI_SERVICE); WifiManager.MulticastLock lock= manager.createMulticastLock("localWifi");
7. (四)Android基于UDP的多客户端语音通信
在前三篇得基础上,这次研究了组播功能。非常感谢https://blog.csdn.net/jspping/article/details/64438515得贡献!
组播也就是通过MulticastSocket来进行开发,与DatagramSocket比较相类似,这次依然是用两个线程进行实现,发送线程MultiSendThread和接收线程MultiReceiveThread。废话不多说,开始码:
(一)MultiSendThread:
(1)初始化MuticastSocket
// 侦听的端口
try {
multicastSocket = new MulticastSocket(8082);
// 使用D类地址,该地址为发起组播的那个ip段,即侦听10001的套接字
address = InetAddress.getByName("239.0.0.1");
} catch (IOException e) {
e.printStackTrace();
}
(2)初始化AudioRecord
protected LinkedList<byte[]> mRecordQueue;
int minBufferSize;
private static AcousticEchoCanceler aec;
private static AutomaticGainControl agc;
private static NoiseSuppressor nc;
AudioRecord audioRec;
byte[] buffer;
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
private void initAudio() {
//播放的采样频率 和录制的采样频率一样
int sampleRate = 44100;
//和录制的一样的
int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
//录音用输入单声道 播放用输出单声道
int channelConfig = AudioFormat.CHANNEL_IN_MONO;
minBufferSize = AudioRecord.getMinBufferSize(
sampleRate,
channelConfig, AudioFormat.ENCODING_PCM_16BIT);
System.out.println("****RecordMinBufferSize = " + minBufferSize);
audioRec = new AudioRecord(
MediaRecorder.AudioSource.MIC,
sampleRate,
channelConfig,
audioFormat,
minBufferSize);
buffer = new byte[minBufferSize];
if (audioRec == null) {
return;
}
//声学回声消除器 AcousticEchoCanceler 消除了从远程捕捉到音频信号上的信号的作用
if (AcousticEchoCanceler.isAvailable()) {
aec = AcousticEchoCanceler.create(audioRec.getAudioSessionId());
if (aec != null) {
aec.setEnabled(true);
}
}
//自动增益控制 AutomaticGainControl 自动恢复正常捕获的信号输出
if (AutomaticGainControl.isAvailable()) {
agc = AutomaticGainControl.create(audioRec.getAudioSessionId());
if (agc != null) {
agc.setEnabled(true);
}
}
//噪声抑制器 NoiseSuppressor 可以消除被捕获信号的背景噪音
if (NoiseSuppressor.isAvailable()) {
nc = NoiseSuppressor.create(audioRec.getAudioSessionId());
if (nc != null) {
nc.setEnabled(true);
}
}
mRecordQueue = new LinkedList<byte[]>();
}
(3)开始录制,并实时发送出去
@Override
public void run() {
if (multicastSocket == null)
return;
try {
audioRec.startRecording();
while (true) {
try {
byte[] bytes_pkg = buffer.clone();
if (mRecordQueue.size() >= 2) {
int length = audioRec.read(buffer, 0, minBufferSize);
// 组报
DatagramPacket datagramPacket = new DatagramPacket(buffer, length);
// 向组播ID,即接收group /239.0.0.1 端口 10001
datagramPacket.setAddress(address);
// 发送的端口号
datagramPacket.setPort(10001);
System.out.println("AudioRTwritePacket = " + datagramPacket.getData().toString());
multicastSocket.send(datagramPacket);
}
mRecordQueue.add(bytes_pkg);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
(二)MultiReceiveThread
(1)初始化MulticastSocket
// 接收数据时需要指定监听的端口号
try {
multicastSocket = new MulticastSocket(10001);
// 创建组播ID地址
InetAddress address = InetAddress.getByName("239.0.0.1");
// 加入地址
multicastSocket.joinGroup(address);
} catch (IOException e) {
e.printStackTrace();
}
(2)初始化AudioTrack
byte[] buffer;
AudioTrack audioTrk;
private void initAudioTracker() {
//扬声器播放
int streamType = AudioManager.STREAM_MUSIC;
//播放的采样频率 和录制的采样频率一样
int sampleRate = 44100;
//和录制的一样的
int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
//流模式
int mode = AudioTrack.MODE_STREAM;
//录音用输入单声道 播放用输出单声道
int channelConfig = AudioFormat.CHANNEL_OUT_MONO;
int recBufSize = AudioTrack.getMinBufferSize(
sampleRate,
channelConfig,
audioFormat);
System.out.println("****playRecBufSize = " + recBufSize);
audioTrk = new AudioTrack(
streamType,
sampleRate,
channelConfig,
audioFormat,
recBufSize,
mode);
audioTrk.setStereoVolume(AudioTrack.getMaxVolume(),
AudioTrack.getMaxVolume());
buffer = new byte[recBufSize];
}
(3)开始接收,并进行实时播放
@Override
public void run() {
if (multicastSocket == null)
return;
//从文件流读数据
audioTrk.play();
// 包长
while (true) {
try {
// 数据报
DatagramPacket datagramPacket = new DatagramPacket(buffer, buffer.length);
// 接收数据,同样会进入阻塞状态
multicastSocket.receive(datagramPacket);
audioTrk.write(datagramPacket.getData(), 0, datagramPacket.getLength());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
(三)开始测试
MultiSendThread multiSendThread;
MultiReceiverThread multiReceiverThread;
@OnClick({R.id.btnSend, R.id.btnReceive})
public void onViewClicked(View view) {
switch (view.getId()) {
case R.id.btnSend:
if (multiSendThread == null) {
multiSendThread = new MultiSendThread();
}
new Thread(multiSendThread).start();
break;
case R.id.btnReceive:
if (multiReceiverThread == null) {
multiReceiverThread = new MultiReceiverThread();
}
new Thread(multiReceiverThread).start();
break;
}
}
8. android接收不到udp包吗
1、有的手机不能直接接收UDP包,可能是手机厂商在定制Rom的时候把这个功能给关掉了。
2、在UDP通信中,android端发送UDP广播包没有问题。至于接收的话,有时候不能接收到包。
9. Android 使用udp发送广播
最近做项目时,遇到一个对新人我来说稍微有点麻烦的事情!
那就是使用udp协议发送广播获取服务器地址!
http都好说,github开源项目不知道有多少。
可是再难的问题也要去解决!
发送广播需要权限!
AndroidManifest.xml 中添加:
最少这三个是必须的,多的也忘了!
原因后面会讲到
使用到RxJava:
udp发送与接受都需指定端口号
广播地址是255.255.255.255
在之前添加权限的时候CHANGE_WIFI_MULTICAST_STATE有添加这个
往下面看
接下来我们开启接收udp信息
发送消息?
谢谢该作者的文章让我学会udp发送
https://blog.csdn.net/tanghongchang123/article/details/53609237
10. Android 基于UDP的Socket通信
1、连接DatagramSocket的服务端(ip和port):开启异步线程和socket
2、发送数据(DatagramPacket):异步
3、接收数据(DatagramPacket):注意连接状态,异步读取
4、关闭连接:关闭DatagramSocket和对应线程
1、异常:android.os.NetworkOnMainThreadException。 socket需要在线程中使用
2、前后端统一传输或者接收协议 [requestcode size d1 d2 d3 ... ],在解析时候用得到
3、实施监控socket的连接状态,还是用心跳包发过去,然后返回数据,一段时间没有的话则代表socket连接失败。
4、注意receive接收数据后的有效长度(一个是预存的buffer,一个是有效结果buffer)
5、客户端连上去后不知道为何一定要先发送一次,才能接收?
6、UDP不安全,有长度限制64K
2019 (* ̄(oo) ̄) 诸事顺利!