本文目录一览:
- 1、java socket,我有客户端和服务器的代码,帮我添加广播和能多人会话,加分!!代码如下
- 2、谈谈你对广播的理解?
- 3、java里怎么发广播呀
- 4、Android系统广播(Broadcast)注册,发送,接收流程解析
java socket,我有客户端和服务器的代码,帮我添加广播和能多人会话,加分!!代码如下
根据你的改了个!不好意思,其中读写的思路稍微有点不同!不过可以做参考!
Server端代码:
import java.net.*;
import java.io.*;
import java.util.*;
public class TestServer {
ServerSocket s = null;
boolean started = false;//用来监听服务器是否启动!
ListServerReaderWriter clients = new ArrayListServerReaderWriter();//用来存放启动的客服端
public static void main(String[] args) {
new TestServer().start();
}
public void start() {
try {
s = new ServerSocket(5050);
started = true;
} catch(SocketException e) {
System.out.println("5050端口正在使用中!!!请关掉相关程序并重新运行服务器!");
System.exit(0);
} catch (IOException e) {
e.printStackTrace();
}
int i = 1;
try {
while(started) {
Socket ss = s.accept();
ServerReaderWriter c = new ServerReaderWriter(ss);//建立客服端
System.out.println("第" + i + "个客服端启动!");
++i;
new Thread(c).start();//启动线程
clients.add(c);
}
} catch (EOFException e) {
System.out.println("客服端被关闭!");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
class ServerReaderWriter implements Runnable { //建议使用Runnable避免你重写run方法麻烦!
private Socket s;
private DataInputStream dis = null;//注意赋值,养成好习惯!
private DataOutputStream dos = null;
private boolean bConnected = false;//用于调用连接成功后的run方法
public ServerReaderWriter(Socket s) {
this.s = s;
try {
dis = new DataInputStream(s.getInputStream());
dos = new DataOutputStream(s.getOutputStream());
bConnected = true;
} catch (IOException e) {
e.printStackTrace();
}
}
public void send(String str) {
try {
dos.writeUTF(str);
} catch (IOException e) {
clients.remove(this);
System.out.println("有客户退出!");
}
}
public void run() {
try {
while (bConnected) {
String input = dis.readUTF();
System.out.println(input);
for(int i=0; iclients.size(); ++i) {
ServerReaderWriter c = clients.get(i);
c.send(input);
}
}
} catch(SocketException e) {
System.out.println("一个客服端已关闭,请勿再像他发送信息!");
} catch (EOFException e) {
System.out.println("谢谢使用!");
}catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (dis != null) {
dis.close();
}
if (dos != null) {
dos.close();
}
if (s != null) {
s.close();
s = null;
}
//clients.clear();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
}
Client端代码:
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
public class TestClient extends Frame { //用到Frame生产界面比较直观
Socket s = null;
DataOutputStream dos = null;
DataInputStream dis = null;
private boolean bConnected = false;
TextField tfText = new TextField();
TextArea taContent = new TextArea();
Thread tRecv = new Thread(new ClientReaderWriter());
public static void main(String[] args){
new TestClient().launchFrame();
}
public void launchFrame() {
this.setSize(300, 300); //设置客服端窗口格式
this.setLocation(400, 300);
add(tfText, BorderLayout.SOUTH);
add(taContent, BorderLayout.NORTH);
this.pack();
this.addWindowListener(new WindowAdapter() { //监听窗口关闭事件
public void windowClosing(WindowEvent arg0) {
disconnect();
System.exit(0);
}
});
tfText.addActionListener(new TFListener());
setVisible(true);
connect();
tRecv.start();
}
public void connect() {
try {
s = new Socket("127.0.0.1", 5050); //依据自己的服务器,我这里用的localhost
dos = new DataOutputStream(s.getOutputStream());
dis = new DataInputStream(s.getInputStream());
System.out.println("连接服务器!");
bConnected = true;
} catch(ConnectException e) {
System.out.println("请检查服务器是否启动!");
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
System.exit(0);
}
catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public void disconnect() {
try {
dos.close();
dis.close();
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private class TFListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
String str = tfText.getText().trim();
tfText.setText("");
try {
dos.writeUTF(str);
if(str.equals("bye")){
System.exit(0);
}
dos.flush();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
class ClientReaderWriter implements Runnable {
public void run() {
try {
while(bConnected) {
String input = dis.readUTF();
taContent.setText(taContent.getText() + input +'\n');
}
} catch (SocketException e) {
System.out.println("轻轻的我走了!Bye-bye!");
} catch (EOFException e) {
System.out.println("我断网了,再见!");
}
catch (IOException e) {
e.printStackTrace();
}
}
}
}
谈谈你对广播的理解?
广播就是用来发送/接收一系列通知的组件,它是四大组件之一,常用于进程间的通信。
低耦合高内聚:如果两个组件之间需要通信的话,可以通过获取组件之间的实例,但是这种方法无疑增加了耦合,不是很好,而使用广播,可以不需要获取对方的实例就能拿到想到的数据,当然还有更方便的事件总线机制,这里只是举个例子。它不仅可以使用在组件之间的通信,还有使用在进程间通信,程序保活等。
a.有序广播
b.无序广播
c.普通广播
d.粘性广播
e.本地广播
f.系统广播
首先需要一个广播接收器
然后注册广播, 注册可分为静态和动态注册:
1.动态注册:
这里要注意的是在程序销毁之前要解绑该广播,防止造成内存泄漏。
2.静态注册:
静态注册是通过在xml中完成的
最后就是发送广播:
这里需要特别说明一下本地广播,其他的广播可以存在被人拦截或者被人攻击的情况,所以安全性不是很高,所以就出了本地广播,这套机制只能接收应用程序内部的广播,所以就不存被人拦截或者攻击的情况。
广播的发送不变。
a.广播不会发送消息给已经停止的应用
b.Android 7.0屏蔽了某些广播事件,如: 后台程序无法监听网络状态,不允许静态注册,防止应用无节操地恶意唤醒
c.某些三方ROM(如:MUI/EMUI)也限制了某些广播事件,如:华为 EMUI 需要设置允许当前程序开机启动才允许监听 BOOT_COMPLETED
d.onReceiver()方法不要执行特别耗时的操作,耗时操作可以放到Service组件中
e.LocalBroadcastManager 不会有应用劫持广播信息的情况 ,只有 BroadcastManager 才会出现 ,所以 如果不是跨进程的话可以用 LocalBroadcastManager 完全替代 Broadcastreceive
是通过binder实现的,这个暂时不了解,后续会继续研究。
1.静态广播和动态广播哪一个先接收到?
答:动态优先静态,具体原因可以翻看ActivityManagerService(.../sdk/sources/android-xx/com/android/server/am/ActivityManagerService.java)的源码,可以根据sendBroadcast去一步一步的往下跟,最后你会发现,先遍历动态广播再静态广播,所以动态广播优先于静态。
java里怎么发广播呀
java里怎么发广播
public void onReceive(Context context,Intent intent){
Intent intent = new Intent(context,XxxService.class);
context.startService(intent);
}
Intent intent = new Intent();
intent.setAction("...");
Context.sendBroadcast(intent);
Android系统广播(Broadcast)注册,发送,接收流程解析
以下广播简称Broadcast
是Android四大组件之一,在四大组件的另外两个组件 和 拥有发送和接收广播的能力。Android 是在 进程间通信机制的基础上实现的,内部基于消息发布和订阅的事件驱动模型,广播发送者负责发送消息,广播接收者需要先订阅消息,然后才能收到消息。 进程间通信与 的区别在于:
有三种类型
存在一个注册中心,也可以说是一个调度中心,即 。广播接收者将自己注册到 中,并指定要接收的广播类型;广播发送者发送广播时,发送的广播首先会发送到 , 根据广播的类型找到对应的 ,找到后边将广播发送给其处理。
这里以普通广播为例子, 接收者有两种注册方式,一种是 ,一种是 :
(广播的发送分为 两种,这里针对有序的广播) 中的android:priority=""和 中的IntentFilter.setPriority(int)可以用来设置广播接收者的优先级,默认都是0 , 范围是[-1000, 1000],值越大优先级越高,优先级越高越早收到。
在相同优先级接收同个类型广播时, 的广播接收器比 的广播接收者更快的接收到对应的广播,这个之后会进行分析。
注:以下源码基于rk3399_industry Android7.1.2
的流程可分为 , 和 三个部分,这里依次分析下
在Android系统的 机制中,前面提到, 作为一个注册和调度中心负责注册和转发 。所以 的注册过程就是把它注册到 的过程。
这里我们分析 广播的过程, 和 有一个共同的父类 ,所以它们对应的注册过程其实是调用 ,接下来我们按照流程逐步分析调用流程的源码。
frameworks/base/core/java/android/content/ContextWrapper.java
在之前的 Android应用程序启动入口ActivityThread.main流程分析 分析过,在我们启动 Activity 时会创建一个 对象,然后通过 传给我们启动的 ,其内部就会将该对象赋值给 ; 的 方法也是类似的赋值流程,这里放个简易的源码应该更好理解
可以看到最后都会将生成的 对象赋值给对应的
对象。接下来继续分析 , 即 函数。
/frameworks/base/core/java/android/app/ContextImpl.java
这里我们首先看下如何将广播接收者 封装成一个 接口的 本地对象
/frameworks/base/core/java/android/app/LoadedApk.java
每一个注册过广播接收者的 或 组件在font color='Crimson' LoadedApk /font类中都有个对应的 对象,该对象负责将 与 组件关联起来。这些对象,以关联的 作为关键字保存在一个 中。之后对应的 又以 的 作为关键字保存在 的成员变量 对象中。最后通过 对应的 方法获得其 接口的 本地对象。之后再回到 注册方法内,将 对象发给 进行注册。
/frameworks/base/core/java/android/app/ActivityManagerNative.java
/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
在的 或 注册一个 时,并不是将其注册到font color='OrangeRed'AMS/font中,而是将与它关联的font color='OrangeRed'InnerReceiver/font对象注册到font color='OrangeRed'AMS/font中,当font color='OrangeRed'AMS/font接收到广播时,会根据 在内部找到对应的font color='OrangeRed'InnerReceiver/font对象,然后在通过这个对象将这个广播发送给对应的 处理。
注册过程这边画了一个简单的流程图:
font color='OrangeRed'Broadcast/font的发送过程可简单描述为以下几个过程:
frameworks/base/core/java/android/content/ContextWrapper.java
/frameworks/base/core/java/android/app/ContextImpl.java
/frameworks/base/core/java/android/app/ActivityManagerNative.java
/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java