Archive for November, 2014

作者:AngryFox 分类: Uncategorized November 30th, 2014 暂无评论

1.加快HTML网页装载完成的速度
默认情况html代码下载到WebView后,webkit开始解析网页各个节点,发现有外部样式文件或者外部脚本文件时,会异步发起网络请求下载文件,但如果在这之前也有解析到image节点,那势必也会发起网络请求下载相应的图片。在网络情况较差的情况下,过多的网络请求就会造成带宽紧张,影响到css或js文件加载完成的时间,造成页面空白loading过久。解决的方法就是告诉WebView先不要自动加载图片,等页面finish后再发起图片加载。
故在WebView初始化时设置如下代码:

public void int () {
    if(Build.VERSION.SDK_INT >= 19) {
        webView.getSettings().setLoadsImagesAutomatically(true);
    } else {
        webView.getSettings().setLoadsImagesAutomatically(false);
    }
}

同时在WebView的WebViewClient实例中的onPageFinished()方法添加如下代码:

@Override
public void onPageFinished(WebView view, String url) {
    if(!webView.getSettings().getLoadsImagesAutomatically()) {
        webView.getSettings().setLoadsImagesAutomatically(true);
    }
}

从上面的代码,可以看出我们对系统API在19以上的版本作了兼容。因为4.4以上系统在onPageFinished时再恢复图片加载时,如果存在多张图片引用的是相同的src时,会只有一个image标签得到加载,因而对于这样的系统我们就先直接加载。
2.自定义出错界面
当WebView加载页面出错时(一般为404 NOT FOUND),安卓WebView会默认显示一个卖萌的出错界面。但我们怎么能让用户发现原来我使用的是网页应用呢,我们期望的是用户在网页上得到是如原生般应用的体验,那就先要从干掉这个默认出错页面开始。当WebView加载出错时,我们会在WebViewClient实例中的onReceivedError()方法接收到错误,我们就在这里做些手脚:

@Override
public void onReceivedError (WebView view, int errorCode, String description, String failingUrl) {
    super.onReceivedError(view, errorCode, description, failingUrl);
    loadDataWithBaseURL(null, "", "text/html", "utf-8", null);
    mErrorFrame.setVisibility(View.VISIBLE);
}

从上面可以看出,我们先使用loadDataWithBaseURL清除掉默认错误页内容,再让我们自定义的View得到显示(mErrorFrame为蒙在WebView之上的一个LinearLayout布局,默认为View.GONE)。
3.是否存在滚动条
当我们做类似上拉加载下一页这样的功能的时候,页面初始的时候需要知道当前WebView是否存在纵向滚动条,如果有则不加载下一页,如果没有则加载下一页直到其出现纵向滚动条。首先继承WebView类,在子类添加下面的代码:

public boolean existVerticalScrollbar () {
return computeVerticalScrollRange() > computeVerticalScrollExtent();
}
computeVerticalScrollRange得到的是可滑动的最大高度,computeVerticalScrollExtent得到的是滚动把手自身的高,当不存在滚动条时,两者的值是相等的。当有滚动条时前者一定是大于后者的。
4.是否已滚动到页面底部
同样我们在做上拉加载下一页这样的功能时,也需要知道当前页面滚动条所处的状态,如果快到底部,则要发起网络请求数据更新网页。同样继承WebView类,在子类覆盖onScrollChanged方法,具体如下:

@Override
protected void onScrollChanged(int newX, int newY, int oldX, int oldY) {
    super.onScrollChanged(newX, newY, oldX, oldY);
    if (newY != oldY) {
        float contentHeight = getContentHeight() * getScale();
        // 当前内容高度下从未触发过, 浏览器存在滚动条且滑动到将抵底部位置
        if (mCurrContentHeight != contentHeight && newY > 0 && contentHeight <= newY + getHeight() + mThreshold) {
            // TODO Something...
            mCurrContentHeight = contentHeight;
        }
    }
}

上面mCurrContentHeight用于记录上次触发时的网页高度,用来防止在网页总高度未发生变化而目标区域发生连续滚动时会多次触发TODO,mThreshold是一个阈值,当页面底部距离滚动条底部的高度差<=这个值时会触发TODO。
5.远程网页需访问本地资源
当我们在WebView中加载出从web服务器上拿取的内容时,是无法访问本地资源的,如assets目录下的图片资源,因为这样的行为属于跨域行为(Cross-Domain),而WebView是禁止的。解决这个问题的方案是把html内容先下载到本地,然后使用loadDataWithBaseURL加载html。这样就可以在html中使用 file:///android_asset/xxx.png 的链接来引用包里面assets下的资源了。示例如下:

private void loadWithAccessLocal(final String htmlUrl) {
    new Thread(new Runnable() {
        public void run() {
            try {
                final String htmlStr = NetService.fetchHtml(htmlUrl);
                if (htmlStr != null) {
                    TaskExecutor.runTaskOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            loadDataWithBaseURL(htmlUrl, htmlStr, "text/html", "UTF-8", "");
                        }
                    });
                    return;
                }
            } catch (Exception e) {
                Log.e("Exception:" + e.getMessage());
            }
            TaskExecutor.runTaskOnUiThread(new Runnable() {
                @Override
                public void run() {
                    onPageLoadedError(-1, "fetch html failed");
                }
            });
        }
    }).start();
}

上面有几点需要注意:
从网络上下载html的过程应放在工作线程中
html下载成功后渲染出html的步骤应放在UI主线程,不然WebView会报错
html下载失败则可以使用我们前面讲述的方法来显示自定义错误界面

6.ViewPager里非首屏WebView点击事件不响应
如果你的多个WebView是放在ViewPager里一个个加载出来的,那么就会遇到这样的问题。ViewPager首屏WebView的创建是在前台,点击时没有问题;而其他非首屏的WebView是在后台创建,滑动到它后点击页面会出现如下错误日志:

20955-20968/xx.xxx.xxx E/webcoreglue﹕ Should not happen: no rect-based-test nodes found
解决这个问题的办法是继承WebView类,在子类覆盖onTouchEvent方法,填入如下代码:

@Override
public boolean onTouchEvent(MotionEvent ev) {
    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
        onScrollChanged(getScrollX(), getScrollY(), getScrollX(), getScrollY());
    }
    return super.onTouchEvent(ev);
}

该方法的最先提出在WebView in ViewPager not receive user inputs。
7.WebView硬件加速导致页面渲染闪烁
4.0以上的系统我们开启硬件加速后,WebView渲染页面更加快速,拖动也更加顺滑。但有个副作用就是,当WebView视图被整体遮住一块,然后突然恢复时(比如使用SlideMenu将WebView从侧边滑出来时),这个过渡期会出现白块同时界面闪烁。解决这个问题的方法是在过渡期前将WebView的硬件加速临时关闭,过渡期后再开启,代码如下:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
    webview.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}

8.避免addJavaScriptInterface带来的安全问题
使用开源项目Safe Java-JS WebView Bridge可以很好替代addJavaScriptInterface方法,同时增加了异步回调等支持,并且不存在了安全风险。
9.WebView与上层父元素的TouchMove事件冲突
在开发过程中你可能会遇到这样一种情况。端里面使用ViewPager嵌套了多个WebView页面,同时某一个WebView中的页面元素需要响应TouchMove事件。

作者:AngryFox 分类: Uncategorized November 28th, 2014 暂无评论

关于 XHProf
XHProf 是 FaceBook 开发的一个函数级别的 PHP 分层分析器。
数据收集部分是一个基于 C 的 PHP 扩展,分析报告是一系列基于 PHP 的 HTML 导航页面。
XHProf 能统计每个函数的调用次数、内存使用、CPU占用等多项重要的数据。
并且 XHProf 还能比较两个统计样本,或从多个数据样本中汇总结果。
XHProf 是分析 PHP 程序执行效率的利器,能让我们得到更底层的的分析数据。
安装 XHProf
安装之前这里说下我把第三方编译的程序都放在根目录下的 opt 目录下了, 下面用 wget 下载程序之前先进入
cd /opt
下面的步骤,应该在Linux / Unix环境下进行命令令安装

wget http://pecl.php.net/get/xhprof-0.9.2.tgz
tar zxvf xhprof-0.9.2.tgz
cd xhprof-0.9.2
cp -r xhprof_html xhprof_lib /apps/dat/web/working/xhprof.ofwho.com
cd extension
# 执行以下命令需要root权限
1
原因是xhprof绘制的是png图,graphviz-2.24.0不支持。绘图的dot拓展没装成功, 不支持PNG。
解决办法
1. 编译安装 libpng

wget http://sourceforge.net/projects/libpng/files/libpng15/1.5.13/libpng-1.5.13.tar.gz
./configure
make
make install
 2. 重装 graphviz
./configure –with-png=yes
 完成之后你就可以再去看一看View啦!
使用 XHProf
使用 XHProf 非常简单,我们只需要修改少许代码即可实现。
例如,我们需要分析代码执行时关于 CPU 和内存的数据。
xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY);
// Test Code Start
…………
// Test Code End
$xhprofData = xhprof_disable();
include_once "/home/wwwroot/xhprof.ofwho.com/xhprof_lib/utils/xhprof_lib.php";</data/ecos.cn替换成你的webroot目录>
include_once "/home/wwwroot/xhprof.ofwho.com/xhprof_lib/utils/xhprof_runs.php";</data/ecos.cn替换成你的webroot目录
$xhprofRuns = new XHProfRuns_Default();
$run_id = $xhprofRuns->save_run($xhprofData, "xh");
echo '<a target="_blank" href="http://xhprof.ofwho.com/xhprof_html/index.php?run=' . $run_id . '&source=xh">统计</a>'1
 这样,当我们运行程序之后,会在 php.ini中设置的xhprof.output_dir的地址中生成分析数据文件。
文件名类似于 4b4c239a86593.xh ,我们可以通过改变 save_run 的参数,来改变文件后缀。
同时在页面最下方会有一个“统计”的链接,点击就能查看分析数据。
由于分析可能会影响响应速度,通常我们会加上一个随机数,随机取样,而不是分析所有用户请求的执行过程。
1$randKey = mt_rand(1, 10000);
if ($randKey == 1){
xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY);
}
// Test Code Start
//…………
// Test Code End
if ($randKey == 1)
{
$xhprofData = xhprof_disable();
include_once "/home/wwwroot/xhprof.ofwho.com/xhprof_lib/utils/xhprof_lib.php";</data/ecos.cn替换成你的webroot目录>
include_once "/home/wwwroot/xhprof.ofwho.com/xhprof_lib/utils/xhprof_runs.php";</data/ecos.cn替换成你的webroot目录>
$xhprofRuns = new XHProfRuns_Default();
$run_id = $xhprofRuns->save_run($xhprofData, "xh");
echo '<a target="_blank" href="http://xhprof.ofwho.com/xhprof_html/index.php?run=' . $run_id . '&source=xh">统计</a>'
}

查看 XHProf 分析数据
例如,域名是 xhprof.ofwho.com,现在我们就可以通过 web 来查看详细的分析数据了。
1. 查看单个报告。
# 我们想要查看 4b4c239a86593.xh 这个报告的详细信息,查看链接如下:
http:// xhprof.ofwho.com/xhprof_html/index.php?run=4b4c239a86593&source=xh
2. 比较两个报告。
# 我们想比较 4b4c239a86593.xh 和 4b4c2645794f0.xh 两个报告,查看链接如下:
http:// xhprof.ofwho.com/xhprof_html/index.php?run1=4b4c239a86593&run2=4b4c2645794f0&source=xh
我们可以看到精确到函数级的分析数据,包括调用次数、CPU、内存等,还可以不断的向下跟踪。
相信如此详细的数据,将会给程序优化工作,带来巨大的帮助和便利。
参数说明
Inclusive Time 包括子函数所有执行时间。
Exclusive Time/Self Time 函数执行本身花费的时间,不包括子树执行时间。
Wall Time 花去了的时间或挂钟时间。
CPU Time 用户耗的时间+内核耗的时间
Inclusive CPU 包括子函数一起所占用的
CPU Exclusive CPU 函数自身所占用的CPU

作者:AngryFox 分类: Uncategorized November 24th, 2014 暂无评论

根据标准C库函数的定义,malloc具有如下原型:
void* malloc(size_t size);
这个函数要实现的功能是在系统中分配一段连续的可用的内存,具体有如下要求:
malloc分配的内存大小至少为size参数所指定的字节数
malloc的返回值是一个指针,指向一段可用内存的起始地址
多次调用malloc所分配的地址不能有重叠部分,除非某次malloc所分配的地址被释放掉
malloc应该尽快完成内存分配并返回(不能使用NP-hard的内存分配算法)
实现malloc时应同时实现内存大小调整和内存释放函数(即realloc和free)

服务的配置管理。包括服务发现、负载均衡及服务依赖管理。
服务之间的调度及生命周期管理。
一个完整的系统在内部是由很多小服务构成,服务之间以及服务与资源之间会存在远程调用。
每个系统的可用性不可能达到100%
各种网络及硬件问题,如网络拥堵、网络中断、硬件故障……
远程服务平均响应速度变慢
服务器平均响应速度如果慢下来,慢慢消耗掉系统所有资源,进而导致整个系统不可用。因此在分布式系统中,除了远程服务本身需要有容错设计之外,在应用层的远程调用的环节,需要有良好的容错设计。
访问MySQL的容错设计
写操作:如果master异常,直接抛异常。
读操作:如果slave有多个,先选择其中一个slave,如果获取连接失败,再选择其他的slave,如果全部不可用,最后选择master。
访问Memcached/Redis的容错设计
首先设置so_timeout,避免无限制等待;服务器连接如果IO异常,设置错误标志,一段时间停止访问;出错后定期主动(比如ping Redis)或被动(当被再次访问时)探测服务是否恢复。
Failover机制:
如果连接某个node失败, 当前pool启用一致性hash切换到backup node;如果backup node没有数据,则通过另外一个服务池(数据副本)获取数据。
访问远程HTTP API的容错设计
设置so_timeout;部分场景:短超时,重试一次;另外由于HTTP service情况的多样性,业务层面还有通用的降级机制。

作者:AngryFox 分类: Uncategorized November 12th, 2014 暂无评论

案例1

static $j = 10;
static $j;

if(!$j) {
        print_r($j);
}
[root@GD6G6S06 su]# php file8.php
PHP Notice:  Use of undefined constant j - assumed 'j' in /home/su/file8.php on line 6

第一次的内存被回收了,不是退回给OS,而是退回了当初分配给PHP的一大块内存区域
验证结论:

将常量赋值给某变量,内核会大致进行以下几个步骤:
1:将此变量的refcounf_gc减1
2:将此变量放入GC buffer中,当回收垃圾条件成熟时,回收内存
3:从php启动时已获取的一大片内存中为该变量分配一些内存
4:初始化此内存,例如赋值,拷贝构造函数
5: 将变量name 和 def所对应的val放入 symbol_table 符号表中, 没找相应代码
通过VLD,可定位具体的分配函数 ZEND_ASSIGN_SPEC_CV_CONST_HANDLER

//zend_execute.c
static inline zval* zend_assign_const_to_variable(zval **variable_ptr_ptr, zval *value TSRMLS_DC)
{
    zval *variable_ptr = *variable_ptr_ptr; //变量的值赋给另一个变量,$a=1,即把$a的值传给另一个变量,只不过是指针
    zval garbage;

     /**
         *针对对象的赋值,以后再分析
      */

    if (Z_TYPE_P(variable_ptr) == IS_OBJECT &&
        UNEXPECTED(Z_OBJ_HANDLER_P(variable_ptr, set) != NULL)) {
        Z_OBJ_HANDLER_P(variable_ptr, set)(variable_ptr_ptr, value TSRMLS_CC);
        return variable_ptr;
    }

     if (UNEXPECTED(Z_REFCOUNT_P(variable_ptr) > 1) &&  //左值的引用个数为1或0 AND 不是引用类型
         EXPECTED(!PZVAL_IS_REF(variable_ptr))) { //左值不是个引用,而且可能多个变量共同使用左值的那个zval地址
        /* we need to split */
        Z_DELREF_P(variable_ptr);             //将refcount_gc减1
        GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr);   //放到gc root缓冲区中
        ALLOC_ZVAL(variable_ptr);             //为左值 分配内存

        INIT_PZVAL_COPY(variable_ptr, value);
        zval_copy_ctor(variable_ptr);
        *variable_ptr_ptr = variable_ptr;
        return variable_ptr;
     } else {
        if (EXPECTED(Z_TYPE_P(variable_ptr) <= IS_BOOL)) {
            /* nothing to destroy */
            ZVAL_COPY_VALUE(variable_ptr, value);
            zendi_zval_copy_ctor(*variable_ptr);
        } else {
            ZVAL_COPY_VALUE(&garbage, variable_ptr);
            ZVAL_COPY_VALUE(variable_ptr, value);
            zendi_zval_copy_ctor(*variable_ptr);
            _zval_dtor_func(&garbage ZEND_FILE_LINE_CC);
        }
        return variable_ptr;
    }
}

案例2

static $i;
$i++;
print_r($i);

static $i = 3;
$i++;
print_r($i);
在centos5.8上执行 输出45 在windows64位输出56
作者:AngryFox 分类: Uncategorized November 10th, 2014 暂无评论

在2001年定义的RFC3164中,描述了BSD syslog协议:

http://www.ietf.org/rfc/rfc3164.txt

约定发送syslog的设备为Device,转发syslog的设备为Relay,接收syslog的设备为Collector。Relay本身也可以发送自身的syslog给Collector,这个时候它表现为一个Device。Relay也可以只转发部分接收到的syslog消息,这个时候它同时表现为Relay和Collector。
syslog消息发送到Collector的UDP 514端口,不需要接收方应答,RFC3164建议 Device 也使用514作为源端口。规定syslog消息的UDP报文不能超过1024字节,并且全部由可打印的字符组成。完整的syslog消息由3部分组成,分别是PRI、HEADER和MSG。大部分syslog都包含PRI和MSG部分,而HEADER可能没有。
syslog的格式
下面是一个syslog消息:
<30>Oct 9 22:33:20 hlfedora auditd[1787]: The audit daemon is exiting.
其中“<30>”是PRI部分,“Oct 9 22:33:20 hlfedora”是HEADER部分,“auditd[1787]: The audit daemon is exiting.”是MSG部分。
按严重程度由低到高排序:
debug 不包含函数条件或问题的其他信息
info 提供信息的消息
none 没有重要级,通常用于排错
notice 具有重要性的普通条件
warning 预警信息
err 阻止工具或某些子系统部分功能实现的错误条件
crit 阻止某些工具或子系统功能实现的错误条件
alert 需要立即被修改的条件
emerg 该系统不可用

[root@GD6G6S06 logs]# service syslog restart
Shutting down kernel logger: [  OK  ]
Shutting down system logger: [  OK  ]
Starting system logger: [  OK  ]
Starting kernel logger: [  OK  ] 
作者:AngryFox 分类: Uncategorized November 9th, 2014 暂无评论

11-09 03:16:30.729: W/dalvikvm(15964): threadid=1: thread exiting with uncaught exception (group=0x41d6d438)
AndroidManifest.xml
报出类似的错误,运行到虚拟机时activity异常终止,问题出在AndroidManifest.xml中多了一条activity注册语句或未注册
E/PhonePolicy(28721): Could not preload class for phone policy: com.android.internal.policy.impl.PhoneWindow$ContextMenuCallback

通过VideoView和MediaController播放视频
(1)修改新建项日的rcs\layout目录下的布局文件main.xml,将默认添加的Text View组件删除,然后在默认添加的线性布局管理器中添加一个VideoView组件用于播放视频文件。关键代码如下:

 <VideoView
        android:id="@+id/vip_video_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center" />

(2)打开默认添加的MainActivity,在该类中,声明一个VideoView对象,具体代码如下:
private VideoView video;
(3)在onCreateO方法中,首先获取布局管理器中添加的VideoYew组件。并创建一个要括放视预所对应的对象。然后创建一个MediaController对象,用于控制视频的播放。最后判断要播放的视频文件是否存在。如果存在,使用VideoView播放该视频,否则弹出消息提示框显示提示信息,具体代码如下:

	video = (VideoView)findViewById(R.id.vip_video_view);
		File file = new File("/storage/sdcard0/wandoujia/video/y.mp4");
		MediaController mc= new MediaController(VipVideoDetailActivity.this);
		if(file.exists()) {
			video.setVideoPath(file.getAbsolutePath());
			video.setMediaController(mc);
			video.requestFocus();
			try{
				video.start();
			}catch(Exception e){
				e.printStackTrace();
			}
		}
作者:AngryFox 分类: Uncategorized November 7th, 2014 暂无评论

服务端

package main

import (
    "bytes"
    "encoding/binary"
    "fmt"
    "io"
    "net"
)

func main() {
    // 监听端口
    ln, err := net.Listen("tcp", ":6000")
    if err != nil {
        fmt.Printf("Listen Error: %s\n", err)
        return
    }

    // 监听循环
    for {
        // 接受客户端链接
        conn, err := ln.Accept()
        if err != nil {
            fmt.Printf("Accept Error: %s\n", err)
            continue
        }

        // 处理客户端链接
        go handleConnection(conn)
    }
}

func handleConnection(conn net.Conn) {
    // 关闭链接
    defer conn.Close()

    // 客户端
    fmt.Printf("Client: %s\n", conn.RemoteAddr())

    // 消息缓冲
    msgbuf := bytes.NewBuffer(make([]byte, 0, 10240))
    // 数据缓冲
    databuf := make([]byte, 4096)
    // 消息长度
    length := 0
    // 消息长度uint32
    ulength := uint32(0)

    // 数据循环
    for {
        // 读取数据
        n, err := conn.Read(databuf)
        if err == io.EOF {
            fmt.Printf("Client exit: %s\n", conn.RemoteAddr())
        }
        if err != nil {
            fmt.Printf("Read error: %s\n", err)
            return
        }
        fmt.Println(databuf[:n])

        // 数据添加到消息缓冲
        n, err = msgbuf.Write(databuf[:n])
        if err != nil {
            fmt.Printf("Buffer write error: %s\n", err)
            return
        }

        // 消息分割循环
        for {
            // 消息头
            if length == 0 && msgbuf.Len() >= 4 {
                binary.Read(msgbuf, binary.LittleEndian, &ulength)
                length = int(ulength)
                // 检查超长消息
                if length > 10240 {
                    fmt.Printf("Message too length: %d\n", length)
                    return
                }
            }

            // 消息体
            if length > 0 && msgbuf.Len() >= length {
                fmt.Printf("Client messge: %s\n", string(msgbuf.Next(length)))
                length = 0
            } else {
                break
            }
        }
    }
}

客户端

package main

import (
    "bytes"
    "encoding/binary"
    "fmt"
    "net"
    "time"
)

func main() {
    // 链接服务器
    conn, err := net.Dial("tcp", "127.0.0.1:6000")
    if err != nil {
        fmt.Printf("Dial error: %s\n", err)
        return
    }

    // 客户端信息
    fmt.Printf("Client: %s\n", conn.LocalAddr())

    // 消息缓冲
    msgbuf := bytes.NewBuffer(make([]byte, 0, 1024))

    // 消息内容
    message := []byte("我是utf-8的消息")
    // 消息长度
    messageLen := uint32(len(message))
    // 消息总长度
    mlen := 4 + len(message)

    // 写入5条消息
    for i := 0; i < 10; i++ {
        binary.Write(msgbuf, binary.LittleEndian, messageLen)
        msgbuf.Write(message)
    }

    // 单包发送一条消息
    conn.Write(msgbuf.Next(mlen))
    time.Sleep(time.Second)

    // 单包发送三条消息
    conn.Write(msgbuf.Next(mlen * 3))
    time.Sleep(time.Second)

    // 发送不完整的消息头
    conn.Write(msgbuf.Next(2))
    time.Sleep(time.Second)
    // 发送消息剩下部分
    conn.Write(msgbuf.Next(mlen - 2))
    time.Sleep(time.Second)

    // 发送不完整的消息体
    conn.Write(msgbuf.Next(mlen - 6))
    time.Sleep(time.Second)
    // 发送消息剩下部分
    conn.Write(msgbuf.Next(6))
    time.Sleep(time.Second)

    // 多段发送
    conn.Write(msgbuf.Next(mlen + 2))
    time.Sleep(time.Second)
    conn.Write(msgbuf.Next(-2 + mlen - 8))
    time.Sleep(time.Second)
    conn.Write(msgbuf.Next(8 + 1))
    time.Sleep(time.Second)
    conn.Write(msgbuf.Next(-1 + mlen + mlen))
    time.Sleep(time.Second)

    // 关闭链接
    conn.Close()
}
作者:AngryFox 分类: Uncategorized November 7th, 2014 暂无评论

指定网卡
tcpdump -i lo
指定IP
tcpdump host 192.168.1.101
指定通讯双方IP
tcpdump host 192.168.1.101 and \(192.168.1.102 or 192.168.1.103\)
排除IP
tcpdump host 192.168.1.102 and not 192.168.1.103
来源IP
tcpdump src host 192.168.1.102
目标IP
tcpdump dst host 192.168.1.102
指定端口
tcpdump port 80
TCP数据
tcpdump tcp
UDP数据
tcpdump udp
打印数据包内容
tcpdump -A
写入文件
tcpdump -w data.pcap
读取文件
tcpdump -r data.pcap
显示IP不显示域名
tcpdump -n
GUI工具
CocoaPacketAnalyzer
SmartSniff
Wireshark

监听
nc -l 8888
nc -k -l 8888 # 持续监听
连接
nc 127.0.0.1 8888
检查端口
nc -v -w 5 127.0.0.1 8888
端口扫描
nc -v -w 2 -z 127.0.0.1 20-80 # -w 超时时间 -z 发送0值
nc -u -v -w 2 -z 127.0.0.1 20-80 # udp
文件传输
nc -l 8888 > data.gz
nc 127.0.0.1 8888 < data.gz
多个文件或大文件传输
nc -l 8888 | tar -C /www -xz
tar cz /www | nc 127.0.0.1 8888
加密传输
nc -l 8888 | openssl enc -aes-256-cbc -d -pass pass:dotcoo | tar -C /www -xz
tar cz /www | openssl enc -aes-256-cbc -pass pass:dotcoo | nc 127.0.0.1 8888
发送/接收
while true ; do date "+%Y-%m-%d %H:%M:%D"; done | nc 127.0.0.1 8888
nc -k -l 8888 | while read line ; do echo $line; done
请求/响应
mkfifo msg & tail -f msg | nc -k -l 8888 | while read req; do echo Request ":" $req ; echo world > msg; echo Response “:” world; done
echo hello | nc 127.0.0.1 8888
广播/订阅
# 广播 用golang 或 nodejs实现比较好
nc 127.0.0.1 8888 | while read line ; do echo $line; done # 订阅
cat list.txt | while read host port ; do echo close | nc $host $port; done # 广播
nc -k -l 8888 | while read line ; do echo $line; done # 订阅
复杂远程调用
cat << EOF | nc 127.0.0.1 80
GET / HTTP/1.1
Host: 127.0.0.1
EOF

作者:AngryFox 分类: Uncategorized November 5th, 2014 暂无评论

建立docker私有hub
docker是一个非常好用的虚拟化工具。
下面给出建立私有docker hub的方法。docker将私有hub的环境打包在registry image中
执行指令:
docker run -p 5000:5000 registry
这条指令启动一个基于registry image的cotainer。并将host主机的port 5000绑定到虚拟机的端口5000。
这样,对该host主机端口5000的任何访问都转移到虚拟机中。
上传image:
首先给image赋予一个tag
docker tag $ID $IP:$port/$name
如 docker tag b832n2b87 192.168.1.1:5000/vim
ID为image的ID,IP为host主机的IP,name为该image的名字
docker push 192.168.1.1:5000/vim
下载image:
docker pull 192.168.1.1:5000/vim

docker tag b750fe79269d 127.0.0.1:5000/mycom/base
b750fe79269d是现有image一个id,你可以从docker hub中pull,或者自己构建image。后面的部分参考上面解释。
这一步的工作主要是给image指定一个服务器地址,让docker知道往哪里push。
然后就是push,命令:
docker push 127.0.0.1:5000/mycom/base
然后等待docker push完成就可以从私有docker-registry中pull或者run了,如:
docker run 127.0.0.1:5000/mycom/base
这里直接使用本机ip,正式使用最好指定一个二级域名,这样ip变了以后也不影响使用。
私有docker-registry的使用
其实http://docs.docker.com/reference/api/registry_api/这里有docker-registry的api,
只是没有如何获取所有image列表的方法,后来查了下,可通过http://127.0.0.1:5000/v1/search查出

作者:AngryFox 分类: Uncategorized November 2nd, 2014 暂无评论

一、系统的定义:

设计如下特点的系统:
1、 有多种业务逻辑组成
2、 业务之间需要通信
3、 业务有分布式的需求。
二、 分布式系统的需求:
1、 分布式
1)、 业务逻辑可部署在多台物理机器上
2)、 可扩展性: 当性能等遇到瓶颈后,可通过扩展来解决
3)、 可重新部署
2、 业务逻辑的控制:
1)、 启动、停止
2)、 重启
3、 业务状态监控:
1)、 运行状态
2)、 资源占用情况
4、 业务逻辑更新
1)、 程序升级
2)、 配置修改
3)、 模块升级
5、 节点机器监控
6、 节点机器维护

它既是一套运维平台,也是一套运行平台。
三、系统如何满足如上需求:
为了能满足如上需求,系统需要进行了如下抽象:
1、 用“云”来描述业务逻辑
任何业务逻辑,都是一种云
云有唯一的 namespace
云之间可进行通信

2、 “云”由一组虚节点组成
虚节点具有相同的逻辑
虚节点可部署到不同的物理机器上
通过扩展虚节点数量,并将之部署到不同的物理机器上,从而满足“分布式”、“冗余”、“扩展”等需求。
虚节点最终落实为物理机器上的一个进程。

3、 将运行虚节点所需要的素材抽象为“资源”
要运行一个虚节点,通常需要准备如下素材:
1)、 容器的可执行程序
2)、 应用逻辑的动态库、脚本、配置文件
3)、 应用逻辑所需要的模块
4)、 依赖的其它库、可执行程序、脚本
把这些素材抽象为资源,并分成不同类别。
资源对应着“资源文件”
在描述一个虚节点的时候,需要指定它用到哪些资源
要运行一个虚节点,首先要获取所需要的资源文件
当资源文件更新后,可能需要重新启动虚节点。
这样,一个虚节点需要多种资源,
在运行虚节点之前,所需要的资源文件应该就绪。
如果某种资源更新后,应及时获取,并根据需要重启虚节点。
4、 通过 Agent 进程来实现分布式管理。
资源的获取、虚节点的管理,等等,都需要在屋里机器上进行。
因此,在每台物理机器上,必须部署一个 Agent 进程,作为中央控制服务的在物理机器上代言人。
Agent 进程接受中央控制服务的指令,并执行之,这些指令包括:
1)、 资源获取
2)、 虚节点控制
3)、 虚节点监控
4)、 其它
5、 让虚节点跑在相同的容器中
虚节点,最终变现为跑在某台物理机器上的服务进程
为了能对这些进程进行统一管理,我们让虚节点,跑在相同的容器中,而具体业务逻辑通过动态库来提供。
容器,提供了管理和通信等接口,可接收外部的控制,并可与其它虚节点通信。
而业务逻辑,则由动态库来提供
业务逻辑课用不同的语言开发,例如 C, C++, Java, Python
有了“中央控制服务”、”Agent进程”、“物理机器”、“云”、“虚节点”、“资源”、“统一的虚节点容器”等概念,一个分布式管理平台就具备了雏形。
1、 Agent 进程运行在“物理机器”上,接收“中央控制服务”的指令
2、 用“云”来描述业务逻辑
3、 “云”由相同逻辑的“虚节点”组成
4、 “虚节点”需要不同的“资源”
5、 “虚节点”部署到“物理机器”上,表现为一个进程
6、 “虚节点”由“统一的虚节点容器” 加上“具体的业务逻辑”等资源组成
7、 “Agent 进程”接受“中央控制服务”的质量,获取资源文件,控制“虚节点”的运行。
四、 逻辑云和物理云
分布式系统,要求业务之间需要通信,
1、 将云分为“逻辑云”和“物理云”两个层次
2、 逻辑云在系统中具有唯一的名称,且不能改变
3、 通过名称来访问“逻辑云”,由于名称不变,
4、 “物理云”描述云的虚节点的组成,“物理云”属于某个逻辑云,但名称可变化
5、 “逻辑云”与“物理云”之间需要建立“绑定关系”。
五、 云之间的通信
1、 通过“路由表”来描述一个物理云中的虚节点的分布
2、 当需要访问某个云的时候,首先获取路由表,然后根据访问策略,选择虚节点,建立连接,并进行通信。
3、 当“物理云”发生变化后,路由表需要及时更新
4、 采用亚马逊 paper 中的 DHT 环