‘壹’ android2个Activity,界面1通过udp发送消息到服务器,接收服务器消息后跳到界面2,由2返回1时仍然发消息给
你在跳向Activity2的时候,就不要发了,不就ok了?
‘贰’ 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();
}
}
希望能帮到你。
‘叁’ android开发,UDP发送失败。ip,端口都没问题,就send(包)的时候报异常。
解决问题的关键:第一,只建立一个socket用来收发数据,每次点击连接时新建,中间不在新建或close同一端口的socket直到点击断开,这样PC端服务程序解析出的端口就在断开前不会变了,这可以解决前一段提到的两个问题。第二,PC端服务程序要具有解析功能,最好用我提供的。顺带提一下,如果同一个端口的socket在没有close的时候再次新建会出现程序自动退出的现象。
‘肆’ C# 和Android的 TCP(UDP)通信
服务器程序
它仅仅建立ServerSocket监听,并使用Socket获取输入输出流。
import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class SimpleServer {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
//创建一个ServerSocket,用于监听客户端socket的连接请求
ServerSocket ss=new ServerSocket(30000);
//采用循环不断接受来自客户端的请求,服务器端也对应产生一个Socket
while(true){
Socket s=ss.accept();
OutputStream os=s.getOutputStream();
os.write("您好,您收到了服务器的新年祝福!n".getBytes("utf-8"));
os.close();
s.close();
}
}}
客户端程序
package my.learn.tcp;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.EditText;
public class SimpleClient extends Activity {
private EditText show;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
show = (EditText) findViewById(R.id.show);
try {
Socket socket = new Socket("自己计算机的IP地址", 30000);
//设置10秒之后即认为是超时
socket.setSoTimeout(10000);
BufferedReader br = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
String line = br.readLine();
show.setText("来自服务器的数据:"+line);
br.close();
socket.close();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
Log.e("UnknownHost", "来自服务器的数据");
e.printStackTrace();
} catch (IOException e) {
Log.e("IOException", "来自服务器的数据");
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
‘伍’ 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) ̄) 诸事顺利!
‘陆’ (四)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;
}
}
‘柒’ 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