2012年3月30日星期五

一种高效异步IO机制



一种高效异步IO机制
     -- windows

# 背景描述
在此,简单总结一种高效的异步IO机制,话说也是在windows平台上最为高效的(没有之一)。很久之前就一直有这么一个总结的想法,可惜有时不够自信总觉得总结不到位或存在纰漏,甚至有些错误的理解吧,所以常常就搁下,放弃总结机会了。此时想法不然…即使错误理解了,那也尽快让错误更正了吧。
开始总结吧,即完成通知异步IO机制,简称IOCP。
还有一种同步非堵塞IO机制,重叠IO机制。


# 示例说明

结合Win32-API,以简单的伪代码形式描述该异步IO机制,如下:

struct asyn_io_operation
{
     WSAOVERLAPPED overlapped;
     ...
     handle_io_operation(); // do callback function when io-operation completed.
     ...
};

class more_asyn_io_operation : public asyn_io_operation
{
     ...
};

init()
{
     ...
     iocp_handle = CreateIoCompletionPort(...);
     ...
}

uninit()
{
     CloseHandle(iocp_handle);
}

post_io_handle()
{
     ...
     iocp_handle = PostQueuedCompletionStatus(iocp_handle,...);
     ...
}

commit_io_handle()
{
     ...
     asyn_io_operation* io_op_ptr = new more_asyn_io_operation(...);
     tcp_sock = socket(...);
     udp_sock = socket(...);
     ...
     WSASend(tcp_sock, ... , &io_op_ptr->overlapped, ...); //e.g 1
     ...
     WSARecv(tcp_sock, ... , &io_op_ptr->overlapped, ...); //e.g 2
     ...
     WSASendTo(tcp_sock, ... , &io_op_ptr->overlapped, ...); //e.g 3
     ...
     WSARecvFrom(tcp_sock, ... , &io_op_ptr->overlapped, ...); //e.g 4
     ...
   
     file_h = CreateFile(...);
     ...
     ReadFile(file_h, ... , &io_op_ptr->overlapped, ...); //e.g 5
     ...
     WriteFile(file_h, ... , &io_op_ptr->overlapped, ...); //e.g 6
     ...
}

main_thread_do()
{
     ...
     while (true)
     {
          ...
          LPWSAOVERLAPPED lpOverlapped;
          get_res = GetQueuedCompletionStatus(iocp_handle, ..., lpOverlapped, ...);
          asyn_io_operation* io_op_ptr = change_asyn_io_operation(lpOverlapped);
          io_op_ptr->handle_io_operation();
          ...
          delete io_op_ptr;
          ...
          if (is_exit)
               break;
     }
     ...
}

other_thread_do()
{
     ...
     commit_io_handle();
     ...
}

(... 待续 ...)



# 涉及Win32-API
http://msdn.microsoft.com/en-us/library/windows/desktop/ms741394(v=vs.85).aspx

typedef struct _WSAOVERLAPPED {
  ULONG_PTR Internal;
  ULONG_PTR InternalHigh;
  union {
    struct {
      DWORD Offset;
      DWORD OffsetHigh;
    };
    PVOID Pointer;
  };
  HANDLE hEvent;
} WSAOVERLAPPED, 
 *LPWSAOVERLAPPED;



HANDLE WINAPI CreateIoCompletionPort(
  __in          HANDLE FileHandle,
  __in          HANDLE ExistingCompletionPort,
  __in          ULONG_PTR CompletionKey,
  __in          DWORD NumberOfConcurrentThreads
);

BOOL WINAPI GetQueuedCompletionStatus(
  __in          HANDLE CompletionPort,
  __out         LPDWORD lpNumberOfBytes,
  __out         PULONG_PTR lpCompletionKey,
  __out         LPOVERLAPPED* lpOverlapped,
  __in          DWORD dwMilliseconds
);

BOOL WINAPI GetQueuedCompletionStatusEx(
  __in          HANDLE CompletionPort,
  __out         LPOVERLAPPED_ENTRY lpCompletionPortEntries,
  __in          ULONG ulCount,
  __out         PULONG ulNumEntriesRemoved,
  __in          DWORD dwMilliseconds,
  __in          BOOL fAlertable
);


BOOL WINAPI PostQueuedCompletionStatus(
  __in          HANDLE CompletionPort,
  __in          DWORD dwNumberOfBytesTransferred,
  __in          ULONG_PTR dwCompletionKey,
  __in          LPOVERLAPPED lpOverlapped
);



BOOL WSAAPI WSAGetOverlappedResult(
  __in          SOCKET s,
  __in          LPWSAOVERLAPPED lpOverlapped,
  __out         LPDWORD lpcbTransfer,
  __in          BOOL fWait,
  __out         LPDWORD lpdwFlags
);

SOCKET WSAAPI socket(
  __in          int af,
  __in          int type,
  __in          int protocol
);

SOCKET WSASocket(
  __in          int af,
  __in          int type,
  __in          int protocol,
  __in          LPWSAPROTOCOL_INFO lpProtocolInfo,
  __in          GROUP g,
  __in          DWORD dwFlags
);

int WSAIoctl(
  __in          SOCKET s,
  __in          DWORD dwIoControlCode,
  __in          LPVOID lpvInBuffer,
  __in          DWORD cbInBuffer,
  __out         LPVOID lpvOutBuffer,
  __in          DWORD cbOutBuffer,
  __out         LPDWORD lpcbBytesReturned,
  __in          LPWSAOVERLAPPED lpOverlapped,
  __in          LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);

int WSASend(
  __in          SOCKET s,
  __in          LPWSABUF lpBuffers,
  __in          DWORD dwBufferCount,
  __out         LPDWORD lpNumberOfBytesSent,
  __in          DWORD dwFlags,
  __in          LPWSAOVERLAPPED lpOverlapped,
  __in          LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);


int WSASend(
  __in          SOCKET s,
  __in          LPWSABUF lpBuffers,
  __in          DWORD dwBufferCount,
  __out         LPDWORD lpNumberOfBytesSent,
  __in          DWORD dwFlags,
  __in          LPWSAOVERLAPPED lpOverlapped,
  __in          LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);


int WSASendTo(
  __in          SOCKET s,
  __in          LPWSABUF lpBuffers,
  __in          DWORD dwBufferCount,
  __out         LPDWORD lpNumberOfBytesSent,
  __in          DWORD dwFlags,
  __in          const struct sockaddr* lpTo,
  __in          int iToLen,
  __in          LPWSAOVERLAPPED lpOverlapped,
  __in          LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);

int WSARecvFrom(
  __in          SOCKET s,
  __in_out      LPWSABUF lpBuffers,
  __in          DWORD dwBufferCount,
  __out         LPDWORD lpNumberOfBytesRecvd,
  __in_out      LPDWORD lpFlags,
  __out         struct sockaddr* lpFrom,
  __in_out      LPINT lpFromlen,
  __in          LPWSAOVERLAPPED lpOverlapped,
  __in          LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);



BOOL WINAPI ReadFile(
  __in          HANDLE hFile,
  __out         LPVOID lpBuffer,
  __in          DWORD nNumberOfBytesToRead,
  __out         LPDWORD lpNumberOfBytesRead,
  __in          LPOVERLAPPED lpOverlapped
);

BOOL WINAPI ReadFileEx(
  __in          HANDLE hFile,
  __out         LPVOID lpBuffer,
  __in          DWORD nNumberOfBytesToRead,
  __in          LPOVERLAPPED lpOverlapped,
  __in          LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);




HANDLE WINAPI CreateFile(
  __in          LPCTSTR lpFileName,
  __in          DWORD dwDesiredAccess,
  __in          DWORD dwShareMode,
  __in          LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  __in          DWORD dwCreationDisposition,
  __in          DWORD dwFlagsAndAttributes,
  __in          HANDLE hTemplateFile
);


BOOL WINAPI WriteFileEx(
  __in          HANDLE hFile,
  __in          LPCVOID lpBuffer,
  __in          DWORD nNumberOfBytesToWrite,
  __in          LPOVERLAPPED lpOverlapped,
  __in          LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);


BOOL WINAPI WriteFile(
  __in          HANDLE hFile,
  __in          LPCVOID lpBuffer,
  __in          DWORD nNumberOfBytesToWrite,
  __out         LPDWORD lpNumberOfBytesWritten,
  __in          LPOVERLAPPED lpOverlapped
);

BOOL WINAPI CancelIo(
  __in          HANDLE hFile
);

2012年3月29日星期四

许仙为白娘子而皈依佛门(法海)





许仙为白娘子而皈依佛门(法海)
     -- 《新白娘子传奇》我的小小回想

# 以前
白素贞


小时候,完全不明白许仙为啥非要到金山寺请愿法海收其为徒弟。其实真的不明白的是许仙这么傻,法海抓去了其妻白娘子破坏了其家庭,明明有着不共戴天的仇恨在里面,为何还要……

# 后来
……
2012过年放假回家,在家中碰巧和奶奶看了一段子的经典版《新白娘子传奇》(赵雅芝饰演)。正好,电视剧演到了以上描述的那一段子,白素贞被法海收服,许仙一度低迷沉沦……最后,皈依佛门,落入金山寺法海门下。
……

之后,我(真的)有些明白了为啥许仙皈依佛门,落入金山寺法海门下。表示理解。
既然法海是许仙的大仇人,那么许仙要是在这样大仇人面前能得以淡然平静地修炼,其积聚功德方为显著。足矣尽可能多地积聚功德,希望可早日救出白娘子!

# 台词
……
我记得,剧情里面有段法海与许仙的台词,在网上搜索了一番,找到如下:
法海与许仙(无视图中台词吧:-) )

法 海:许施主能够豁然醒悟,教不适往,果然慧根不浅老衲甚感欣慰。 
许 仙:我已经想通了,与其在钱塘悲伤,倒不如来金山寺修行积聚功德。 
法 海:恩,万山其实心静佛,已真透出佛随心一心恭仰本来无需到场,乃是人烦扰之身,不易修行,许施主,老衲替你辔剃烦修吧,道明。 
小和尚:师傅。 
法 海:替许施主准备。 
小和尚:是。 
法 海:许仙,老衲赐你法号道宗,朴实归依三宝之后,诸恶不做,诸善奉行,参三慎妙法,为原来舍下,倘能苦心修行不灭善根,终成正果。 
许 仙:徒儿紧记师傅教训,相信,人有善意,天必从之,人有悔意,天必怜之,我是个懵懂痴呆的负心汉,愧对结发妻子白素贞甚甚,现在跪在佛祖面前忏悔,愿将此后修行功德,回向爱妻,助她早日脱离苦海,飞登仙界。 
法 海:许施主,你到现在还是执迷不悟。 
许 仙:徒儿虽执迷,却以了悟,我娘子的罪在全因我而起,如果她不思恩情,既不必了情缘,如果她绝情背义,何至水漫金山,我再是真正的祸首,我耳根软,相信谗言,我人痴呆,辜负发妻,我是来忏悔的,就在肇祸之地忏悔,我也是来修行的,就在我仇人面前修行,如果我能见你而不怒不怨不恨,那岂不是就得道了吗,所以在你面前修行最为不易,公德却也最大最好。 
法 海:许仙,你尘念尚重不宜出家。 
许 仙:你不要找借口,我在这出家是出定了。 
法 海:许施主,万佛不止一心,你心里老是掂着别人,你怎么出家呢。 
许 仙:你心里也掂着别人,不是也一样出家吗。 
法 海:总之施主出家的机缘尚未成熟,老衲暂时不予你剃渡。 
许 仙:禅师真奇怪,我不想出家,你千方百计骗我出家,如今我想出家,你又不要。 
法 海:许施主,佛门宽广,怎么会拒人与外呢,虽然,老衲念你孽缘已了,但痴心仍重,暂时准许你带发修行暂入门下,道明。 
--
关键这么段言辞触到了我,让我改变了先前对于许仙愚昧的误解。
“我娘子的罪在全因我而起,如果她不思恩情,既不必了情缘,如果她绝情背义,何至水漫金山,我再是真正的祸首,我耳根软,相信谗言,我人痴呆,辜负发妻,我是来忏悔的,就在肇祸之地忏悔,我也是来修行的,就在我仇人面前修行,如果我能见你而不怒不怨不恨,那岂不是就得道了吗,所以在你面前修行最为不易,公德却也最大最好。 ”

所以,最后我表示理解了,支持他(许仙)。

# 引用
台词引用于:http://tieba.baidu.com/p/115445666?pn=5



网络协议TCP-IP小节




网络协议TCP-IP小节

     --  《计算机网络》第5章 运输层. 谢希仁



# 转图
IP报文段的首部格式


TCP报文段的首部格式




# 细节

随着因特网的发展,又陆续增加了几个选项。如窗口扩大选项、时间戳选项等【rfc1323】,以后又增加了有关选择确认(SACK)选项【rfc2018】。
窗口扩大选项是为了扩大窗口。我们知道,tcp首部中窗口字段长度是16位,因此最大的窗口大小为64K字节(2^16 字节)。
……

tcp标准规定,确认推迟的时间不应超过0.5秒。若收到一连串具有最大长度的报文段,则必须每隔一个报文段就要发送一个确认【rfc 1122】。第二,捎带确认时间上并不经常发生,因为大多数程序不同时在两个方向上发送数据。
……

(选择确认SACK)
由于首部长度最多只有40字节,而指明一个边界要用掉4字节(因为序号有32位,需用4字节表示),因此在选项中最多只能指明4个字节块的边界信息,即8个边界值。另外还需两个字节,一个用来指明SACK选项,另一个用来指明这个选项要占用多少字节。
8 * 4 + 2 = 34 < 40 (字节)-- OK
10 * 4 + 2 > 40 -- OVER
……

发送窗口 -- 接收窗口(通知窗口)
发送方的发送窗口一定不能超过对方给出的接收出口值rwnd。

(待续)
……

# 附
     -- 目录预览
第5章 运输层
*5.1 运输层协议概述
5.1.1 进程之间的通信
5.1.2 运输层的两个主要协议
5.1.3 运输层的端口
*5.2 用户数据报协议UDP
5.2.1 UDP概述
5.2.2 UDP的首部格式
*5.3 传输控制协议TCP概述
5.3.1 TCP最主要的特点
5.3.2 TCP的连接
*5.4 可靠传输的工作原理
5.4.1 停止等待协议
5.4.2 连续ARQ协议
*5.5 TCP报文段的首部格式
5.6 TCP可靠传输的实现
*5.6.1 以字节为单位的滑动窗口
*5.6.2 超时重传时间的选择
5.6.3 选择确认SACK
5.7 TCP的流量控制
*5.7.1 利用滑动窗口实现流量控制
5.7.2 必须考虑传输效率
*5.8 TCP的拥塞控制
5.8.1 拥塞控制的一般原理
5.8.2 几种拥塞控制方法
5.8.3 随机早期检测RED
5.9 TCP的运输连接管理
*5.9.1 TCP的连接建立
*5.9.2 TCP的连接释放
5.9.3 TCP的有限状态机

2012年3月25日星期日

新友旧友,把酒言欢(图)

新友旧友,把酒言欢(图)

  -- 转发: 2012-03-24晚 把酒言欢



2012-03-24晚 同学数位聚餐 把酒言欢
为某位远方而来的朋友践行。他明天就要回家了!
祝他顺利!好朋友,有空常联系。

save image

- - - - - - - - - - - -
谢谢,祝你快乐!(自动添加邮件末尾签名)

Junkun Huang
-- EOF --



---------- 已转发邮件 ----------
发件人: stoneyulay@gmail.com <stoneyulay@gmail.com>
日期: 2012年3月25日 上午12:10
主题: 2012-03-04照片1
收件人: huangjunkun@gmail.com




已通过MOTOBLUR™连接