首页 文章 精选 留言 我的

精选列表

搜索[分享平台],共10003篇文章
优秀的个人博客,低调大师

Android -- 经验分享(二)

目录 自定义两个View进行画图,让其各自刷新重绘 Activity设为singleTop,长按Home键启动的问题 Activity设为singleTop,长按Home键启动问题 Android软键盘挡住界面 Android使用AsyncTask下载图片,最好使用WeakReference Android webview 加载网络视频 Android 开发中的网络下载策略 与 文件缓存策略 Android中ListView的addFooterView不显示的问题 Android自动弹出软键盘 自定义两个View进行画图,让其各自刷新重绘 我将屏幕分为左右两部分,并且自定义了绘图类drawOneView和drawTwoView,它们都继承View类,其中drawOneView在屏幕左边显示,drawTwoView在右边显示,在drawOneView中能够通过invalidate()函数,使其重绘,但是在drawTwoView中就不能通过invalidate()函数使drawTwoView进行重绘了,这是为什么呢?并且当drawOneView进行重绘的时候,怎么也会带动drawTwoView重绘,它们应该是分别由各自的类进行控制的,为什么会出现这种情况呢? 一个用Invalidate(),另外一个用postInvalidate()就可以刷新了 就是在你需要刷新UI的地方分别调用Invalidate(),postInvalidate()就可以了。 Activity设为singleTop,长按Home键启动的问题 若将Activity设置为singleTop的,则,按Home键之后,再长按启动时候,Home键的启动机制里面,好像会重新启动被设置为singleTop的Activity,尽管你的singleTop的Activity已经finish或者整个程序已经结束了。 目前的解决办法是:做标记,然后在被设置为singleTop的Activity里做拦截。 Android软键盘挡住界面 AndroidManifest.xml 中设置 android:windowSoftInputMode="stateUnspecified|adjustPan" 不挤压屏幕,反之为把界面挤压上去。 <activity android:name=".activity.MainTabActivity" android:theme="@android:style/Theme.NoTitleBar" android:configChanges="keyboardHidden|orientation" android:screenOrientation="portrait" android:launchMode="singleTask" android:windowSoftInputMode="stateUnspecified|adjustPan"> </activity> 需要注意的是:如果是TabActivity里面的一个Activity有EditText有软键盘弹出的时候,在该Activity设置没有作用,需要在TabActivity里设置。 Android使用AsyncTask下载图片,最好使用WeakReference 有些人喜欢用Android提供的AsyncTask,但事实上AsyncTask的问题更加严重,Thread只有在run函数不结束时才出现这种内存泄露问题,然而AsyncTask内部的实现机制是运用了ThreadPoolExcutor,该类产生的Thread对象的生命周期是不确定的,是应用程序无法控制的,因此如果AsyncTask作为Activity的内部类,就更容易出现内存泄露的问题。 这种线程导致的内存泄露问题应该如何解决呢? 第一、将线程的内部类,改为静态内部类。 第二、在线程内部采用弱引用保存Context引用。 解决的模型如下: public abstract class WeakAsyncTask<Params, Progress, Result, WeakTarget> extends AsyncTask<Params, Progress, Result> { protected WeakReference<WeakTarget> mTarget; public WeakAsyncTask(WeakTarget target) { mTarget = new WeakReference<WeakTarget>(target); } /** {@inheritDoc} */ @Override protected final void onPreExecute() { final WeakTarget target = mTarget.get(); if (target != null) { this.onPreExecute(target); } } /** {@inheritDoc} */ @Override protected final Result doInBackground(Params... params) { final WeakTarget target = mTarget.get(); if (target != null) { return this.doInBackground(target, params); } else { return null; } } /** {@inheritDoc} */ @Override protected final void onPostExecute(Result result) { final WeakTarget target = mTarget.get(); if (target != null) { this.onPostExecute(target, result); } } protected void onPreExecute(WeakTarget target) { // No default action } protected abstract Result doInBackground(WeakTarget target, Params... params); protected void onPostExecute(WeakTarget target, Result result) { // No default action } } Android webview 加载网络视频 webView.loadUrl(video_url); webView.setInitialScale(50); WebSettings setting = webView.getSettings(); setting.setUseWideViewPort(true); setting.setJavaScriptEnabled(true); //Support JavaScript setting.setPluginsEnabled(true); //Support Plugins, for example just like flash plugin. setting.setSupportZoom(true); //Zoom Control on web (You don't need this if ROM supports Multi-Touch setting.setBuiltInZoomControls(true); //Enable Multitouch if supported by ROM webView.setWebViewClient(new MyWebViewClient()); public class MyWebViewClient extends WebViewClient { private ProgressDialog loadingBar; @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { loadingBar=ProgressDialog.show(mActivity, null, "正在加载…"); super.onPageStarted(view, url, favicon); } @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url); // webview里面的链接还在同一个页面中加载 return true; } @Override public void onPageFinished(WebView view, String url) { if(loadingBar.isShowing()){ loadingBar.dismiss(); } super.onPageFinished(view, url); } @Override public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { Toast.makeText(mActivity, "加载出错!", Toast.LENGTH_LONG).show(); final AlertDialog alertDialog = new AlertDialog.Builder(mActivity).create(); alertDialog.setTitle("ERROR"); alertDialog.setMessage(description); alertDialog.setButton("OK", new DialogInterface.OnClickListener(){ @Override public void onClick(DialogInterface dialog, int which) { alertDialog.dismiss(); } }); alertDialog.show(); } } Android 开发中的网络下载策略 与 文件缓存策略 一般的缓存策略是: 一级内存缓存、二级文件缓存(数据库也算作文件缓存)、三级网络数据 一、网络下载的缓存策略 关于网络下载文件(图片、音频、视频)的基本策略:1.不要直接下载到目标文件,应使用temp文件作中转,以确保文件的正确性与完整性,流程如下: a)以网络目标文件名 A 生成唯一的本地目标文件名 B b)以本地目标文件名 B 生成唯一的本地临时文件名 T c)下载文件到 T 中 d)下载完毕,校验文件 T 的正确性与完整性 e)若不正确或不完整则 delete 文件 T,并返回 false f)校验完毕后,将文件 T 重命名 或 复制到 B 文件 g)最后的清理现场,删除临时文件 T,成功后,返回 true2.尽力提供文件正确性与完整性的校验: a)正确性:比如 MD5/Hash Code 比对、文件格式的比对。 b)完整性:比如 文件大小是否一致、图片的数据是否正确(图片文件头中提供了相关信息)3.考虑对于下载到本地的文件是否需要再做二次加工,可以思考以下情况: a)比如网络源始图片的大小为800*600,而我们需要作为缩略图的大小为160*145,所以考虑对下载后的文件进行裁剪,再保存,对于源始文件则直接删除。 二、文件缓存策略: 1.需要唯一的缓存文件的对应I/O key,一般可以使用 hashcode。 2.若是同一个文件,以不同的时间,可以考虑,先清本地缓存,再下载新的缓存到本地。 3.同一文件也可以加上时间戳后,再生成唯一hashcode。 4.生成文件缓时,也许需要作以下全面的考虑: a)sdcard是否已经没有空间(这个需求是存在的,但几乎没有人会考虑到,一旦发生,必crash)。 b)缓存的清理策略。每日、每周定时清理?到达一个阀值后,自动清理?(若无清理策略,把垃圾数据一直当个宝一相存着,是很SB的)。 c)缓存真正需要的数据。不要觉外存是无限的,所以就可以什么都存,要知道,多则繁,繁则乱。曾经有一同事,每天存几百MB的用户数据(所有用户的性别、age、联系方式等等),而PM需要的只是一个每日数户的活跃数据报表,于是最后改为缓存每天的用户分析报表数据即可(才10几KB)。 d)给缓存文件加密。最简单就是去掉文件的扩展名,这也算加密,当然,你可以把服务端文件加密,然后在内存中解密。这就看项目的需求而定,我的经验也不足,一般就是改改扩展名之类的。 三、内存缓存策略 内存缓存策略是为了应对更加高效的缓存,对于不是频烦更新的文件数据,就可以缓存在内存中,但是有以下注意事项: a)内存的I/O,弱引用。弱引用可以让JVM更加合理、自主的回收。 b)内存缓存的 key 也必须唯一,可以参考文件缓存 key 策略。 c)提供一个内存缓存刷新的接口。虽然内存缓存本身的生命周期就较短,但它必竟是最上层的用户数据,所以设计时提供一个UI刷新接口,是可以考虑的。 Android中ListView的addFooterView不显示的问题 mListView.addFooterView(btn_more, null, false); mListView.setAdapter(mBlogListAdapter); 把addFootView放在setAdapter之前就可解决。 Android自动弹出软键盘 在onCreate中加入: // 自动调出软键盘 Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { ((InputMethodManager) getSystemService(INPUT_METHOD_SERVICE)).toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS); } }, 200); 我是天王盖地虎的分割线 本文转自我爱物联网博客园博客,原文链接:http://www.cnblogs.com/yydcdut/p/3904516.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

Android技术分享| Context浅析

类继承图 我们来看下关于 Context 的类继承图,我们通过查看源码得知,Context 是一个抽象类,所以它肯定有其实现类,查阅得知它的实现类为 ContextWrapper 和 ContextImpl ,所以它的继承图如下: 以上的 Context 类继承关系清晰简洁,可以得知,Application 、 Service 、Activity 都是继承的 Context 类,所以从这里我们可以得知: Context 数量 = Activity 数量 + Service 数量 + 1 另外,我们可以看到 Application 和 Service 都是直接继承 ContextWrapper 的而 Activity 却是继承 ContextThemeWrapper 的,这是为何?其实 ContextThemeWrapper 是关于主题类的,Activity 是有界面的,而 Application 和 Service 却没有。接下来我们来详细看下它们的源码实现。 ContextWrapper 我们进入到 ContextWrapper 源码中可以发现,它其实调用了 mBase 里面的方法,而 mBase 其实是 ContextImpl ,所以最终还是得调用它的实现类 ContextImpl 类里面的方法。 public class ContextWrapper extends Context { Context mBase; public ContextWrapper(Context base) { mBase = base; } protected void attachBaseContext(Context base) { if (mBase != null) { throw new IllegalStateException("Base context already set"); } mBase = base; } //其余的都是覆盖Context里面的方法 } 我们可以按照上面的类的继承图进行依次分析,由上面可以知道 ContextWrapper 其实是调用 ContextImpl 里面的方法,所以 Application 和 Service 还有 Activity 它们应该都跟 ContextImpl 有关的。到底是不是这样的呢?我们追踪源码进行分析。 Application 类似于 Java 的 main 启动方法程序,Android 也有一个类似的方法,那就是在 ActivityThread 类中也有一个 main ,这是开始的地方,我们从这里进行一点一点跟踪: ActivityThread#main //省略部分代码... Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); //省略部分代码... Looper.loop(); //省略部分代码... 我们找到 ActivityThread 的 main 方法,省略无关代码,这个 main 方法就是不断的从消息队列中获取消息,然后进行处理。我们本次不分析 Looper 相关的东西,只分析跟 Context 有关的内容,继续进入 attach 方法, Android 分析源码,不能一头扎进去,我们应该主要分析它的流程。 ActivityThread#attach //省略部分代码... mInstrumentation = new Instrumentation(); ContextImpl context = ContextImpl.createAppContext( this, getSystemContext().mPackageInfo); //Application的实例创建 mInitialApplication = context.mPackageInfo.makeApplication(true, null); //调用Application里面的生命周期方法onCreate mInitialApplication.onCreate(); //省略部分代码... 这里面出现了 ContextImpl ,所以下面应该会跟 Application 扯上关系,所以进入到 makeApplication 方法中继续往下追踪, LoadedApk#makeApplication //省略部分代码... Application app = null; ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this); app = mActivityThread.mInstrumentation.newApplication( cl, appClass, appContext); appContext.setOuterContext(app); //省略部分代码... 最终又进入到 Instrumentation#newApplication 方法里面 Instrumentation#newApplication static public Application newApplication(Class<?> clazz, Context context) throws InstantiationException, IllegalAccessException, ClassNotFoundException { Application app = (Application)clazz.newInstance(); app.attach(context); return app; } Application#attach /** * @hide */ /* package */ final void attach(Context context) { attachBaseContext(context); mLoadedApk = ContextImpl.getImpl(context).mPackageInfo; } 走到这里就很明清晰了,最终将会调用 ContextWrapper 的 attachBaseContext 方法。从上面到这里,如预料的一样,分析到这里,记住了多少?是不是只知道 Application 里面最终会调用 attachBaseContext 这个方法?这样的话就对了,不能一头扎进代码的海洋里,到处遨游,那样会迷失方向的,Android 源码那么大,那么多,一一细节分析根本是不大可能的,所以只能把握流程,然后再针对性的分析实现过程。接着分析 Service 里面相关的方法。 Service 对于 Service ,我们在 ActivityThread 中可以发现有个方法叫 handleCreateService ,这里面有关于 Service 和 ContextImpl 之间的联系。 ActivityThread#handleCreateService Service service = null; ContextImpl context = ContextImpl.createAppContext(this, packageInfo); context.setOuterContext(service); Application app = packageInfo.makeApplication(false, mInstrumentation); service.attach(context, this, data.info.name, data.token, app, ActivityManager.getService()); service.onCreate(); 对于 Application 的那段代码我们可以发现,这两者及其类似,我们进入到 attach 方法中查看相关代码,发现 /** * @hide */ public final void attach( Context context, ActivityThread thread, String className, IBinder token, Application application, Object activityManager) { //调用attachBaseContext方法 attachBaseContext(context); mThread = thread; // NOTE: unused - remove? mClassName = className; mToken = token; mApplication = application; mActivityManager = (IActivityManager)activityManager; mStartCompatibility = getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.ECLAIR; } 代码很简单,就是这样跟 ContextImpl 扯上关系的。因为 Service 和 Application 都是继承的 ContextWrapper 类,接下来我们来分析一下关于 Activity 的代码。 Activity 在这里说明一下为什么 Service 和 Application 都是继承的 ContextWrapper 类而 Activity 却是继承 ContextThemeWrapper 那是因为 Activity 是带有界面显示的,而 Service 和 Application 却没有,所以从名字我们可以看到 ContextThemeWrapper 包含主题的信息,同时 ContextThemeWrapper 却又是继承自 ContextWrapper ,分析 ContextThemeWrapper 源码我们可以看到,里面基本都是关于 theme 的方法,同时它也覆盖了 attachBaseContext 方法。 我们进入 Activity 源码也发现它也有和 Service 类似的 attach 方法 final void attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token, int ident, Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, NonConfigurationInstances lastNonConfigurationInstances, Configuration config, String referrer, IVoiceInteractor voiceInteractor, Window window, ActivityConfigCallback activityConfigCallback) { //省略部分代码... attachBaseContext(context); 接下来我们来分析一下 Activity 在哪里和这个扯上关系的。 ActivityThread#performLaunchActivity performLaunchActivity 这个方法其实就是启动 Activity 的方法 ,我们以后再来学习关于这个方法的内容,现在先分析 Context 的内容。我们进入到这个方法查看: //省略部分代码... ContextImpl appContext = createBaseContextForActivity(r); Activity activity = null; //省略部分代码... activity.attach(appContext, this, getInstrumentation(), r.token, r.ident, app, r.intent, r.activityInfo, title, r.parent, r.embeddedID, r.lastNonConfigurationInstances, config, r.referrer, r.voiceInteractor, window, r.configCallback); //省略部分代码... 首先通过 createBaseContextForActivity 方法创建ContextImpl 然后直接有 Activity attach 进去。到此为止,关于 Application 、Service 和 Activity 关于Context 的源码基本就差不多了。接下来我们来解决一些实际的内容。 实例理解 既然 Application、Service 和 Activity 都有 Context 那么它们之间到底有啥区别呢?同时 getApplicationContext 和 getApplication() 又有什么区别呢?接下来我们通过代码进行验证。 我们现在的项目一般都有自定义 Application 的类进行一些初始化操作,本例中也新建一个 MyApplication 的类继承自 Application,然后在Manifest.xml中进行注册,代码如下: public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); Log.d("androidos_analysis", "getApplicationContext()——> " + getApplicationContext()); Log.d("androidos_analysis", "getBaseContext() ——> " + getBaseContext()); } } 打印结果如下: getApplicationContext()——> com.ihidea.androidosanalysis.MyApp@9831cf9 getBaseContext() ——> android.app.ContextImpl@13d643e 我们发现当我们通过 getApplicationContext 获取的是我们申明的 Application 实例,而通过 getBaseContext 获取到的却是 ContextImpl 这是为什么呢?我们查看它们的实现发现 ContextWrapper#getBaseContext /** * @return the base context as set by the constructor or setBaseContext */ public Context getBaseContext() { return mBase; } 其实在上文我们已经分析过了它们的源码,我们知道其实这个mBase就是 ContextImpl 了。而 getApplicationContext ContextWrapper#getApplicationContext @Override public Context getApplicationContext() { return mBase.getApplicationContext(); } 通过上面分析我们知道 其实 Application 它本身也是一个 Context 所以,这个们返回的就是它自己了。所以这里获取getApplicationContext()得到的结果就是MyApplication本身的实例。 有时候我们代码里面也会有关于 getApplication 的用法,那么 这个跟 getApplicationContext 又有什么区别呢?我们再来log一下就知道了。 我们创建一个 MainActivity 然后在里面打印两行代码: MainActivity#onCreate Log.d("androidos_analysis", "getApplicationContext()——> " + getApplicationContext()); Log.d("androidos_analysis", "getApplication() ——> " + getApplication()); 我们可以发现 这两个返回的结果都是 一样的,其实不难理解, Activity#getApplication /** Return the application that owns this activity. */ public final Application getApplication() { return mApplication; } 其实 getApplication 返回的就是 Application 所以这两者是一样的了。但是都是返回的 Application ,Android 为什么要存在这两个方法呢?这就涉及到作用域的问题了,我们可以发现使用 getApplication 的方法的作用范围是 Activity 和 Service ,但是我们在其他地方却不能使用这个方法,这种情况下我们就可以使用 getApplicationContext 来获取 Application 了。什么情况下呢?譬如:BroadcastReceiver 我们想在Receiver 中获取 Application 的实例我们就可以通过这种方式来获取: public class MyReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { MyApplication myApp = (MyApplication) context.getApplicationContext(); //... } }

优秀的个人博客,低调大师

勒索病毒处置经验分享

勒索病毒事件愈来愈多 近期针对传统行业的勒索病毒攻击事件愈来愈多,甚至一天内会有多家同一行业的企业同时受到攻击,造成企业业务运营中断,个人和公司重要数据遭受破坏等严重安全问题。 这种情况一方面说明勒索病毒攻击已经开始组织化和行业化,另一方面也说明传统行业在信息安全方面防护能力脆弱,相比于互联网、金融等行业,在信息安全管理和安全技术方面存在更多漏洞,更容易成为勒索病毒攻击的对象。 勒索病毒危害分析 机器感染勒索病毒后,使用人员会很快发现许多常见的文件如word,excel,pdf等不能正常打开,异常现象明显,因此很容易发现并上报到IT或安全部门,如果处置及时,一般不会造成企业内大量机器感染。 但是另一方面,由于勒索病毒使用了非对称加密方式对机器上的所有数据文件进行加密,如果没有对应的解密密钥,被加密后的文件基本不可能再被解密和还原。因此对已经感染勒索病毒的个人电脑和服务器,如果之前没有及时进行数据备份,可能会因为关键数据丢失而造成无法挽回的损失。 如何正确处置勒索病毒感染事件 根据我们之前处理勒索病毒事件总结的经验,企业在发现一台或多台机器感染勒索病毒后,IT人员和安全人员可按照如下流程进行正确处置(如果企业没有设置信息安全岗位,建议立即联系第三方专业安全服务公司协助处置)。 3.1 确认勒索病毒感染迹象 勒索病毒感染后,桌面或文件夹通常会出现类似how_to_decrypt.hta网页文件,可通过浏览器打开,主要是英文信息,显示勒索提示信息及解密联系方式等; 同时很多文件被加上乱七八糟的带有勒索病毒攻击者邮箱地址信息的后缀名,文件不能被正常打开;(类似如下截图) 3.2 隔离已感染机器,避免勒索病毒进一步扩散 对存在上述勒索病毒感染迹象的机器,应立即实施网络或物理隔离,避免勒索病毒通过公司有线和无线网络继续传播。隔离方法包括: 已感染的无线上网机器,禁用无线网卡; 已感染的有线上网用户,禁用有线网卡,同时拔掉机器的物理网线; 如果同一网段有多台机器感染,可通过交换机进行断网,或修改无线网络密码; 已感染关键岗位电脑和重要服务器,立即关机,避免勒索病毒进一步加密所有文件; 专人整理感染机器列表,供后续处置; 3.3 对暂未感染勒索病毒的机器进行加固,防止可能的感染途径 勒索病毒感染一台机器后,会通过文件共享、操作系统远程利用漏洞、账号弱密码等方式,进一步获取其它机器或AD服务器的账号,从而进行全网络感染。 对暂未明确发现感染勒索病毒迹象的机器,基于勒索病毒的传播方法和传播途径,可采取一些基本的安全措施快速进行防护,避免感染。这些安全措施包括: 修改个人电脑、应用服务器、域控服务器登录密码,修改为强密码; 禁用guest账号; 统一关闭139、445端口,关闭RDP服务; 安装360、火绒等防病毒软件进行防护和查杀; 更新操作系统安全补丁; 3.4 分析已感染机器,提取病毒特征 如果能够快速定位出勒索病毒文件特征(如进程名称,执行路径,文件大小,md5值,自启动位置,进程保护文件等),可立即开始全网排查,找出网络内其它已感染的机器并进行隔离,从而减少整个勒索病毒事件的处置时间,降低勒索病毒给企业带来的危害和损失。 根据我们处置勒索病毒的经验,可优先从以下几方面进行,包括: 和感染机器人员进行深入沟通,如什么时间发现异常,之前执行过哪些操作等,可帮助快速定位可能的病毒感染源; 通过任务管理器,查看CPU、内存、IO使用率高的可疑进程(特别是文件很多的机器,勒索病毒加密需要占用大量机器资源); 安装病毒查杀工具,快速查找病毒文件,如火绒、360、clamav、BitDefender等; 安装其它系统安全工具,包括微软提供的SysinternalsSuite安全工具(autoruns64.exe,procexp64.exe,procmon.exe,tcpview.exe等),PCHunter,火绒剑等进行分析; 通过以上操作,安全人员应该可以查找出勒索病毒文件和执行进程,可进一步通过在线病毒查杀引擎快速对病毒文件进行确认,如:www.virustotal.com, www.virscan.org等网站。 对确认为勒索病毒的可执行文件,可进一步通过在线沙盘快速进行行为分析,如s.threatbook.cn,app.any.run等,确认病毒行为特征。如通过微步云沙箱对某个伪装成svchost.com文件的勒索病毒分析结果: 确认勒索病毒行为特征后,可通过停止勒索病毒进程,新建文件并观察,启动勒索病毒进程,查看文件是否被加密,进一步确认勒索病毒。 3.5 根据病毒特征,全网筛查感染机器 通过提取的勒索病毒文件名、文件路径、文件大小、文件签名、md5值、进程路径和名称等特征,可通过域控、单机或专业桌面管理工具等进行操作,迅速进行全网排查。对存在感染勒索病毒特征的机器,进行断网隔离,并删除勒索病毒文件和进程,同时持续监控是否继续感染。 另外基于勒索病毒的网络行为特征,可进一步通过交换机镜像流量分析,查找网络内是否存在已感染机器。 3.6 已感染机器处置 已感染勒索病毒的机器,可通过停止勒索病毒进程,删除保护进程或文件的方法,禁止勒索病毒运行。同时通过U盘备份未加密文件。 文件备份后,统一重新安装操作系统,并按照安全基线进行加固和检测后,部署应用和恢复数据。 3.7 勒索病毒感染溯源 勒索病毒感染途径一般包括:外网服务器存在漏洞(如应用层漏洞,RCE高危补丁未更新,账号弱密码等),钓鱼邮件附件,长期隐藏存在的APT攻击等。 勒索病毒溯源可通过对最初感染机器的人员操作行为和操作系统日志分析,企业内网络设备和安全设备日志分析等,进一步追溯原始漏洞和入侵方式。 3.8 修复感染源漏洞 如果能够追溯到最初的感染源,可有针对性地进行安全加固。如果不能追溯到原始安全漏洞,也应根据勒索病毒传播方式进行安全加固,包括安全意识宣讲,外网安全漏洞扫描和渗透,防病毒软件安装、安全补丁更新等。 3.9 安全事件总结 根据勒索病毒溯源结果,IT或安全负责人应对勒索病毒感染源情况进行说明,对感染机器、数据损失、恢复情况、恢复时间和费用等进行说明。 3.10 制定后续安全加固方案 企业感染勒索病毒的根本原因必然是在安全技术或安全管理方面存在某些漏洞,如没有安装防病毒软件对勒索病毒文件进行查杀,非IT部门员工缺乏基础的信息安全意识,随意保存和打开勒索病毒可执行文件等。这些当前存在的和潜在的各种安全漏洞和安全风险需要及时处置,并最终在多层次、多阶段建立一个统一的纵深安全防御体系。 新钛云服可以基于安全优秀实践并结合企业安全现状,从远程办公、网络安全边界、终端准入、桌面管理、防病毒、数据防泄密、日常安全服务等多方面为企业提供合适的安全防护解决方案,同时也可以在安全规范、安全意识培训等方面提供帮助。 后记 勒索病毒越演越烈的背后原因主要还是利益驱动,针对的是企业最具价值的数据,危害的是数据的可用性。后续攻击者更有可能利用APT攻击,在秘密窃取企业敏感数据后,进一步加密数据进行勒索,从而最大化攻击者价值。 对传统企业领导者和IT管理者而言,应能够认识到企业信息化转型后的IT威胁和风险影响,从而在企业信息安全建设和数据安全方面,可以给予IT部门和安全部门需要的各类安全资源,包括选择专业的第三方安全服务厂商,进而可以从安全管理和安全技术多方面进行防范,减少和避免各类信息安全事件的发生。

优秀的个人博客,低调大师

OSS 直播功能深度分享

场景描述 目前有很多直播爱好者使用的是 OSS + RTMP 做的推流直播,其中不乏一些企业级别应用,由于 OSS 作为推流的接收略微有一些复杂,故单独开篇讲一下。其实不建议使用 OSS+RTMP 做直播推流,因为功能性相比专业的阿里云直播产品来说,OSS 的推流适合监管备份等特定场景 ,客户端对直播推流的延迟要求不是很敏感。如果对直播的拉流推流延迟有高敏感的场景,建议大家使用阿里云视频直播服务,可以做到上下行链路加速,且支持多样化的直播功能适配; 使用基础 简单的直播知识 您需要了解甚至掌握简单的直播知识技巧才能熟练的使用 OSS 直播,不仅是针对 OSS 还涉及到客户端的推流等相关问题,所以需要明白直播的相关基础 【音视频头介绍】 OSS 的直播功能是建立在 RTMP 直播传输协议的基础上,所以需要指导一些基础的 RMTP 知识:RTMP 的音视频流的封装形式和 FLV 格式相似, 流媒体服务器向客户端发送包含 H264 和 AAC 的 RTMP 直播流,需要首先发送这两个 header,没有这些信息播放端是无法解码音视频流的,其中音频 tag 格式如下 1)AVC sequence header2)AAC sequence header 从上面推论出 AAC sequence header 内容的前 2 个字节是 0xAF 0x00,我们来看一个示例: 3)ADIF:Audio Data Interchange Format 音频数据交换格式。这种格式的特征是可以确定的找到这个音频数据的开始,不需进行在音频数据流中间开始的解码,即它的解码必须在明确定义的开始处进行。故这种格式常用在磁盘文件中。 4)ADTS:Audio Data Transport Stream 音频数据传输流。这种格式的特征是它是一个有同步字的比特流,解码可以在这个流中任何位置开始。它的特征类似于 mp3 数据流格式。 【RTMP 内容介绍】 以下是我对 RTMP 总结的一张完整描述图 对象存储推流架构 看下官网对于 OSS 推流的过程定义: 1)只能使用RTMP推流的方式,不支持拉流。2)必须包含视频流,且视频流格式为H264。3)音频流是可选的,并且只支持AAC格式,其他格式的音频流会被丢弃。4)转储只支持HLS协议。5)一个LiveChannel同时只能有一个客户端向其推流。 RTMP 的推流格式: demo :rtmp://your-bucket.oss-cn-hangzhou.aliyuncs.com/live/test-channel live 等同于 RTMP 的 APP 挂载点 test-channel 等同于 RTMP 的 stream name RTMP URL 推流签名: demo:rtmp://${bucket}.${host}/live/${channel}?OSSAccessKeyId=xxx&Expires=yyy&Signature=zzz&${params} 推流前 LiveChannel有两种Status:enabled和disabled,用户可以使用本接口在两种Status之间进行切换。处于disabled状态时,OSS会禁止用户向该LiveChannel进行推流操作;如果有用户正在向该LiveChannel推流,那么推流的客户端会被强制断开(可能会有10s左右的延迟) 对象存储推流的流程汇总图如下 生成推流 URL API设置推流状态API 使用 JAVA SDK 生成推流地址 我们现在用 java 的 SDK 演示一下如上的推理过程,在跑 SDK 之前,需要先搭建好一套本地的 eclipse 环境,如下是我用的 eclipse,如果有没搭建请网上搜索一下 eclipse 的搭建方式(之前需要安装 JDK 且配置环境变量) 环境要求 Eclipse 版本:Version: Neon.3 Release (4.6.3) JDK 版本:jdk1.8.0_144 OSS:公开读(为了验证推流功能是否正常,我们用公开读的方式快速测试) 我们采用主函数入口的方式,实例化其他类进行调用,这样方便类的拆分,不用都集合在主函数中。 主函数 domain,实例化 OSSClient 对象传入到 RtmpTest 类中测试。 所有的 jar 都会通过官方的 maven 解决的依赖关系,https://help.aliyun.com/document_detail/32009.html package javasdk; import java.io.FileNotFoundException; import java.text.ParseException; import java.util.HashMap; import java.util.Map; import com.aliyun.oss.OSSClient; public class domain { public static void main( String[] args ) throws ParseException, FileNotFoundException { System.out.println( "Hello World!" ); String accessid = "AK"; String secretkey = "SK"; String objectpath = "C://Users//hanli.zyb//Desktop//running.png"; String bucket = "bucket"; String object = "running"; String endpoint = "http://oss-cn-hangzhou.aliyuncs.com"; // OSS + rtmp 推流 String bucketName = "ali-hangzhou"; RtmpTest pushoss = new RtmpTest(); OSSClient ossClient = new OSSClient(endpoint, AK, SK); pushoss.testCreateLiveChannel(bucketName,ossClient); } } ​``` /* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at* http://www.apache.org/licenses/LICENSE-2.0* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.*/ package javasdk; import java.text.ParseException;import java.util.Date;import java.util.List;import junit.framework.Assert; import org.junit.Ignore;import org.junit.Test; import com.aliyun.oss.OSSClient;import com.aliyun.oss.OSSErrorCode;import com.aliyun.oss.OSSException;import com.aliyun.oss.common.utils.DateUtil;import com.aliyun.oss.model.CannedAccessControlList;import com.aliyun.oss.model.CreateLiveChannelRequest;import com.aliyun.oss.model.CreateLiveChannelResult;import com.aliyun.oss.model.ListLiveChannelsRequest;import com.aliyun.oss.model.LiveChannel;import com.aliyun.oss.model.LiveChannelInfo;import com.aliyun.oss.model.LiveChannelListing;import com.aliyun.oss.model.LiveChannelStat;import com.aliyun.oss.model.LiveChannelStatus;import com.aliyun.oss.model.LiveChannelTarget;import com.aliyun.oss.model.LiveRecord;import com.aliyun.oss.model.PushflowStatus;import com.aliyuncs.DefaultAcsClient;import com.aliyuncs.profile.DefaultProfile;import com.aliyuncs.profile.IClientProfile; /** Test rtmp*/ public class RtmpTest { String bucketName = "bucket"; final String liveChannel = "stream name"; @Test public void testCreateLiveChannelDefault(String bucketname,OSSClient ossClient) { try { CreateLiveChannelRequest createLiveChannelRequest = new CreateLiveChannelRequest( bucketName, liveChannel); CreateLiveChannelResult createLiveChannelResult = ossClient.createLiveChannel(createLiveChannelRequest); LiveChannelInfo liveChannelInfo = ossClient.getLiveChannelInfo(bucketName, liveChannel); ossClient.deleteLiveChannel(bucketName, liveChannel); } catch (Exception e) { Assert.fail(e.getMessage()); } } @Test public void testCreateLiveChannel(String bucketname,OSSClient ossClient) { final String liveChannel = "normal-create-live-channel"; final String liveChannelDesc = "my test live channel"; try { LiveChannelTarget target = new LiveChannelTarget("HLS", 100, 99, "myplaylist.m3u8"); CreateLiveChannelRequest createLiveChannelRequest = new CreateLiveChannelRequest( bucketName, liveChannel, liveChannelDesc, LiveChannelStatus.Enabled, target); CreateLiveChannelResult createLiveChannelResult = ossClient.createLiveChannel(createLiveChannelRequest); System.out.println(createLiveChannelResult.getPublishUrls()); /*Assert.assertEquals(createLiveChannelResult.getPublishUrls().size(), 1); Assert.assertTrue(createLiveChannelResult.getPublishUrls().get(0).startsWith("rtmp://")); Assert.assertTrue(createLiveChannelResult.getPublishUrls().get(0).endsWith("live/" + liveChannel)); Assert.assertEquals(createLiveChannelResult.getPlayUrls().size(), 1); Assert.assertTrue(createLiveChannelResult.getPlayUrls().get(0).startsWith("http://")); Assert.assertTrue(createLiveChannelResult.getPlayUrls().get(0).endsWith(liveChannel + "/myplaylist.m3u8"));*/ /* LiveChannelInfo liveChannelInfo = ossClient.getLiveChannelInfo(bucketName, liveChannel); Assert.assertEquals(liveChannelInfo.getDescription(), liveChannelDesc); Assert.assertEquals(liveChannelInfo.getStatus(), LiveChannelStatus.Disabled); Assert.assertEquals(liveChannelInfo.getTarget().getType(), "HLS"); Assert.assertEquals(liveChannelInfo.getTarget().getFragDuration(), 100); Assert.assertEquals(liveChannelInfo.getTarget().getFragCount(), 99); Assert.assertEquals(liveChannelInfo.getTarget().getPlaylistName(), "myplaylist.m3u8");*/ // ossClient.deleteLiveChannel(bucketName, liveChannel); } catch (Exception e) { Assert.fail(e.getMessage()); } } } 其中我们最关注的是 testCreateLiveChannel 类,创建了推流地址,其中参数 LiveChannelStatus.enable 是要让推流变为可用状态。 running 主函数,打印出推流地址。 rtmp://hangzhou.oss-cn-hangzhou.aliyuncs.com/live/normal-create-live-channel public void testCreateLiveChannel(String bucketname,OSSClient ossClient) { final String liveChannel = "normal-create-live-channel"; final String liveChannelDesc = "my test live channel"; try { LiveChannelTarget target = new LiveChannelTarget("HLS", 100, 99, "myplaylist.m3u8"); CreateLiveChannelRequest createLiveChannelRequest = new CreateLiveChannelRequest( bucketName, liveChannel, liveChannelDesc, LiveChannelStatus.Enabled, target); CreateLiveChannelResult createLiveChannelResult = ossClient.createLiveChannel(createLiveChannelRequest); System.out.println(createLiveChannelResult.getPublishUrls()); /*Assert.assertEquals(createLiveChannelResult.getPublishUrls().size(), 1); Assert.assertTrue(createLiveChannelResult.getPublishUrls().get(0).startsWith("rtmp://")); Assert.assertTrue(createLiveChannelResult.getPublishUrls().get(0).endsWith("live/" + liveChannel)); Assert.assertEquals(createLiveChannelResult.getPlayUrls().size(), 1); Assert.assertTrue(createLiveChannelResult.getPlayUrls().get(0).startsWith("http://")); Assert.assertTrue(createLiveChannelResult.getPlayUrls().get(0).endsWith(liveChannel + "/myplaylist.m3u8"));*/ // ossClient.deleteLiveChannel(bucketName, liveChannel); } catch (Exception e) { Assert.fail(e.getMessage()); } }​

优秀的个人博客,低调大师

好物分享——JavaScript编程

小笨笨给大家发福利啦!阿里云云栖社区:小笨笨qaqcnblogs:小笨笨的世界,希望大家支持1.https://files.cnblogs.com/files/sillyben/javascript-tower-platformer-master.zip2.https://files.cnblogs.com/files/sillyben/javascript-tiny-platformer-master.zip3.https://files.cnblogs.com/files/sillyben/javascript-racer-master.zip4.https://files.cnblogs.com/files/sillyben/javascript-boulderdash-master.zip 本文来自作者cnblogs同步小笨笨的世界,欢迎下载,喜欢的就点个关注哦!

优秀的个人博客,低调大师

微服务实战分享

导语喜欢踢球的同学一般知道这样的一个段子,当年有好事的记者问风头正盛的球王马拉多纳,在他进球中,哪个踢得最精彩?马拉多纳想了想就说:“一个吧”所以,努力追求“下一个”是一个普通球员到天才球员的必备品质,那么在快速互联网行业中同样如此,每一次的技术更新变革也意味着无数个追求“下一个”的互联网从事着的日日夜夜的辛勤劳动。 第一章 软件架构演进按照不同阶段使用的软件架构来排序:单体架构,垂直架构,服务化架构,微服务架构以及未来可能出现的无服务架构(ServiceLess)以及服务网格(Service Mesh)。1.单体架构单体架构在初创的小微企业比较常见,典型代表就是一个应用、一个数据库、一个Web容器就可以跑起来,但现在实际的。特点:所有功能集中在一个项目工程中,所有的功能在一个war包中,然后部署到服务上,并且可以通过集群来提高系统

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册