Fox's profileFox涂鸦PhotosBlogListsMore ![]() | Help |
|
|
September 16 [古文今读] 袁枚《黄生借书说》
本文同步自游戏人生 -------------------------------------------------------------------
以前读书大多都是借书,工作后,俸去书来,捧卷在手也是人生一乐。况时代不同了,现在读书,既为扩充知识,也有工作需要,想读的时候,电子书翻起来还是不如纸质舒服。 最近买书买爽了: 9月1日,拿到了《代码大全》; 9月11日,拿到了《UNIX网络编程》v1; 9月16日,拿到了《TCP/IP详解》v2。 加上之前的《TCP/IP详解》v1、v3和《UNIX环境高级编程》,Stevens的几本经典著作就剩《UNIX网络编程》v2,但因为我不喜欢中文版第二版科海培训做的那个业余的封面(看到这个封面我就想起了读大学时的那几本教材辅助),最后第一卷选了清华大学的第三版,但第二卷好像还没有。权衡再三,还是拿下了第二版。毕竟Stevens不可能再为我们写新版了。 看了一下,只有蔚蓝书店才有这本书,为了免5元运费(满100元,是不是特傻?),加了一本《人月神话》和《人件》,虽然读大学的时候看过这两本书,但毕竟那时缺乏工程的思想,现在再读一读,还是蛮清爽的,也当收藏了。还可以弥补一下当年『黄生只能借书』的遗憾。 后面忽然发现蔚蓝书店居然还有《UNIX编程艺术(英文版)》,只好再下一单,谁让刚才那么激动呢?本来还想把K & R的《The C Programming Language》、Bjarne Stroustrup的《The Design and Evolution of C++》和《The C++ Programming Language》一并收藏的,后来纠结要不要,因为买回来真的就成收藏了,轻易自然不会再去翻了,最终还是算了,好书看过了就看过了,没有必要非得留一本。钱钟书不是说过『假如你吃了个鸡蛋觉得不错,何必认识那下蛋的母鸡呢?』 最后,为了凑齐新的一单,拿了本《深入理解计算机系统》,因为手上现在没有这样一本书。 大概瞄了一下,感觉蔚蓝书店的书还要多一些,像《UNIX网络编程》、《UNIX编程艺术》各地都缺货,它那儿居然有,而且价格没有高出去,还是等拿到书再看吧。 请移步至此阅读全文» September 15 [古文今读] 梁启超《少年中国说》
本文同步自游戏人生 -------------------------------------------------------------------
----------------------------------------------------------------------- 欣赏任公写作此文时的英姿勃发。行文犀利,气吞万里。以前途似海的年少和天下为公的担当,面对“凋尽朱颜”的西风老朽发出自己的声音,似可涤清世间陋习恶俗。 年少的时候,每个人都曾有一段“指点江山”的梦想。然人食五谷,终难免俗。到最后,只留下最初的文字在激励着一代一代的后来少年。 此处发挥五千字,暂时挥发掉。只留一个记号,以后另行说明。 ----------------------------------------------------------------------- 成都这几天忽然就降温了,上周还要整天吹冷气,现在已经需要穿秋装了,被子还没来得及加厚,结果昨晚一觉睡得有些恍惚,早上七点醒来之后,再也没睡好,以致今天一天状态都不好。今晚早点休息,一会儿躺床上看看书就睡了。 夏天快过去的时候,在老婆的压迫下,把含辛茹苦、呕心沥血留了两年的头发剪了。时间过去两周了,我这心里依然是痛不欲生。不过也好,以后再也不会理会她这种无理的要求了,我爱怎么留怎么留。 blog最近作了几点改动: o 去掉了几个多余的分类; o 加了twitter @yulefox; o 加了豆瓣(读书) @yulefox; o feed使用feedburner。 请使用GR或其他工具订阅的同学将RSS改成 http://feeds.feedburner.com/yulefox 请移步至此阅读全文» September 11 IOCP使用时常见的几个错误
本文同步自游戏人生 ------------------------------------------------------------------- 在使用IOCP时,最重要的几个API就是GetQueueCompeltionStatus、WSARecv、WSASend,数据的I/O及其完成状态通过这几个接口获取并进行后续处理。 GetQueueCompeltionStatus attempts to dequeue an I/O completion packet from the specified I/O completion port. If there is no completion packet queued, the function waits for a pending I/O operation associated with the completion port to complete. If the function dequeues a completion packet for a successful I/O operation from the completion port, the return value is nonzero. The function stores information in the variables pointed to by the lpNumberOfBytes, lpCompletionKey, and lpOverlapped parameters. 除了关心这个API的in & out(这是MSDN开头的几行就可以告诉我们的)之外,我们更加关心不同的return & out意味着什么,因为由于各种已知或未知的原因,我们的程序并不总是有正确的return & out。 If *lpOverlapped is NULL and the function does not dequeue a completion packet from the completion port, the return value is zero. The function does not store information in the variables pointed to by the lpNumberOfBytes and lpCompletionKey parameters. To get extended error information, call GetLastError. If the function did not dequeue a completion packet because the wait timed out, GetLastError returns WAIT_TIMEOUT. 假设我们指定dwMilliseconds为INFINITE。 这里常见的几个错误有: WSA_OPERATION_ABORTED (995): Overlapped operation aborted. 由于线程退出或应用程序请求,已放弃I/O 操作。 MSDN: An overlapped operation was canceled due to the closure of the socket, or the execution of the SIO_FLUSH command in WSAIoctl. Note that this error is returned by the operating system, so the error number may change in future releases of Windows. 成因分析:这个错误一般是由于peer socket被closesocket或者WSACleanup关闭后,针对这些socket的pending overlapped I/O operation被中止。 解决方案:针对socket,一般应该先调用shutdown禁止I/O操作后再调用closesocket关闭。 严重程度:轻微易处理。 WSAENOTSOCK (10038): Socket operation on nonsocket. MSDN: An operation was attempted on something that is not a socket. Either the socket handle parameter did not reference a valid socket, or for select, a member of an fd_set was not valid. 成因分析:在一个非套接字上尝试了一个操作。 使用closesocket关闭socket之后,针对该invalid socket的任何操作都会获得该错误。 解决方案:如果是多线程存在对同一socket的操作,要保证对socket的I/O操作逻辑上的顺序,做好socket的graceful disconnect。 严重程度:轻微易处理。 WSAECONNRESET (10054): Connection reset by peer. 远程主机强迫关闭了一个现有的连接。 MSDN: An existing connection was forcibly closed by the remote host. This normally results if the peer application on the remote host is suddenly stopped, the host is rebooted, the host or remote network interface is disabled, or the remote host uses a hard close (see setsockopt for more information on the SO_LINGER option on the remote socket). This error may also result if a connection was broken due to keep-alive activity detecting a failure while one or more operations are in progress. Operations that were in progress fail with WSAENETRESET. Subsequent operations fail with WSAECONNRESET. 成因分析:在使用WSAAccpet、WSARecv、WSASend等接口时,如果peer application突然中止(原因如上所述),往其对应的socket上投递的operations将会失败。 解决方案:如果是对方主机或程序意外中止,那就只有各安天命了。但如果这程序是你写的,而你只是hard close,那就由不得别人了。至少,你要知道这样的错误已经出现了,就不要再费劲的继续投递或等待了。 严重程度:轻微易处理。 WSAECONNREFUSED (10061): Connection refused. 由于目标机器积极拒绝,无法连接。 MSDN: No connection could be made because the target computer actively refused it. This usually results from trying to connect to a service that is inactive on the foreign host—that is, one with no server application running. 成因分析:在使用connect或WSAConnect时,服务器没有运行或者服务器的监听队列已满;在使用WSAAccept时,客户端的连接请求被condition function拒绝。 解决方案:Call connect or WSAConnect again for the same socket. 等待服务器开启、监听空闲或查看被拒绝的原因。是不是长的丑或者钱没给够,要不就是服务器拒绝接受天价薪酬自主创业去了? 严重程度:轻微易处理。 WSAENOBUFS (10055): No buffer space available. 由于系统缓冲区空间不足或列队已满,不能执行套接字上的操作。 MSDN: An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full. 成因分析:这个错误是我查看错误日志后,最在意的一个错误。因为服务器对于消息收发有明确限制,如果缓冲区不足应该早就处理了,不可能待到send/recv失败啊。而且这个错误在之前的版本中几乎没有出现过。这也是这篇文章的主要内容。像connect和accept因为缓冲区空间不足都可以理解,而且危险不高,但如果send/recv造成拥堵并恶性循环下去,麻烦就大了,至少说明之前的验证逻辑有疏漏。 WSASend失败的原因是:The Windows Sockets provider reports a buffer deadlock. 这里提到的是buffer deadlock,显然是由于多线程I/O投递不当引起的。 解决方案:在消息收发前,对最大挂起的消息总的数量和容量进行检验和控制。 严重程度:严重。 本文主要参考MSDN。 ************* 说明 ************* Fox只是对自己关心的几个错误和API参照MSDN进行分析,不提供额外帮助。 请移步至此阅读全文» September 10 Amdahl 定律 = Gustafson定律
本文同步自游戏人生 ------------------------------------------------------------------- 周伟明老师应该是多核计算领域的老人了。 这几日因为想找找无锁(lock-free)方面的信息,就打开了周老师的blog。看到多核系统中三种典型锁竞争的加速比分析这篇文章时,觉得老师强调多核计算效率是有必要的,但拿Amdahl 定律和Gustafson定律作对比有点不恰当。 按照我的理解,这两个定律所刻画的内容是完全一致的,只是对加速比的定义不一样罢了。这里,我们都以S(n)表示n核系统对具体程序的加速比,K表示串行部分计算时间比例。 Amdahl 定律的加速比:S(n) = 使用1个处理器的串行计算时间 / 使用n个处理器的并行计算时间 S(n) = 1/(K+(1-K)/n) = n/(1+(n-1)K) Gustafson定律的加速比:S(n) = 使用n个处理器的并行计算量 / 使用1个处理器的串行计算量 S(n) = K+(1-K)n 通俗的讲,Amdahl 定律将工作量看作1,有n核也只能分担1-K的工作量;而Gustafson定律则将单核工作量看作1,有n核,就可以增加n(1-K)的工作量。 这两个计算公式都没有将锁开销考虑在内,是理想化的。周老师提到设计不当造成并行变串行的问题与这两个公式计算无关。因为任何多核计算都存在对串行和并行的设计考量,这正是程序员在使用多核并行时最关心的事情。 总之,二者的区别只在于态度的不同:一个消极悲观,一个积极乐观,充其量是一个冷笑话,而于多核计算没有任何关联。 我说这些也与多核计算没有关联,丝毫没有质疑多核效率的意思。相反,我期待能够通过技术层面提高多核的有效负载。 最后一句题外话,周老师使用Word的水平一般:所有来自Word的截图都是在页面视图直接截,换行符和光标随处可见。请移步至此阅读全文» September 09 W. R. Stevens十年
本文同步自游戏人生 ------------------------------------------------------------------- W. R. Stevens是我敬仰的几位计算机领域的知名学者之一,先生辞世(1999年9月1日)已整整十年了。他留下的几部著述在世界范围内产生过并将持续产生深远的影响: Unix Network Programming v1-2, 1990-1998; Advanced Programming in the UNIX Environment, 1992; TCP/IP Illustrated V1-3, 1994-1996. 其中,UNP原定出版三卷,先生英年早逝,这不能不说是一个遗憾。所幸,除TCP外,UNP和APUE均有人续写或编写新版。 读书的时候虽然粗浅学习过TCP,但离开学校之后也就渐渐忘却了,而对TCP实战经验也仅仅停留在Win API使用上。这次因工作和兴趣使然,慢慢发现理论的效用,希望可以将这几本经典之作细细读一读。 上次在书店只是购回了TCP v1, v3,这几日终于看到UNPv1(cn E3)到货,立马入手,顺便把TCP v2一起买了。 晚上在家便翻看一会儿,大热天的,说不上如沐春风,怎么也算是苦热中的一件乐事了。 请移步至此阅读全文» September 01 ACE: Socket封装(01)
本文同步自游戏人生 ------------------------------------------------------------------- o *__ 序 __* o 在阅读ACE代码和C++NPv1, v2, APG的时候,我意识到一个问题:虽然稍有C++和网络基础的同学都可以读懂ACE,但如果你对OS(五大管理模块都包含在内)、TCP/IP、C++、Design Patterns了解越多,你就越能体会ACE为什么需要这么庞杂,虽然它不够完美(但至少我还没有资格来批评这一点,我现在最常想做的一个动作就是五体投地)。 而且我隐约感觉到,我现在所写的很多东西在以后(对于有些人或许就是现在)看来会相当不深刻、相当不严谨,但对于一段学习历程,这个过程是必然的、必需的。 在C++NPv1中,Douglas C. Schmidt把原始socket及其API的缺陷有些妖魔化了,比如一段加上注释、空行在内的35行的代码,被指出有10处错误之多。这就像很多其他语言的倡导者或反传统C/C++指针者在批评指针时的说法一样。长期使用原始socket和指针的同学对此感觉很不舒服,何况socket API提供了大量错误检测的接口,至多是不够友好罢了。你好就好了,没必要抓住别人一顿痛批吧,『本是同根生,相煎何太急』。 虽然Solaris、Linux的很多版本及Windows对起源于Berkeley的socket API进行了重写,但不可否认,由于历史原因和POSIX标准的存在,对于使用者而言,我们可以无视这些API的实现差异。只是一旦我们从socket通信扩展到其他IPC通信的话,就需要正视各种I/O细节的差异了。 由于UNIX中,对于socket, file, pipe, device的大多数操作,描述符都是通用的(这一点,OS上面讲的更清楚些)。而Windows中,句柄大多不能互换(socket对于MS来说是舶来品)。系统和标准的不一致导致地址、协议和API的混杂甚至混乱。 UNIX下的描述符和Windows的句柄可以看作是同一个概念,只是应用环境不一样,所描述的内容也时常不一样,再简单了说,它们都是一个整型的ID。 ACE的源码中使用了大量预处理指令,尤其在跨平台/编译环境的部分更加明显。鉴于C/C++标准的博大胸怀,有些指令需要阅读相关编译器提供的帮助文档: o #define (#, #@, ##) : GCC, MSVC 其中有若干代码文件以.inl为后缀,里面是对部分函数的内联实现,以使代码结构看上去更加简洁。如果确定使用内联函数的话,*.inl将被包含于*.h的最后,如果不使用,则像*.h一样,包含于*.cpp的头部。 ACE采用doxygen输出文档,在阅读代码注释时能够感受到差异,但基本不会影响阅读。 o * __ 关于第3章(C++NPv1)__ * o ACE抽象的地址类ACE_Addr拥有ACE_DEV_Addr, ACE_FILE_Addr, ACE_INET_Addr, ACE_SPIPE_Addr, ACE_UNIX_Addr五个子类。对于狭义上的网络通信(TCP/IP)而言,ACE_INET_Addr对应于我们熟悉的sockaddr_in。 ACE_IPC_SAP是IPC(interprocess communication)I/O操作类的root类。 从编码的角度看,这个类漂亮的地方在于示例了抽象类的另一种实现方式。 一提到抽象类,大多数人的第一反应是pure virtual function。当一个基类确定需要使用virtual function时,这是一个不错的选择。但我们都知道虚拟函数有开销。而且对于一个结构简单的抽象基类和其继承子类(尤其是大量使用时),一个虚函数表带来的开销会让整个设计显得十分蹩脚。 我们都知道如何强制让一个类无法使用default constructor(protected)。如果对基类使用该方法,仅使子类具有public的default constructor,这就达到了定义抽象基类的效果。 virtual destructor的意义在于防止delete父类指针(指向子类对象)时未调用子类destructor。在此例中,为避免这种情况,同样将destructor声明为protected即可。 从设计实现的角度看,相较于socket API,ACE_IPC_SAP的子类ACE_SOCK提供了编译时对句柄合法性的检测。 从逻辑功能层面划分,socket有三种角色: o active connection role (connector):主动连接 o passive connection role (acceptor):被动连接 o communication role (stream):数据通信 但socket API毕竟不是OOD出来的,对于一个socket描述符,也完全没有必要去限制其担负的功能,更不可能搞成三种不同的socket。而OOD的ACE则可以轻易实现对socket对象及其操作的封装。 工厂类ACE_SOCK_Connector是一个主动创建通信端的工厂类。socket API中的connect接口只是为一个socket建立与其它peer的网络连接,而不产生新的socket实例,也不依赖于任何其它socket。同样,ACE_SOCK_Connector只是为一个ACE_SOCK_Stream对象(对用于数据通信的socket的封装)连接到ACE_Addr(对struct sockaddr的封装)提供接口,也不含对ACE_SOCK_Stream对象的其它操作。 工厂类ACE_SOCK_Acceptor是一个被动创建通信端的工厂类。当监听到新的网络连接后,为该连接初始化一个ACE_SOCK_Stream对象。和connector不同的是,acceptor依赖于一个已经存在的充当监听功能的socket句柄(ACE_SOCK),因此,ACE_SOCK_Acceptor是ACE_SOCK的一个子类。 ACE_SOCK_Stream是只负有通信传输功能的socket,对应connection-oriented的TCP通信格式stream,和UDP的CE_SOCK_CODgram相呼应。ACE_SOCK_Stream只是socket的通信载体,在两个工厂ACE_SOCK_Connector和ACE_SOCK_Acceptor中初始化。这样一个类除支持最基本的数据发送(send)和接收(recv)和阻塞(blocking)、非阻塞(nonblocking)及定时(timed)的I/O模式外,还支持分散读取(scatter-read)和集中写入(gather-write)。 对于一个简单的『网络课程作业:写一个有连接的IM小程序』,上面这些内容已经足够了。当然即使使用对应的几个socket API也已经足够了。但我们显然更加关心如此庞大的一个库,是如何解决复杂的网络应用的,我尤其关心的是多线程并发如何更好的处理。 所以,我准备跑到第8、9章了。 请移步至此阅读全文» |
|
|