随笔-29  评论-8  文章-8  trackbacks-0
  2008年11月29日

class 读书:
  subclass 设计方面
  <<快速软件开发>>

  subclass 软件工程 & 项目管理
  <<微软360度---成功与成长>>

  subclass 系统方面
   linux内核方面的东西.
  <<windows核心编程>>:目前主要工作不在windows上,只能偶尔很少一点空闲来研究下windows的东东.

  subclass 语言方面:
  <<The Ruby Way>>: 对语言的本质介绍得比较全面和详细.
  <<python源码解析>>: 写得浅显易懂
  <<Erlang程序设计>>: 并行程序设计,有很多新鲜元素在里头.没有看完,暂时无过多评论.


class 理论学习:
  bloom filter的详细研究.
  paxos分布式一致性算法
  种群算法
  基于动态访问模式的分布式缓存算法
  <<数学之美>>

class IT史:
  <<浪潮之颠>>

 

class 开源学习:
  hadoop: 此代码经过一年多断断续续的阅读,基本烂熟.
  kfs: 一个类GFS的分布式文件系统,代码写得比较清晰,虽然质量不是非常高,技艺不是非常精湛.但作为一个prototype是很不错了. 
  zookeeper: 这个算法和思想是有一定坡度的.

 

class 行业动态:
  云计算: IaaS, PaaS.
  这块跟当前工作联系很大,所以有一定的关注度.

  移动平台: Android, iphone, mobin
  Note: 以前做移动开发有过一段经历:并且本人对新鲜事物和酷眩体验式也有偏好.其间玩了玩android,摆弄了些小例子,当作消遣.

class 工作方面:
  主要是做分布式计算方面的东西,主要有这几部分:
  MapReduce基础框架.
  海量数据统计分析.


class 后期:
  虚拟化技术方面, 集群资源虚拟化,动态负载均衡调度等.

posted @ 2008-11-29 16:23 彭帅 阅读(596) | 评论 (2)编辑
  2008年11月19日
     摘要: 软件集成开发环境(代码编辑、浏览、编译、调试)Emacs http://www.gnu.org/software/emacs/Source-Navigator 5.2b2 http://sourceforge.net/projects/sourcenavAnjuta http://anjuta.sourceforge.net(可用yum安装)代码索引工具Cscope http://cscope.s... 阅读全文
posted @ 2008-11-19 11:44 彭帅 阅读(243) | 评论 (0)编辑
  2008年11月2日
编译: edisonpeng@tencent.com



zookeeper的基本功能:
名称服务(naming)
配置管理(configuration management)
同步(synchronization)
group services(组服务)

在此基础上,你可以构建:
一致性(consensus)
组管理(group management)
leader选举(leader election)
(presence protocols)



zookeeper概述
针对分布式应用的分布式协作服务.
zookeeper的开发动机就是为了减轻分布式应用从头开发协作服务的负担.

设计目标
简单. 允许多个分布的进程基于一个共享的,类似标准文件系统的树状名称空间进行协作.每个节点称作一个znode.

ZooKeeper is replicated
几个zookeeper集群包含多个zookeeper server, 称作一个ensemble. 这些server彼此都知道对方的存在.
需要维护的数据: 内存中的状态的镜像, 持久化存储中的事务日志和快照.
client和单个zookeeper server通信.client维护一个持久TCP连接,通过其发送请求, 获取响应和watch events,并发送心跳信息.
如果到server的TCP连接中断, client将会连接到另外一个server.

ZooKeeper is ordered
zookeeper对每次更新进行一个计数器stamp以反映所有zookeeper事务的次序.后续的操作能够使用此次序来实现高级抽象,如同步原语.

ZooKeeper is fast
zookeeper在read操作上是非常快的.通常的应用中,读写操作比也在10:1左右.



数据模型和层级名称空间


节点和临时节点
有别于标准文件系统的是,zookeeper名称空间中的每个节点都可以关联数据到它本身或者它的子节点.就好比标准文件系统中的文件同时又可以
充当目录.(zookeeper用于存储协作数据: 状态信息, 配置, 位置信息等, 所以存放在每个node的数据通常都比较小,一般在K级别).我们以znode
来描述zookeeper中的数据节点.

znodes维护一个stat结构,其中包括数据变更, 权限变更的版本信息,还有时间戳,以便于缓存有效性验证和协作更新.每当znode的数据变更时,
版本号都会递增.例如, 每次client在获取数据时,它同时也获得了数据的版本信息.

存储在znode中的数据对read, write都是原子性操作的.read会获取znode中的所有字节, write会整个替换znode中的信息.每个znode都包含一个
访问控制列表(ACL)以约束谁可以访问此节点.

zookeeper还有一个临时节点的概念.临时节点在创建它的session的生命周期内存活, 当其session终止时,此类节点将会被删除.
临时节点在我们需要实现[tbd]时非常有用.

条件更新和监听器(watches)
zookeeper提供监听器的概念. client可以在某个znode上设置watch. 当znode有变更时, 相关的watch会被触发或删除.一旦watch触发, client
将会收到一个数据包以通知znode的变更.如果在client和zookeeper server之间的连接被中断了, client将会收到一个本地的通知.
这些都能被用于[tbd].

Guarantees
zookeeper在使用上非常简单高效.因为它的设计目标,是作为构建复杂服务类型,如同步, zookeeper提供的保证包括:
序列一致性: 数据更新会依照client发送的次序来进行.
原子性: 更新要么成功,要么失败.不存在部分结果.
唯一系统镜像: client总是会看到一致的视图,而不管它是连接到具体哪个zookeeper server.
可靠性: 一旦更新完成, 它会持续保存直到有另外的client重写.
及时: 客户端视图会在一定的时间间隔内进行更新.

Simple API
zookeeper的一个重要设计目标就是要提供简单的编程接口.所以,它仅仅提供如下操作:
create:在树种某个位置创建一个节点.
delete:删除一个节点.
exists:检查给定节点是否存在.
get data: 从一个节点读取数据.
set data: 写数据到给定节点.
get children: 获取节点的子节点列表
sync: 等待知道数据被传输.

实现

如下展示了zookeeper服务的高层组件.
除了request processor, 组成zookeeper服务的每个server都会在本地备份其它组件的拷贝.
replicated database是一个包含整个数据树的内存数据库.更新被logged到磁盘以提供可恢复性,写操作先持久化到磁盘,然后再对内存数据库作变更.
每个zookeeper server都对client提供服务.client连接到具体的某一个server以提交请求.读操作依赖与每个server的本地数据库.改变服务状态的请求,
写操作,由一致性协议来处理.
作为一致性协议的一部分,所有的client写请求被提交到专门的一个leader server. 其余的server,被称为followers,从leader接收消息,并对消息的传递达成一致.
消息层负责替换失效leader并同步followers.
zookeeper使用自定义的原子消息传递协议.因为消息传递层是原子性的,zookeeper能够确保本地备份不会出现分歧.When the leader receives a write request, it calculates what the state of the system is when the write is to be applied and transforms this into a transaction that captures this new state.
使用
zookeeper的编程接口特意做的非常简单.在此之上,你可以实现更高层次的操作, 如同步原语, 组管理, 所有权等等.
性能
zookeeper被设计用于高性能场景.参见ZooKeeper Throughput as the Read-Write Ratio Varies.
可靠性
下图的benchmarks同时也表明zookeeper是可靠的. Reliability in the Presence of Errors展示了一个zookeeper部署如何应对各种失效. 在图中标示的事件定义如下:
1. follower的失效和恢复.
2. 不同的follower失效和恢复.
3. leader的失效.
4. 两个follower同时失效和恢复.
5. 另一个leader失效.
这张图中有一些重要的观测值.首先,如果followers失效并快速恢复,zookeeper可以持续保持高吞吐而不受影响;最重要的是,leader推举算法允许系统快速恢复以防止
吞吐大幅度下降.在我们的观测中,zookeeper只花费不到200ms来推举一个新的leader;第三点,当follower恢复并开始处理请求时,zookeeper的吞吐也会回升.

zookeeper项目
zookeeper已经在很多工业级项目中被成功运用.在Yahoo!, 它被用于Yahoo! Message Broker以提供协作和失效恢复服务, Yahoo! Message Broker是一个高效的发布/订阅系统,
其管理着用于备份和数据迁移的主题. zookeeper还被用于Yahoo!爬虫的抓取服务,在此它同样提供了失效恢复机制.许多Yahoo!的广告系统也使用zookeeper来提供可靠服务.
posted @ 2008-11-02 22:47 彭帅 阅读(102) | 评论 (0)编辑
  2007年12月14日

http://mindprod.com/jgloss/classloader.html
类似个java辞典,有一定深度

通过CL你可以同时装载一个类的不同版本,通过用不同的CL来实现。
自定义CL可以热部署类
默认的CL不会被卸载,其装载的类也不会被GC掉。
不同CL装载的相同的类文件中的类用instanceof来比较是不同的。



http://www.blogjava.net/killme2008/archive/2007/06/26/126282.html

http://topic.csdn.net/t/20020716/23/879661.html

http://forum.springframework.org/showthread.php?t=21383

http://forum.java.sun.com/thread.jspa?threadID=661841&messageID=3880883

http://www.jroller.com/agileanswers/entry/preventing_java_s_java_lang

posted @ 2007-12-14 01:07 彭帅 阅读(49) | 评论 (0)编辑
  2007年10月1日
apr
APR(Apache portable Run-time libraries,Apache可移植运行库)的目的如其名称一样,主要为上层的应用程序提供一个可以跨越多操作系统平台使用的底层支持接口库。
在早期的Apache版本中,应用程序本身必须能够处理各种具体操作系统平台的细节,并针对不同的平台调用不同的处理函数。随着Apache的进一步开发,Apache组织决定将这些通用的函数独立出来并发展成为一个新的项目。这样,APR的开发就从Apache中独立出来,Apache仅仅是使用APR而已。
目前APR主要还是由Apache使用,不过由于APR的较好的移植性,因此一些需要进行移植的C程序也开始使用APR,开源项目比如Flood loader tester(http://httpd.apache.org/test/flood/,该项目用于服务器压力测试,不仅仅适用于Apache)、FreeSwitch(www.freeswitch.org),JXTA-C(http://jxta-c.jxta.org,C版本的JXTA点对点平台实现);商业的项目则包括Blogline(http://www.bloglines.com/,covalent(http://www.covalent.net)等等。 APR使得平台细节的处理进行下移。对于应用程序而言,它们根本就不需要考虑具体的平台,不管是Unix、Linux还是Window,应用程序执行的接口基本都是统一一致的。因此对于APR而言,可移植性和统一的上层接口是其考虑的一个重点。而APR最早的目的并不是如此,它最早只是希望将Apache中用到的所有代码合并为一个通用的代码库,然而这不是一个正确的策略,因此后来APR改变了其目标。有的时候使用公共代码并不是一件好事,比如如何将一个请求映射到线程或者进程是平台相关的,因此仅仅一个公共的代码库并不能完成这种区分。
APR的目标则是希望安全合并所有的能够合并的代码而不需要牺牲性能。 APR的最早的一个目标就是为所有的平台(不是部分)提供一个公共的统一操作函数接口,这是一个非常了不起的目的,当然也是不现实的一个目标。我们不可能支持所有平台的所有特征,因此APR目前只能为大多数平台提供所有的APR特性支持,包括Win32、OS/2、BeOS、Darwin、Linux等等。为了能够实现这个目标,APR开发者必须为那些不能运行于所有平台的特性创建了一系列的特征宏(FEATURE MACROS)以在各个平台之间区分这些特征。这些特征宏定义非常简单,通常如下: APR_HAS_FEATURE 如果某个平台具有这个特性,则该宏必须设置为true,比如Linux和window都具有内存映射文件,同时APR提供了内存映射文件的操作接口,因此在这两个平台上,APR_HAS_MMAP宏必须设置,同时ap_mmap_*函数应该将磁盘文件映射为内存并返回适当的状态码。如果你的操作系统并不支持内存映射,那么APR_HAS_MMAP必须设置为0,而且所有的ap_mmap_*函数也可以不需要定义。第二步就是对于那些在程序中使用了不支持的函数必须提出警告。
APR中支持的基本类型
文件夹名称                            描述
atomic/srclib/apr/atomic           原子操作
dso/srclib/apr/dso                 动态加载共享库
fileio/srclib/apr/file_io          文件IO处理
mmap/srclib/apr/mmap               内存映射文件
locks/srclib/apr/locks             进程和线程互斥锁
memory/srclib/apr/memory           内存池操作
network_io/srclib/apr/network_io   网络IO处理
poll/srclib/apr/poll               轮询IO
table/srclib/apr/tables            Apache数组(堆栈)和表格以及哈希表
process /srclib/apr/threadproc     进程和线程操作
user /srclib/apr/user              用户和用户组操作
time /srclib/apr/time              时间操作
string/srclib/apr/strings          字符串操作
password /srclib/apr/passwd        终端密码处理
misc /srclib/apr/misc              大杂烩,不属于其余类的任何apr类型都可以放在里面
shmem /srclib/apr/shmem            共享内存
random /srclib/apr/random          随机数生成库
posted @ 2007-10-01 13:38 彭帅 阅读(44) | 评论 (0)编辑
  2007年9月29日

tcp_syn_retriesINTEGER
默认值是5

对于一个新建连接,内核要发送多少个 SYN 连接请求才决定放弃。不应该大于255,默认值是5,对应于180秒左右时间。(对于大负载而物理通信良好的网络而言,这个值偏高,可修改为2.这个值仅仅是针对对外的连接,对进来的连接,是由tcp_retries1 决定的)

tcp_synack_retriesINTEGER
默认值是5

对于远端的连接请求SYN,内核会发送SYN + ACK数据报,以确认收到上一个 SYN连接请求包。这是所谓的三次握手( threeway handshake)机制的第二个步骤。这里决定内核在放弃连接之前所送出的 SYN+ACK 数目。不应该大于255,默认值是5,对应于180秒左右时间。(可以根据上面的tcp_syn_retries来决定这个值)

tcp_keepalive_timeINTEGER
默认值是7200(2小时)
当keepalive打开的情况下,TCP发送keepalive消息的频率。(由于目前网络攻击等因素,造成了利用这个进行的攻击很频繁,曾经也有cu的朋友提到过,说如果2边建立了连接,然后不发送任何数据或者rst/fin消息,那么持续的时间是不是就是2小时,空连接攻击?tcp_keepalive_time就是预防此情形的.我个人在做nat服务的时候的修改值为1800秒)

tcp_keepalive_probes:INTEGER
默认值是9

TCP发送keepalive探测以确定该连接已经断开的次数。(注意:保持连接仅在SO_KEEPALIVE套接字选项被打开是才发送.次数默认不需要修改,当然根据情形也可以适当地缩短此值.设置为5比较合适)

tcp_keepalive_intvlINTEGER
默认值为75
探测消息发送的频率,乘以tcp_keepalive_probes就得到对于从开始探测以来没有响应的连接杀除的时间。默认值为75秒,也就是没有活动的连接将在大约11分钟以后将被丢弃。(对于普通应用来说,这个值有一些偏大,可以根据需要改小.特别是web类服务器需要改小该值,15是个比较合适的值)

tcp_retries1INTEGER
默认值是3
放弃回应一个TCP连接请求前﹐需要进行多少次重试。RFC 规定最低的数值是3﹐这也是默认值﹐根据RTO的值大约在3秒 - 8分钟之间。(注意:这个值同时还决定进入的syn连接)

tcp_retries2INTEGER
默认值为15
在丢弃激活(已建立通讯状况)的TCP连接之前﹐需要进行多少次重试。默认值为15,根据RTO的值来决定,相当于13-30分钟(RFC1122规定,必须大于100秒).(这个值根据目前的网络设置,可以适当地改小,我的网络内修改为了5)

tcp_orphan_retriesINTEGER
默认值是7
在近端丢弃TCP连接之前﹐要进行多少次重试。默认值是7个﹐相当于 50秒 - 16分钟﹐视 RTO 而定。如果您的系统是负载很大的web服务器﹐那么也许需要降低该值﹐这类 sockets 可能会耗费大量的资源。另外参的考 tcp_max_orphans(事实上做NAT的时候,降低该值也是好处显著的,我本人的网络环境中降低该值为3)

tcp_fin_timeoutINTEGER
默认值是 60
对于本端断开的socket连接,TCP保持在FIN-WAIT-2状态的时间。对方可能会断开连接或一直不结束连接或不可预料的进程死亡。默认值为 60 秒。过去在2.2版本的内核中是 180 秒。您可以设置该值﹐但需要注意﹐如果您的机器为负载很重的web服务器﹐您可能要冒内存被大量无效数据报填满的风险﹐FIN-WAIT-2 sockets 的危险性低于 FIN-WAIT-1 ﹐因为它们最多只吃 1.5K 的内存﹐但是它们存在时间更长。另外参考 tcp_max_orphans(事实上做NAT的时候,降低该值也是好处显著的,我本人的网络环境中降低该值为30)

tcp_max_tw_bucketsINTEGER
默认值是180000
系统在同时所处理的最大 timewait sockets 数目。如果超过此数的话﹐time-wait socket 会被立即砍除并且显示警告信息。之所以要设定这个限制﹐纯粹为了抵御那些简单的 DoS 攻击﹐千万不要人为的降低这个限制﹐不过﹐如果网络条件需要比默认值更多﹐则可以提高它(或许还要增加内存)。(事实上做NAT的时候最好可以适当地增加该值)

tcp_tw_recycleBOOLEAN
默认值是0
打开快速 TIME-WAIT sockets 回收。除非得到技术专家的建议或要求﹐请不要随意修改这个值。(做NAT的时候,建议打开它)


tcp_tw_reuseBOOLEAN
默认值是0
该文件表示是否允许重新应用处于TIME-WAIT状态的socket用于新的TCP连接(这个对快速重启动某些服务,而启动后提示端口已经被使用的情形非常有帮助)

tcp_max_orphansINTEGER
缺省值是8192
系统所能处理不属于任何进程的TCP sockets最大数量。假如超过这个数量﹐那么不属于任何进程的连接会被立即reset,并同时显示警告信息。之所以要设定这个限制﹐纯粹为了抵御那些简单的 DoS 攻击﹐千万不要依赖这个或是人为的降低这个限制(这个值Redhat AS版本中设置为32768,但是很多防火墙修改的时候,建议该值修改为2000)

tcp_abort_on_overflowBOOLEAN
缺省值是0
当守护进程太忙而不能接受新的连接,就象对方发送reset消息,默认值是false。这意味着当溢出的原因是因为一个偶然的猝发,那么连接将恢复状态。只有在你确信守护进程真的不能完成连接请求时才打开该选项,该选项会影响客户的使用。(对待已经满载的sendmail,apache这类服务的时候,这个可以很快让客户端终止连接,可以给予服务程序处理已有连接的缓冲机会,所以很多防火墙上推荐打开它)

tcp_syncookiesBOOLEAN
默认值是0
只有在内核编译时选择了CONFIG_SYNCOOKIES时才会发生作用。当出现syn等候队列出现溢出时象对方发送syncookies。目的是为了防止syn flood攻击。
注意:该选项千万不能用于那些没有收到攻击的高负载服务器,如果在日志中出现synflood消息,但是调查发现没有收到synflood攻击,而是合法用户的连接负载过高的原因,你应该调整其它参数来提高服务器性能。参考:
tcp_max_syn_backlog
tcp_synack_retries
tcp_abort_on_overflow
syncookie严重的违背TCP协议,不允许使用TCP扩展,可能对某些服务导致严重的性能影响(如SMTP转发)。(注意,该实现与BSD上面使用的tcp proxy一样,是违反了RFC中关于tcp连接的三次握手实现的,但是对于防御syn-flood的确很有用.)

tcp_stdurgBOOLEAN
默认值为0
使用 TCP urg pointer 字段中的主机请求解释功能。大部份的主机都使用老旧的 BSD解释,因此如果您在 Linux 打开它﹐或会导致不能和它们正确沟通。


tcp_max_syn_backlogINTEGER
对于那些依然还未获得客户端确认的连接请求﹐需要保存在队列中最大数目。对于超过 128Mb 内存的系统﹐默认值是 1024 ﹐低于 128Mb 的则为 128。如果服务器经常出现过载﹐可以尝试增加这个数字。警告﹗假如您将此值设为大于 1024﹐最好修改 include/net/tcp.h 里面的 TCP_SYNQ_HSIZE ﹐以保持 TCP_SYNQ_HSIZE*16<=tcp_max_syn_backlog ﹐并且编进核心之内。(SYN Flood攻击利用TCP协议散布握手的缺陷,伪造虚假源IP地址发送大量TCP-SYN半打开连接到目标系统,最终导致目标系统Socket队列资源耗尽而无法接受新的连接。为了应付这种攻击,现代Unix系统中普遍采用多连接队列处理的方式来缓冲(而不是解决)这种攻击,是用一个基本队列处理正常的完全连接应用(Connect()和Accept() ),是用另一个队列单独存放半打开连接。这种双队列处理方式和其他一些系统内核措施(例如Syn-Cookies/Caches)联合应用时,能够比较有效的缓解小规模的SYN Flood攻击(事实证明<1000p/s)加大SYN队列长度可以容纳更多等待连接的网络连接数,所以对Server来说可以考虑增大该值.)

tcp_window_scalingINTEGER
缺省值为1

该文件表示设置tcp/ip会话的滑动窗口大小是否可变。参数值为布尔值,为1时表示可变,为0时表示不可变。tcp/ip通常使用的窗口最大可达到 65535 字节,对于高速网络,该值可能太小,这时候如果启用了该功能,可以使tcp/ip滑动窗口大小增大数个数量级,从而提高数据传输的能力(RFC 1323)。(对普通地百M网络而言,关闭会降低开销,所以如果不是高速网络,可以考虑设置为0

tcp_timestampsBOOLEAN
缺省值为1
Timestamps 用在其它一些东西中﹐可以防范那些伪造的 sequence 号码。一条1G的宽带线路或许会重遇到带 out-of-line数值的旧sequence 号码(假如它是由于上次产生的)。Timestamp 会让它知道这是个 '旧封包'。(该文件表示是否启用以一种比超时重发更精确的方法(RFC 1323)来启用对 RTT 的计算;为了实现更好的性能应该启用这个选项。)

tcp_sackBOOLEAN
缺省值为1

使用 Selective ACK﹐它可以用来查找特定的遗失的数据报--- 因此有助于快速恢复状态。该文件表示是否启用有选择的应答(Selective Acknowledgment),这可以通过有选择地应答乱序接收到的报文来提高性能(这样可以让发送者只发送丢失的报文段)。(对于广域网通信来说这个选项应该启用,但是这会增加对 CPU 的占用。)

tcp_fackBOOLEAN
缺省值为1
打开FACK拥塞避免和快速重传功能。(注意,当tcp_sack设置为0的时候,这个值即使设置为1也无效)

tcp_dsackBOOLEAN
缺省值为1
允许TCP发送"两个完全相同"的SACK。

tcp_ecnBOOLEAN
缺省值为0
打开TCP的直接拥塞通告功能。

tcp_reorderingINTEGER
默认值是3
TCP流中重排序的数据报最大数量 。 (一般有看到推荐把这个数值略微调整大一些,比如5)

tcp_retrans_collapseBOOLEAN
缺省值为1
对于某些有bug的打印机提供针对其bug的兼容性。(一般不需要这个支持,可以关闭它)

tcp_wmem(3个INTEGER变量): min, default, max
min
:为TCP socket预留用于发送缓冲的内存最小值。每个tcp socket都可以在建议以后都可以使用它。默认值为4096(4K)

default:为TCP socket预留用于发送缓冲的内存数量,默认情况下该值会影响其它协议使用的net.core.wmem_default 值,一般要低于net.core.wmem_default的值。默认值为16384(16K)

max: 用于TCP socket发送缓冲的内存最大值。该值不会影响net.core.wmem_max,"静态"选择参数SO_SNDBUF则不受该值影响。默认值为131072(128K)(对于服务器而言,增加这个参数的值对于发送数据很有帮助,在我的网络环境中,修改为了51200 131072 204800)

tcp_rmem (3个INTEGER变量): min, default, max
min:为TCP socket预留用于接收缓冲的内存数量,即使在内存出现紧张情况下tcp socket都至少会有这么多数量的内存用于接收缓冲,默认值为8K

default:为TCP socket预留用于接收缓冲的内存数量,默认情况下该值影响其它协议使用的 net.core.wmem_default 值。该值决定了在tcp_adv_win_scaletcp_app_wintcp_app_win=0默认值情况下,TCP窗口大小为65535。默认值为87380

max:用于TCP socket接收缓冲的内存最大值。该值不会影响 net.core.wmem_max,"静态"选择参数 SO_SNDBUF则不受该值影响。默认值为 128K。默认值为87380*2 bytes。(可以看出,.max的设置最好是default的两倍,对于NAT来说主要该增加它,我的网络里为 51200 131072 204800)

tcp_mem(3个INTEGER变量):low, pressure, high
low:当TCP使用了低于该值的内存页面数时,TCP不会考虑释放内存。(理想情况下,这个值应与指定给 tcp_wmem 的第 2 个值相匹配 - 这第 2 个值表明,最大页面大小乘以最大并发请求数除以页大小 (131072 * 300 / 4096)。 )

pressure:当TCP使用了超过该值的内存页面数量时,TCP试图稳定其内存使用,进入pressure模式,当内存消耗低于low值时则退出pressure状态。(理想情况下这个值应该是 TCP 可以使用的总缓冲区大小的最大值 (204800 * 300 / 4096)。 )

high:允许所有tcp sockets用于排队缓冲数据报的页面量。(如果超过这个值,TCP 连接将被拒绝,这就是为什么不要令其过于保守 (512000 * 300 / 4096) 的原因了。 在这种情况下,提供的价值很大,它能处理很多连接,是所预期的 2.5 倍;或者使现有连接能够传输 2.5 倍的数据。 我的网络里为192000 300000 732000)

一般情况下这些值是在系统启动时根据系统内存数量计算得到的。

tcp_app_win : INTEGER
默认值是31

保留max(window/2^tcp_app_win, mss)数量的窗口由于应用缓冲。当为0时表示不需要缓冲。

tcp_adv_win_scale : INTEGER
默认值为2

计算缓冲开销bytes/2^tcp_adv_win_scale(如果tcp_adv_win_scale > 0)或者bytes-bytes/2^(-tcp_adv_win_scale)(如果tcp_adv_win_scale <= 0)。


tcp_rfc1337 :BOOLEAN
缺省值为0
这个开关可以启动对于在RFC1337中描述的"tcp 的time-wait暗杀危机"问题的修复。启用后,内核将丢弃那些发往time-wait状态TCP套接字的RST 包.


tcp_low_latency : BOOLEAN
缺省值为0

允许 TCP/IP 栈适应在高吞吐量情况下低延时的情况;这个选项一般情形是的禁用。(但在构建Beowulf 集群的时候,打开它很有帮助)


tcp_westwood :BOOLEAN
缺省值为0
启用发送者端的拥塞控制算法,它可以维护对吞吐量的评估,并试图对带宽的整体利用情况进行优化;对于 WAN 通信来说应该启用这个选项。


tcp_bic :BOOLEAN
缺省值为0
为快速长距离网络启用 Binary Increase Congestion;这样可以更好地利用以 GB 速度进行操作的链接;对于 WAN 通信应该启用这个选项。

posted @ 2007-09-29 22:45 彭帅 阅读(318) | 评论 (0)编辑

1. 给页面的body上指定class或id,这样可以在一个共享css中为特定页面指定特别样式。

评论:这适用于样式较少的情况,可以把整个站点的样式集中于一个样式表。例如只有一两个页面有一两条特殊规则,就不需要使用多一个单独样式表。当然,样式多的时候,还是应分成若干个样式表,根据情况在页面中import所需样式表。


2. CSS签名,如body id="www-sitename-com",这样允许用户在用户样式表中为你的站点增加(或覆盖)样式。

评论:这个技巧很有意思,不过用户样式表很少被利用。为特定站点写特定样式,用user script之类的方法会更灵活。所以虽然初看时眼前一亮,但总的考虑下来,实用性不是很大。但是这给我一个启发,其实用用户样式表,加上IE7之类的库,就可以定制浏览器。


记录IE的bug:相对定位元素内若向右下进行绝对定位,需要设定相对定位元素的高宽。

模拟fixed的一个办法是使用脚本改变元素的绝对定位坐标,但是通常会导致抖动。实际上有两个小技巧可以模拟出不抖动的fixed。一个是使用css expression配合background-attachment:fixed。另一个(偶自行发现的)方法是使用ie的standard mode,然后html元素overflow:hidden,而body元素overflow:auto,这样body上绝对定位的元素在外层没有定位元素的情况下,会始终相对于html元素定位,从而达到和fixed定位一样的效果。这一方法是我在试图解决standard mode下scrollbar抢夺焦点的Bug(IE7似乎仍有这个bug)时偶然发现的。

关于containing block如何包围float元素(似乎有很多人以为这是FF的bug),需要额外的空元素来clear。为了避免引入无意义的标签,使用::after是个好方法,类似的,也许也可以用:last-child伪类,不过这两种方法无法用在IE上。但是IE可以用Holly hack,实际上就是让containing block获得hasLayout。

1. 固定宽度圆角框

实现:在外层元素(容器)上设定背景色和底部圆角图,在标题(内部第一个元素)上设定顶部圆角图。

限制:
* 宽度是定值像素的。
* 必须有内外两层block元素,内外层要紧贴(即外层不能有padding,内层不能有margin和border)。
* 圆角背景色是固定的(如白色),不能是透明的。

2. 固定宽度圆角框的变形

实现:在外层元素(容器)上设定纵向重复(repeat-y)的背景图,在内部第一个元素上设定顶部圆角图,在内部最后一个元素上设定底部圆角图。

限制:
* 宽度是定值像素的。
* 必须有内外两层block元素,内层至少有两个元素,内外层要紧贴(即外层不能有padding,内层不能有margin和border)。
* 圆角背景色是固定的(如白色),不能是透明的。

注:固定背景色的限制可以通过增加位移来解决,例如:

代码
  1. <div class="box">  
  2.     <div class="top">Heading</div>  
  3.     <div>Content...</div>  
  4.     <div class="bottom">Content...</div>  
  5. </div>  


代码
  1. .box {   
  2.     background:url(border-middle.png) repeat-y; width:120px;   
  3.     margin:12px 0;   
  4. }   
  5. .box .top {   
  6.     background:url(border-top.png) top no-repeat;   
  7.     margin:0;   
  8.     position:relative; top:-12px; padding-top:12px; margin-bottom:-12px;   
  9. }   
  10. .box .bottom {   
  11.     background:url(border-bottom.png) bottom no-repeat;   
  12.     margin:0;   
  13.     position:relative; top:12px; padding-bottom:12px; margin-top:-12px;   
  14. }   

注意,由于使用了margin,需要注意垂直合并的情况,增加了样式的复杂度。


3. sliding doors 技巧
实现:添加若干层额外的container,在每层上分别应用左下、右下、左上、右上的圆角图。
限制:
* 必须有四层block元素,内外层要紧贴(即外层不能有padding,内层不能有margin和border)。
* 圆角背景色是固定的(如白色),不能是透明的。

本质上,sliding doors技巧和前两个方式是一致的,都是通过多层block元素上的背景重叠来模拟总体效果。区别就是前面只需要两层——多数情况下,语义结构可以有两层元素,而几乎不可能出现语义结构需要四层元素的情况。

本书作者对此的看法是,如果只要少数地方,那忍受一下无意义标签也可以,但是如果有很多地方,那就需要考虑其方案。

我对此的看法有些不同。实际上,书中示例在容器宽度高度增大到超出图片宽高时,就会出现空白。如果要适应任意大小的容器,要么增大图片尺寸到一个很大的数值,要么增加更多层次,使用多达九层元素(相当于切分成井字形的九份)!

因此同样是忍受无语义元素,我宁可使用table构造一个井字布局来模拟border,这个方式比多层嵌套无语义div更清晰。

当然,最好的方案是使用CSS3的border-image和border-radius。在没有CSS3支持前,则是使用脚本自动插入辅助元素来实现。书中给出的是http://www.456bereastreet.com/archive/200505/transparent_custom_corners_and_borders/


1. 简单的CSS阴影和Clagnut阴影

实现:在外层wrapper上将阴影图设为背景。元素本身通过margin或者相对定位做向左上方的偏移(以展现右下方向的阴影)。

限制:
* 阴影元素需要一个外层的wrapper元素。

2. 模糊阴影

实现:添加两层container,分别应用阴影图像和蒙板图像。

限制:
* 需要两个外层元素
* 外层背景色是固定的(与蒙板颜色一致)。洋葱皮阴影无此问题。

注意,蒙板需要png的alpha透明特性,但是IE6不支持。书中给出了使用AlphaImageLoader的filter方式,但是问题在于,在IE中与其这样,不如直接在元素上使用DropShadow或Shadow的filter。

3. 洋葱皮阴影

实现:添加两层container,分别应用两个阴影末尾图。

限制:
* 需要两个外层元素
* 外层背景色是固定的,但稍作改进可以避免这一限制。

总的来说,上述的阴影实现,都不是很好的方法,最好还是借助脚本。

最后是图像替换。

关于图像替换,除了本书作者所说的screen reader问题外,另一个问题是,在许多浏览器上,图像不会跟文本一起缩放。所以我的观点是尽量避免使用图像替换。本书作者提出的“公司品牌策略要求特定字体”的例子,我认为不足为证。如果真的需要这样强的视觉强制要求,也肯定不以字体为限,最好直接使用flash。

此外,display:none或visibility:hidden(译本有疏漏)会造成screen reader失效,这其实很大一部分是screen reader本身的问题。因为本身CSS可以只针对media=screen指定图像替换样式。但是许多screen reader忽视了CSS规范(多数是基于IE的)。

所以目前最可靠的图像替换法,仍是利用脚本的,如本书中的IFR和sIFR。

另,在XHTML2中,不需要专门的图像替换法。因为所有元素上都支持src属性。如果src指向的资源可用,就会被替换成该资源的内容(如视频、图像等),否则会使用元素内部的内容。

关于A上伪类的顺序,应按照LoVeHAte(Link Visited Hover Active)。

此外,关于链接伪类补充如下:

根据CSS21,link和visited伪类是互斥的,也就是*:link:visited不可能选择到任何元素。而hover、active与新增的focus伪类,可以共存于一个元素上。因此可以有以下的样式:

a:link:hover { color:red; text-decoration:underline }
a:visited:hover { color:maroon }
a:link { color:blue; text-decoration:none; }
a:visited { color:navy; text-decoration:none; }
a:active { background:green; color:white; }
a:visited:hover:active { text-decoration:line-through }

另,hover、active等动态伪类不限于A,也可以在其他某些元素上。但是IE6不支持。

active伪类还有点问题,因为早期规范定义不清,各个浏览器实现稍有不同。其中IE最离谱,实际效果近似一个只在a上有效的:focus伪类。实际上,IE DOM中的名为onactivate/ondeactivate的事件,也说明了IE是把active看成是一种特殊的focus的。

关于给外部链接加上图标,以及区分下载类型,是属性选择器的极好应用,只是IE6不支持。

Pixy方法,即将若干图合并于一个图片的方法,减少了http请求的数量,也避免了hover切换时的延迟。许多其他trick可以使用pixy方法,例如上一篇里提到的sliding door等。

本书还指出了Pixy方法受到IE的cache bug影响会闪烁。但是书中并没有说清楚这个问题。但其实该bug是有条件的,即IE的cache设置为Every visit to the page,而不是默认的Automatically。基本上,只有开发者才会把cache设置为每次访问检查更新,所以这个bug其实不会影响真正的用户(根据我在winxpsp2的ie6下测试,虽然可能仍然调用了一次网络存取的api,但是并没有发生实际的请求,症状就是鼠标有极短时间的抖动,但是图像不会闪烁)。此外有人发现了一个未公开的方法来让IE对背景图进行缓存:
document.execCommand("BackgroundImageCache",false,true)
使用这种方法甚至避免了api调用,貌似是直接缓存在IE内存中。
详见:http://www.mister-pixel.com/
BTW,我计划还要对这种方法做一些测试,看看是否能解决vml缓存问题

最后关于visited:在已访问链接后加一个打勾的图标,是一个很有意思的设计,可资参考。


关于列表,首先,由于list-style-image的位置各个浏览器实现的不一致,而且缩进使用padding或margin的不一致,所以本书后面的例子几乎完全抛弃了list-style,将padding和margin一律重置为0,然后从头重新定义。

BTW,关于列表缩进应该使用padding或者margin?我倾向于padding。理由另文撰述

关于导航条,本书的例子有一个问题,就是需要对第一个li元素专设样式。对于支持CSS21的浏览器来说,使用一个first-child伪类即可,但是对于IE,需要额外的一个first类。有一些解决的方法,我之前也讨论过这个话题

配合页面ID,可以设定页面特定的样式,例如本书中给出的在导航条中突出显示当前页面的例子。这是一个很有意思的技巧,沿着这个思路也可以有很多变化。

关于滑动门tab式导航,见上一篇关于sliding door的总结。幸运的是,在列表导航中,正好有li和a两层元素可供应用sliding door技巧。此外可以做一个简单的位移变形来支持边缘透明的tab。

关于图像映射,开始一段的译文有些歧义。我想作者是在说map和area,然后给出的是用CSS取代map的方法。我并不完全赞同作者关于map是将表现方式与内容混在一起的说法。在5.7远距离翻转的示例代码中,带有hotspot class的空span扮演的角色和area元素有何不同呢?实际上,map元素是有导航的语义的。xhtml2中新增的nl元素,就可以认为是map和ul的合体,在xhtml2中usemap所指向的也从map元素变成了nl元素。实际上,img等元素上的usemap属性提供了一种将对象(图像)与导航连接在一起的语义。

一个map的例子:

代码
  1. <img id="fu-image" src="fu.gif" alt="Bei Jing Huan Ying Ni" usemap="#fu-map" />  
  2. <map name="fu-map">  
  3.     <area href="#beibei" alt="BeiBei" shape="circle" coords="25,43,20" />  
  4.     <area href="#jingjing" alt="JingJing" shape="circle" coords="62,46,18" />  
  5.     <area href="#huanhuan" alt="HuanHuan" shape="circle" coords="102,36,24" />  
  6.     <area href="#yingying" alt="YingYing" shape="circle" coords="142,45,18" />  
  7.     <area href="#nini" alt="NiNi" shape="circle" coords="178,45,18" />  
  8. </map>  

 

又一个更语义化的例子(注:FF和Opera支持object上usemap,IE和Safari不支持object上usemap):

代码
  1. <object id="fu-nav" data="fu1.gif" type="image/gif" usemap="#fu-nav-map">  
  2.     <map name="fu-nav-map">  
  3.         <h2>Bei Jing Huan Ying Ni</h2>  
  4.         <ul>  
  5.             <li><a href="#beibei" tabindex="1" shape="circle" coords="25,43,20">BeiBei</a></li>  
  6.             <li><a href="#jingjing" tabindex="2" shape="circle" coords="62,46,18">JingJing</a></li>  
  7.             <li><a href="#huanhuan" tabindex="3" shape="circle" coords="102,36,24">HuanHuan</a></li>  
  8.             <li><a href="#yingying" tabindex="4" shape="circle" coords="142,45,18">YingYing</a></li>  
  9.             <li><a href="#nini" tabindex="5" shape="circle" coords="178,45,18">NiNi</a></li>  
  10.         </ul>  
  11.     </map>  
  12. </object>  

使用CSS做的图像映射,实际上与第二个例子相当接近,区别在于CSS无法作出圆形和多边形的点击区域。
当然作者的例子所展示的CSS设计的整个过程是很棒的。


posted @ 2007-09-29 04:49 彭帅 阅读(170) | 评论 (0)编辑
  2007年9月26日

之前tessian都是OK的,socketPool正常。今天albut在测试时突然发现调用效率缓慢。
我查了下,后来发现一个严重的问题,每次调用都重建socket,原因是协议包读取错误,我在协议分析中是这样判断的,如果协议错误,那么Server就强制关闭连接。

晚上我拿出前几天的版本运行,一切OK,没有重连出现!效率比http的hessian快上将近2倍多。对照两个版本查了好久,始终没有发现什么不对劲的地方。真是诡异。难道阿生改了client的socketpool?? 应该不会阿。



后续tessian在实时配置,动态装载,JMX管理,自动测试方面还有东西要做。

posted @ 2007-09-26 02:25 彭帅 阅读(48) | 评论 (0)编辑
     摘要: Hessian 2.0序列化协议规范翻译: Edison peng目录1.概述... 42.设计目标... 43. Hessian语法... 44. 序列化... 64.1. 二进制数据... 74.1.1. 压缩格式:短二进制... 74.1.2. Binary实例... 74.2. boolean. 74.3. date. 84.3.1. Date实例... 84.4. double. 84.... 阅读全文
posted @ 2007-09-26 02:17 彭帅 阅读(409) | 评论 (0)编辑
  2007年8月10日
在linux的网络编程中,很长的时间都在使用select来做事件触发。在linux新的内核中,有了一种替换它的机制,就是epoll。
相比于select,epoll最大的好处在于它不会随着监听fd数目的增长而降低效率。因为在内核中的select实现中,它是采用轮询来处理的,轮询的fd数目越多,自然耗时越多。并且,在linux/posix_types.h头文件有这样的声明:
#define __FD_SETSIZE    1024
表示select最多同时监听1024个fd,当然,可以通过修改头文件再重编译内核来扩大这个数目,但这似乎并不治本。

epoll的接口非常简单,一共就三个函数:
1. int epoll_create(int size);
创建一个epoll的句柄,size用来告诉内核这个监听的数目一共有多大。这个参数不同于select()中的第一个参数,给出最大监听的fd+1的值。需要注意的是,当创建好epoll句柄后,它就是会占用一个fd值,在linux下如果查看/proc/进程id/fd/,是能够看到这个fd的,所以在使用完epoll后,必须调用close()关闭,否则可能导致fd被耗尽。


2. int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
epoll的事件注册函数,它不同与select()是在监听事件时告诉内核要监听什么类型的事件,而是在这里先注册要监听的事件类型。第一个参数是epoll_create()的返回值,第二个参数表示动作,用三个宏来表示:
EPOLL_CTL_ADD:注册新的fd到epfd中;
EPOLL_CTL_MOD:修改已经注册的fd的监听事件;
EPOLL_CTL_DEL:从epfd中删除一个fd;
第三个参数是需要监听的fd,第四个参数是告诉内核需要监听什么事,struct epoll_event结构如下:
struct epoll_event {
  __uint32_t events;  /* Epoll events */
  epoll_data_t data;  /* User data variable */
};

events可以是以下几个宏的集合:
EPOLLIN :表示对应的文件描述符可以读(包括对端SOCKET正常关闭);
EPOLLOUT:表示对应的文件描述符可以写;
EPOLLPRI:表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来);
EPOLLERR:表示对应的文件描述符发生错误;
EPOLLHUP:表示对应的文件描述符被挂断;
EPOLLET: 将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的。
EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里


3. int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
等待事件的产生,类似于select()调用。参数events用来从内核得到事件的集合,maxevents告之内核这个events有多大,这个maxevents的值不能大于创建epoll_create()时的size,参数timeout是超时时间(毫秒,0会立即返回,-1将不确定,也有说法说是永久阻塞)。该函数返回需要处理的事件数目,如返回0表示已超时。

--------------------------------------------------------------------------------------------

从man手册中,得到ET和LT的具体描述如下

EPOLL事件有两种模型:
Edge Triggered (ET)
Level Triggered (LT)

假如有这样一个例子:
1. 我们已经把一个用来从管道中读取数据的文件句柄(RFD)添加到epoll描述符
2. 这个时候从管道的另一端被写入了2KB的数据
3. 调用epoll_wait(2),并且它会返回RFD,说明它已经准备好读取操作
4. 然后我们读取了1KB的数据
5. 调用epoll_wait(2)......

Edge Triggered 工作模式:
如果我们在第1步将RFD添加到epoll描述符的时候使用了EPOLLET标志,那么在第5步调用epoll_wait(2)之后将有可能会挂起,因为剩余的数据还存在于文件的输入缓冲区内,而且数据发出端还在等待一个针对已经发出数据的反馈信息。只有在监视的文件句柄上发生了某个事件的时候 ET 工作模式才会汇报事件。因此在第5步的时候,调用者可能会放弃等待仍在存在于文件输入缓冲区内的剩余数据。在上面的例子中,会有一个事件产生在RFD句柄上,因为在第2步执行了一个写操作,然后,事件将会在第3步被销毁。因为第4步的读取操作没有读空文件输入缓冲区内的数据,因此我们在第5步调用 epoll_wait(2)完成后,是否挂起是不确定的。epoll工作在ET模式的时候,必须使用非阻塞套接口,以避免由于一个文件句柄的阻塞读/阻塞写操作把处理多个文件描述符的任务饿死。最好以下面的方式调用ET模式的epoll接口,在后面会介绍避免可能的缺陷。
   i    基于非阻塞文件句柄
   ii   只有当read(2)或者write(2)返回EAGAIN时才需要挂起,等待。但这并不是说每次read()时都需要循环读,直到读到产生一个EAGAIN才认为此次事件处理完成,当read()返回的读到的数据长度小于请求的数据长度时,就可以确定此时缓冲中已没有数据了,也就可以认为此事读事件已处理完成。

Level Triggered 工作模式
相反的,以LT方式调用epoll接口的时候,它就相当于一个速度比较快的poll(2),并且无论后面的数据是否被使用,因此他们具有同样的职能。因为即使使用ET模式的epoll,在收到多个chunk的数据的时候仍然会产生多个事件。调用者可以设定EPOLLONESHOT标志,在 epoll_wait(2)收到事件后epoll会与事件关联的文件句柄从epoll描述符中禁止掉。因此当EPOLLONESHOT设定后,使用带有 EPOLL_CTL_MOD标志的epoll_ctl(2)处理文件句柄就成为调用者必须作的事情。


然后详细解释ET, LT:

LT(level triggered)是缺省的工作方式,并且同时支持block和no-block socket.在这种做法中,内核告诉你一个文件描述符是否就绪了,然后你可以对这个就绪的fd进行IO操作。如果你不作任何操作,内核还是会继续通知你的,所以,这种模式编程出错误可能性要小一点。传统的select/poll都是这种模型的代表.

ET(edge-triggered)是高速工作方式,只支持no-block socket。在这种模式下,当描述符从未就绪变为就绪时,内核通过epoll告诉你。然后它会假设你知道文件描述符已经就绪,并且不会再为那个文件描述符发送更多的就绪通知,直到你做了某些操作导致那个文件描述符不再为就绪状态了(比如,你在发送,接收或者接收请求,或者发送接收的数据少于一定量时导致了一个EWOULDBLOCK 错误)。但是请注意,如果一直不对这个fd作IO操作(从而导致它再次变成未就绪),内核不会发送更多的通知(only once),不过在TCP协议中,ET模式的加速效用仍需要更多的benchmark确认(这句话不理解)。

在许多测试中我们会看到如果没有大量的idle -connection或者dead-connection,epoll的效率并不会比select/poll高很多,但是当我们遇到大量的idle- connection(例如WAN环境中存在大量的慢速连接),就会发现epoll的效率大大高于select/poll。(未测试)



另外,当使用epoll的ET模型来工作时,当产生了一个EPOLLIN事件后,
读数据的时候需要考虑的是当recv()返回的大小如果等于请求的大小,那么很有可能是缓冲区还有数据未读完,也意味着该次事件还没有处理完,所以还需要再次读取
while(rs)
{
  buflen = recv(activeevents[i].data.fd, buf, sizeof(buf), 0);
  if(buflen < 0)
  {
    // 由于是非阻塞的模式,所以当errno为EAGAIN时,表示当前缓冲区已无数据可读
    // 在这里就当作是该次事件已处理处.
    if(errno == EAGAIN)
     break;
    else
     return;
   }
   else if(buflen == 0)
   {
     // 这里表示对端的socket已正常关闭.
   }
   if(buflen == sizeof(buf)
     rs = 1;   // 需要再次读取
   else
     rs = 0;
}


还有,假如发送端流量大于接收端的流量(意思是epoll所在的程序读比转发的socket要快),由于是非阻塞的socket,那么send()函数虽然返回,但实际缓冲区的数据并未真正发给接收端,这样不断的读和发,当缓冲区满后会产生EAGAIN错误(参考man send),同时,不理会这次请求发送的数据.所以,需要封装socket_send()的函数用来处理这种情况,该函数会尽量将数据写完再返回,返回-1表示出错。在socket_send()内部,当写缓冲已满(send()返回-1,且errno为EAGAIN),那么会等待后再重试.这种方式并不很完美,在理论上可能会长时间的阻塞在socket_send()内部,但暂没有更好的办法.

ssize_t socket_send(int sockfd, const char* buffer, size_t buflen)
{
  ssize_t tmp;
  size_t total = buflen;
  const char *p = buffer;

  while(1)
  {
    tmp = send(sockfd, p, total, 0);
    if(tmp < 0)
    {
      // 当send收到信号时,可以继续写,但这里返回-1.
      if(errno == EINTR)
        return -1;

      // 当socket是非阻塞时,如返回此错误,表示写缓冲队列已满,
      // 在这里做延时后再重试.
      if(errno == EAGAIN)
      {
        usleep(1000);
        continue;
      }

      return -1;
    }

    if((size_t)tmp == total)
      return buflen;

    total -= tmp;
    p += tmp;
  }

  return tmp;
}

 

posted @ 2007-08-10 20:36 彭帅 阅读(2269) | 评论 (4)编辑