xiaobaoqiu Blog

Think More, Code Less

Ubuntu搭建FTP

想在Ubuntu下搭建一个简单ftp服务器,用于和同事之间传数据。发现了vsftpd这个工具。

1.vsftpd简介

首先,网上介绍的比较全面的资料有: vsftpd入门专题:http://os.51cto.com/art/201008/222036.htm

我见过最好的vsftpd配置教程:http://blog.csdn.net/fafa211/article/details/8095081

前者确实介绍的很全面,但是有很多内容都是属于高级主题,初级用户真的很难全部看懂。如果使用要求不搞的话,其实后者就挺合适,更适合入门级菜鸟(想我这样的)参考,我就是参考这篇文章来搭建的。另外,还有一篇:http://www.blogjava.net/stonestyle/articles/369104.html%E3%80%82

2.安装vsftpd

直接运行下面命令即可:

sudo apt-get install vsftpd

安装完毕后,默认配置下就可以直接登录fpt://ip了,比如我的IP是192.168.1.2,则直接在浏览器或者其他入口访问fpt://192.168.1.2。

默认情况下需要username和password访问,默认就是192.168.1.2的ubuntu系统中的账户。

参考文章有更详细的配置讲解。

3.参考

http://blog.csdn.net/dongtingzhizi/article/details/12028627

IO模型

本文主要想理清同步,异步,阻塞,非阻塞这几个概念;之后理解unix上的五种IO模型。

1.同步VS异步,阻塞VS非阻塞

1.1 同步VS异步

访问数据的方式,同步需要主动读写数据,在读写数据的过程中还是会阻塞;异步只需要I/O操作完成的通知,并不主动读写数据,由操作系统内核完成数据的读写。

同步(synchronous)和异步(asynchronous)是针对应用程序和内核的交互而言的:

(1).同步指的是用户进程触发I/O操作并等待或者轮询的去查看I/O操作是否就绪;
(2).异步是指用户进程触发I/O操作以后便开始做自己的事情,而当I/O操作已经完成的时候会得到I/O完成的通知;

1.2 阻塞VS非阻塞

阻塞(blocking)和非阻塞(non-blocking)是针对于进程在访问数据的时候,根据I/O操作的就绪状态来采取的不同方式,说白了是一种读取或者写入操作函数的实现方式:

(1).阻塞方式下读取或者写入函数将一直等待;
(2).非阻塞方式下,读取或者写入函数会立即返回一个状态值;

2.IO模型

《Unix网络编程卷》将unix上的IO模型分为5类:

(1).Blocking I/O
(2).Nonblocking I/O
(3).I/O Multiplexing (select and poll)
(4).Signal Driven I/O (SIGIO)
(5).Asynchronous I/O (the POSIX aio_functions).

一个读操作通常包括两个不同阶段:

(1).等待数据准备好;
(2).从内核向进程复制数据;

我们以一个从网络读数据为例,当网络数据包到达的时候,首先内核通过网卡读输入数据,数据被复制到内核的缓冲区;然后应用程序从内核中将数据拷贝到应用程序缓冲区。

以从网络读数据为例解释上面提到的5个IO模型, 即应用程序通过socket的recvfrom方法读取网络数据,关于recvfrom方法参考:http://baike.baidu.com/view/1744189.htm.

2.1 Blocking I/O

阻塞IO:应用程序调用recvfrom试图读取数据,其实是通过系统调用从网卡读取网络数据,当网络无数据可读的时候,应用程序会一直等待;当内核从网卡读取完数据,会将数据从内核缓冲区拷贝到应用程序缓冲区,当拷贝完成,应用程序调用recvfrom才算完成。示意图如下:

优势在于非常简单,等待的过程中占用的系统资源微乎其微,程序调用返回时,必定可以拿到数据; 但简单也带来一些缺点,程序在数据到来并准备好以前,不能进行其他操作;

2.2 Nonblocking I/O

非阻塞IO:应用程序调用recvfrom试图读取数据,当网络无数据可读的时候,应用程序不是一直等待,而是直接返回错误,过一段时间再去查看数据是否可读,即有一个操作时轮询(polling)。 示意图如下:

这种模式在没有数据可以接收时,可以进行其他的一些操作;实际应用中,这种I/O模型的直接使用并不常见,因为它需要不停的查询,而这些查询大部分会是无必要的调用,白白浪费了系统资源;非阻塞I/O应该算是一个铺垫,为I/O复用和信号驱动奠定了非阻塞使用的基础。

2.3 I/O Multiplexing

首先I/O多路复用的函数也是阻塞的,但是其与以上两种还是有不同的,I/O多路复用是阻塞在select,epoll这样的系统调用之上,而没有阻塞在真正的I/O系统调用如recvfrom之上。

IO复用的目的:将等待数据准备和将数据拷贝给应用这两个阶段分开处理,让一个线程(而且是内核级别的线程)来处理所有的等待,一旦有相应的IO事件发生就通知继续完成IO操作,虽然仍然有阻塞和等待,但是等待总是发生在一个线程,这时使用多线程可以保证其他线程一旦唤醒就是处理数据。

至于select、poll和epoll的区别,推荐这篇文章: http://www.cnblogs.com/Anker/p/3265058.html 。简单来说:select,poll无脑的轮询,忽略了高并发下,轮询本身成了瓶颈,而epoll使用回调实现了轮询真正需要处理的连接。

2.4 Signal Driven I/O

应用线程调用recvfrom试图读取数据,并且直接返回,不管是否有数据可读,内核线程读完数据,给发信号通知应用线程,应用线程收到信息,等待内核线程将数据拷贝给应用线程。

2.5 Asynchronous I/O

这类函数的工作机制是告知内核启动某个操作,并让内核在整个操作(包括将数据从内核拷贝到用户空间)完成后通知我们。

注意,之前的几个模型的recvfrom都是在数据拷贝完成(即第二阶段完成)才返回,而异步IO是在第一阶段直接返回并继续往下执行,数据拷贝完成后系统内核再通知应用进程。

2.6 总结

前4种都是同步IO,只有最后一种是异步IO。他们第二阶段(拷贝数据阶段)是相同的,区别在于第一阶段,同步IO第二阶段是阻塞的,即一定会阻塞于等待数据拷贝完成,而异步IO是不阻塞于数据拷贝,数据拷贝完成,内核进程会通知应用进程。

这就是同步和异步的区别:异步在整个过程都没有阻塞,而同步至少有一个步骤被阻塞(等待内核IO或者等待内核将数据拷贝给应用)。

5种IO的比较:

3.举例子

为了理解上面的理论,举例子如下:

陪女朋友逛街,逛累了,向找个地方吃饭,于是取了一个山西面馆,但是发现面馆生意比较好人比较多,而且面条都是先做的。但是这段时间又想干点别的事,比如去附近的书店看看书。于是引发了一些列的思考:

3.1 Blocking I/O

我不指定做面条需要多久,不敢出去,只能在那里坐在等。等做完,等服务员上面并且我吃调再走。

这里我们是应用线程,面条相当于等待读的数据,厨师相当于内核线程,我们需要等待初始做面条,还需要等待等服务员上面,我才能吃到我的面。

3.2 Nonblocking I/O

我不甘心在这里无聊的等待,我想在这段时间逛逛书店,但是又怕面条做好了,所有我决定取书店看一会书就回面馆看一下我的面是不是好了。如果没好继续取书店看会书再回面馆看看。结果就是来回跑了很多次。

3.3 I/O Multiplexing

我饭量比较大,同时在几个餐馆都点了饭菜,我这样来回来回看的话累死了,善良的管理员(管理所有餐馆)在前台装了一个大屏幕,上面写着每个人每个菜的状态。因此我虽然点了很多份饭菜,但只需要看屏幕就可以了。屏幕高速我某一个菜号了,我就可以去吃。

3.4 Signal Driven I/O

管理员看老是很多人来前台看状态,烦死了,于是弄来个喊号的系统,即每次有饭菜做好了,就会喊点菜的人来吃。但是,这个喊号的系统只会喊一次,并且如果同时多个菜好了,需要一个一个喊,因此部分饭菜有延时。

3.5 Asynchronous I/O

随着行业竞争加大,管理员为了提高用户体验,每次饭菜好了,让各个餐馆的服务员亲自将饭菜送到顾客的手上。

4.参考

http://www.yeolar.com/note/2012/12/15/high-performance-io-design-patterns/

http://www.cnblogs.com/zhuYears/archive/2012/09/28/2690194.html

http://yaocoder.blog.51cto.com/2668309/1308899

http://www.open-open.com/doc/view/cbb2c3363c3b49ceb5812220a9c42e42

http://www.ibm.com/developerworks/cn/linux/l-async/

Github博客加评论

想给自己的博客加评论很久了,一致没时间。今天抽了点时间,上午把google和百度检索的搞定了,下午抽时间把评论系统加上。

本文的评论是基于disqus实现的。

1.Disqus介绍

Disqus号称世界级的评论系统,对现在各种系统的支持都比较全面。

官方网站:https://disqus.com/

2.引用Disqus

2.1 注册

在Disqus官网 https://disqus.com/ 注册帐号

2.2 Universal Code

(1).Add Disqus to your site,填写自己的网址,Disqus URL和Category等

(2).Choose your platform,生成Disqus Code

这里选择Universal Code,然后会生成一段代码:

(3).引用Disqus Code

将生成的代码嵌入到我们的博客系统中,以我的博客为例,找到source/_includes/post目录下的disqus_thread.html文件,将生成的代码放到这个文件中

在source/_layouts中模板页post.html中,引入disqus_thread.html文件:

其中的page.comments,在写每篇文章的时候进行设置,如下:

1
2
3
4
5
layout: post
title: "github博客加评论"
date: 2014-12-30 17:43:36 +0000
comments: true
categories: Tools

3 效果

Tomcat Access Log配置

最近在跟一个图片请求超时的问题,需要在项目的access log中增加请求的响应时间参数。正好学习一下tomcat access log中参数的配置。

我们假设将我的工程命名为project.com,即目录的文件名为project.com。

1.配置的位置

项目conf目录下的server.xml文件,其中的AccessLogValve这个Valve的配置,比如下面这个配置:

1
2
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="access." suffix=".log" 
        pattern="%h %l %u %t "%r" %s %b "%{Referer}i" "%{User-Agent}i" %{X-Forwarded-For}i "%Dms"" resolveHosts="false"/>

2.参数详解

Tomcat AccessLogValve支持写列配置参数:

2.1 className

执行Access Log任务的类,默认是org.apache.catalina.valves.AccessLogValve;也可以使用org.apache.catalina.valves.FastCommonAccessLogValve,但这时候只支持common和combined patterns。

2.2 directory

AccessLogValve产生的Access Log文件存放目录的绝对路径或者相对路径。如果是相对路径,那么是相对$CATALINA_HOME的。如果没有指定这个参数,默认值是"logs"(相对$CATALINA_HOME)。

2.3 pattern

用于指定展示在Access Log中的各种request和response的信息字段的格式,也可以使用单词common或者combined来选择一种标准的日志形式。下一节会详细介绍。

注意优化的access只支持common和combined格式。

2.4 prefix

每个Access Log文件的文件名前缀,如果没有指定,默认是"access_log.“,如果想没有前缀,则指定一个空的字符串(zero-length string)。

2.5 resolveHosts

如果设置为true,则会通过DNS lookup将远程主机的IP地址转换成对应的主机。设置成false则跳过这个DNS lookup过程,然后在日志中直接展示IP地址。

2.6 suffix

每个Access Log文件的文件名后缀,如果没有指定,默认值是“”,如果想没有后缀,则指定一个空的字符串(zero-length string)。

2.7 rotatable

默认为true。这个参数决定是否需要切换切换日志文件,如果被设置为false,则日志文件不会切换,即所有文件打到同一个日志文件中,并且fileDateFormat参数也会被忽略。小心使用这个参数。

2.8 condition

设置是否打开条件日志,如果设置了这个参数,requests只有当ServletRequest.getAttribute()为null的时候才会被记录日志。比如这个值被设置成junk,然后当一个特定请求的ServletRequest.getAttribute(“junk”) == null的时候,这个request会被记录。使用Filters很容易在ServletRequest中设置或者不设置这个属性。

2.9 fileDateFormat

Tomcat允许指定Access Log文件名中日期格式。日期格式同时也决定了如何切换日志文件的策略,比如如果你想每小时生成一个日志文件,设置这个值为yyyy-MM-dd.HH。

3.pattern参数

pattern属性有一系列的字符串参数组成,每个参数都有前缀"%“,目前支持下面这些参数:

%a - 远程IP地址
%A - 本地IP地址
%b - 发送的字节数(Bytes sent), 不包括HTTP headers的字节,如果为0则展示'-'
%B - 发送的字节数(Bytes sent), 不包括HTTP headers的字节
%h - 远程主机名称(如果resolveHosts为false则展示IP)
%H - 请求协议
%l - 远程用户名,始终为'-'(Remote logical username from identd)
%m - 请求的方法(GET, POST等)
%p - 接受请求的本地端口
%q - 查询字符串,如果存在,有一个前置的'?'
%r - 请求的第一行(包括请求方法和请求的URI)
%s - response的HTTP状态码(200,404等)
%S - 用户的session ID
%t - 日期和时间,Common Log Format格式
%u - 被认证的远程用户, 不存在则展示'-'
%U - 请求URL路径
%v - 本地服务名
%D - 处理请求的时间,单位为毫秒
%T - 处理请求的时间,单位为秒
%I - 当前请求的线程名(can compare later with stacktraces)

另外,Access Log中也支持cookie,请求header,响应headers,Session或者其他在ServletRequest中的对象的信息。格式遵循apache语法:

%{xxx}i 请求headers的信息
%{xxx}o 响应headers的信息
%{xxx}c 请求cookie的信息
%{xxx}r xxx是ServletRequest的一个属性
%{xxx}s xxx是HttpSession的一个属性

common模式的pattern(即默认pattern参数)的格式为'%h %l %u %t “%r” %s %b'。

combined模式的pattern可以增加Referer和User-Agent headers的参数形式,每个参数用双引号包起来,引号中的内容还是上面列举的参数。比如"%{User-Agent}i"使其为”%{User-Agent}i“,即请求的User-Agent(客户端,浏览器)。

关于Common Log Format参考:http://baike.baidu.com/view/2948003.htm

3.参考

http://tomcat.apache.org/tomcat-5.5-doc/config/valve.html

如何自己的Github博客被google检索到

本文主要解决如何让自己搭建的github博客被google和百度检索到的问题。

1.html标签验证

我只实验了html标签验证的方法,因为这样侵入最小,特别是对github博客,不需要额外的创建html文件等。

google站长工具:https://www.google.com/webmasters/

百度站长工具:http://zhanzhang.baidu.com/

1.1 google

按照其提示将这段html放在head里面就ok了,比如我的博客是放在_include/head.html里面。

google还包含一系列提升文章被检索到的方案,包括提交sitemap.xml等文件。

1.2 百度

和google一样,将这段html放在head里。

2.参考

http://zyzhang.github.io/blog/2012/09/03/blog-with-github-pages-and-jekyll-seo/