首页 文章 精选 留言 我的

精选列表

搜索[异步加载],共10000篇文章
优秀的个人博客,低调大师

高性能异步批量ping的golang实现

一个监控项目有个需求,会对一批域名全国的边缘节点进行探测,这里包括,丢包率,http 响应时间,探测频率大概时间是2min 一个周期。这里的域名大概有几百个甚至上千。由于是golang 写的调度和agent, 所以,这里探测丢包率是一个有意思的问题。由于目前git 上没有一个好用的支持multi-ping 的库包,或者多ping 有bug,我自己实现了一个。 git 地址:https://github.com/caucy/batch_ping 1,icmp 协议介绍 icmp 的报文头部一共是2+2+4+4+4 个字节。 type ICMP struct { Type uint8 Code uint8 CheckSum uint16 Identifier uint16 SequenceNum uint16 } 这里 type 是icmp 类型,常见有发送报文头 Echo, 回收报文头 Echo Reply 等,更多类型 见 https://tools.ietf.org/html/rfc792 。 Code 进一步划分ICMP的类型,该字段用来查找产生错误的原因;CheckSum 校验码部分,这个字段包含有从ICMP报头和数据部分计算得来的,用于检查错误的数据;而Identifier 通常为进程id,标识具体是哪个进程发送的icmp 包;SequenceNum 标识发送包的顺序id。 icmp 有个特点,listen 能收到其他进程ping 的结果,看下面例子: package main import ( "log" "github.com/caucy/batch_ping" ) func main() { ipSlice := []string{} // ip list should not more than 65535 ipSlice = append(ipSlice, "3g.qq.com") bp, err := ping.NewBatchPinger(ipSlice, false) // true will need to be root if err != nil { log.Fatalf("new batch ping err %v", err) } bp.SetDebug(true) // debug == true will fmt debug log bp.SetCount(100) bp.Run() } 启动上面的进程,会连续ping 3g.qq.com,同时,再启动一个进程ping www.baidu.com , 日志会显示,收到了220.181.38.150 的icmp 包。 2, 如何支持同时支持ping 多个addr 第一种是最简单的,也是大多数探针采用的方式:subprocess 。这个方式有个缺点,就是每个任务会fork 一个进程,非常耗费耗费资源。 第二种方式,我是这样想的,golang 有icmp 包,能够支持send and recive, 我直接起协程 去 收发,每个协程和subprocess 一样,先发后等,这样不就行了?然后起一组协程池,这样并发也能控制。然而,上面例子已经提到了,listen 后的conn 能收到其他进程 ping 的结果,这样实现挺麻烦。 第三种方式,一个协程收,一个协程发。最后选择的是这种方式。 一个协程收,一个协程发,有什么比较麻烦地方?因为icmp 层只能标识seq,所以会出现icmp 包头相同的情况,同时,批量收发,非常容易出现丢包的情况。 3,batch-ping 特性 支持原地址控制 支持ipv6 (操作系统本身支持“ip6:ipv6-icmp”,“udp6” dial ) 支持时间间隔控制 支持发送方式控制 支持多addr 控制 支持 mac, linux 使用示例: package main import ( "log" "github.com/caucy/batch_ping" ) func main() { ipSlice := []string{} // ip list should not more than 65535 ipSlice = append(ipSlice, "2400:da00:2::29") //support ipv6 ipSlice = append(ipSlice, "baidu.com") bp, err := ping.NewBatchPinger(ipSlice, false) // true will need to be root if err != nil { log.Fatalf("new batch ping err %v", err) } bp.SetDebug(true) // debug == true will fmt debug log bp.SetSource("") // if hava multi source ip, can use one isp bp.OnFinish = func(stMap map[string]*ping.Statistics) { for ip, st := range stMap { log.Printf("\n--- %s ping statistics ---\n", st.Addr) log.Printf("ip %s, %d packets transmitted, %d packets received, %v%% packet loss\n", ip, st.PacketsSent, st.PacketsRecv, st.PacketLoss) log.Printf("round-trip min/avg/max/stddev = %v/%v/%v/%v\n", st.MinRtt, st.AvgRtt, st.MaxRtt, st.StdDevRtt) log.Printf("rtts is %v \n", st.Rtts) } } err = bp.Run() if err != nil { log.Printf("run err %v \n", err) } bp.OnFinish(bp.Statistics()) } 4,可能问题 因为icmp 基于udp,时间间隔非常小,发送机器非常多的时候,会出现非常严重丢包,内核参数需要优化。 最后,文章不易,希望大家点个star,试用。 https://github.com/caucy/batch_ping 。

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

Android中的异步处理技术之HandlerThread

目录 前言 众所周知如果想要在Android中执行耗时操作需要新建一个线程然后在该线程中实现,但是如果出现一种需要我们频繁进行耗时操作的业务,那我们再频繁的创建线程无疑会使性能降低,而Android SDK为我们提供了一个循环线程的框架刚好可以帮助我们解决这个问题,它就是HandlerThread。 原理 HandlerThread继承了Thread,集成了Looper和MessageQueue,在内部实现了一个消息队列,队列中的消息是顺序执行的因此线程是安全的,HandlerThread内部机制确保了在创建Looper和发送消息之间不存在竞态条件,这个是通过HandlerThread.getLooper()实现为一个阻塞操作实现的,只有当HandlerThread准备好接收消息消息之后才会返回。 public class HandlerThread extends Thread { int mPriority; int mTid = -1; Looper mLooper; public HandlerThread(String name) { super(name); mPriority = Process.THREAD_PRIORITY_DEFAULT; } /** * Constructs a HandlerThread. * @param name * @param priority The priority to run the thread at. The value supplied must be from * {@link android.os.Process} and not from java.lang.Thread. */ public HandlerThread(String name, int priority) { super(name); mPriority = priority; } /** * Call back method that can be explicitly overridden if needed to execute some * setup before Looper loops. */ protected void onLooperPrepared() { } @Override public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1; } public Looper getLooper() { if (!isAlive()) { return null; } // 如果线程已经启动那么在Looper准备好之前应该等待 synchronized (this) { while (isAlive() && mLooper == null) { try { wait(); } catch (InterruptedException e) { } } } return mLooper; } public boolean quit() { Looper looper = getLooper(); if (looper != null) { looper.quit(); return true; } return false; } public boolean quitSafely() { Looper looper = getLooper(); if (looper != null) { looper.quitSafely(); return true; } return false; } /** * Returns the identifier of this thread. See Process.myTid(). */ public int getThreadId() { return mTid; } } 实现 对外开放Handler实例 public class MainActivity extends AppCompatActivity { private HandlerThread mHandlerThread; private Handler mBgHandler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initHandler(); } private void initHandler() { mHandlerThread=new HandlerThread("myHandlerThread"); mHandlerThread.start(); mBgHandler=new Handler(mHandlerThread.getLooper(), new Handler.Callback() { @Override public boolean handleMessage(Message message) { switch (message.what){ case 0: // 执行操作 break; } return false; } }); } @Override protected void onDestroy() { super.onDestroy(); mHandlerThread.quit(); } } 对外隐藏Handler(需要继承HandlerThread并在onLooperPrepared方法中对Handler进行实例化) public class MyHandlerThread extends HandlerThread { private Handler mHandler; public MyHandlerThread(String name) { super(name); } @Override protected void onLooperPrepared() { super.onLooperPrepared(); mHandler=new Handler(getLooper(), new Handler.Callback() { @Override public boolean handleMessage(Message message) { switch (message.what){ case 1: Log.e("测试","executeOne"+currentThread().getName()); break; case 2: Log.e("测试","executeTwo"+currentThread().getName()); break; } return false; } }); } public void executeOne(){ mHandler.sendEmptyMessage(1); } public void executeTwo(){ mHandler.sendEmptyMessage(2); } } Activity中调用 public class MainActivity extends AppCompatActivity { private TextView tvMainactivityTest; private MyHandlerThread myHandlerThread; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tvMainactivityTest = (TextView) findViewById(R.id.tv_mainactivity_test); initHandler(); } private void initListener() { tvMainactivityTest.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { myHandlerThread.executeOne(); } }); } private void initHandler() { myHandlerThread=new MyHandlerThread("workThread"); myHandlerThread.start(); } } 个人技术博客https://myml666.github.io/

资源下载

更多资源
Mario

Mario

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

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

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

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册