半冷半暖秋天

2010-02-28

TCP半开连接数和“BT为什么影响浏览网页”

Filed under: 文档及资源 — sunu @ 21:01:05

转载自:http://www.windsn.com/article.asp?id=461

首先,无论是XP或VISTA系统中所作的连接数限制并不是限制系统的TCP的连接数量,而是TCP 的半开连接数。所谓TCP半开连接,就是发送了TCP连接请求,等待对方应答的状态(也就是连接尚未完全建立起来,双方还无法进行通信交互的状态。)

这里要说一个概念:
在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接。

第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。
完成三次握手,客户端与服务器开始传送数据。

上述是一个完整的TCP连接过程。

在完成三次握手之后,TCP连接已经建立,那么对系统来说,这就是一个TCP连接数。系统对这样一个数没有限制。
如果三次握手没有完成,客户端与服务器没有开始传送数据,那么,这样试图完成三次握手的事件发生的数是被系统所限制的。而这个数就是所谓的半开连接数了。

引用内容

为什么一开BT就超级慢呢.问题的根本在于BT是频繁的建立TCP连接.并且是同时建立.所以导致有大量的SYN包.
TCP是Layer 4.从技术角度说是非常耗费资源的.无论是系统资源还是网络资源.在同时并发1000个左右的连接请求的时候.
你可以想象你的网络带宽里都充斥着SYN包.所以频繁建立TCP连接才是让BT影响网络的根本原因.

下面再说两个概念:一是系统所限制的TCP半开连接数,二是P2P软件所设定的TCP半开连接数。

我先举个例子:相信大家都上过高速,走过收费站。我在过江阴大桥的时候会经过一个收费站,那里大概有十几二十个收费通道。我把这个收费通道比做TCP半开连接数。这里需要做个说明:不考虑已经建立会话的TCP连接,把收费站理想地当成半开连接数发生的地方。

比如,这里的收费站只有20个通道(即系统限制的TCP半开连接数为20),同时最多只有有10辆车可以要求过收费站。但是如果此时有100辆车要求同时过收费站,那么必须在收费站再新建立80个收费通道(假设这样通道可以随时被建立起来),但这样就超出了限制,不会被允许。

同样的,P2P软件所设定的TCP半开连接数超过了系统所限制的数量,它们在下载文件的时候不断建立新的半开连接,系统自然会给出EventID 4226事件警告。

遇过这种情况应该怎么办呢?要做三个修改:一是修改系统所限制的TCP半开连接数,二是修改P2P软件所设定的TCP半开连接数,三是修改P2P软件所允许的最大TCP连接数(已经开始传送数据的连接数量)。

一是修改系统所限制的TCP半开连接数

相信大家应该都在高速上堵过车,我最惨的一次是从上海回来,原本2个小时的车程,硬是花去我9个多小时的时间。但今年五一过江阴大桥的时候,在收费站没有收费就过去了,当时还高兴一下,但很快就发现,离收费站不远的地方设立一个临时收费站,这个地方比较宽,增加几个收费通道,实在有利于车辆的快速流通的有效措施。

这里所做的临时措施就相当于修改系统的TCP半开连接数限制了,当然修改系统文件并不是每个人都可以的,但网络上的修改工具到处都是。修改了TCP半开连接数限制,可以帮助更快地找到你需要的连接来下载文件。就BT下载而言,我们需要的是优良的种子和对方给我们的下载速度。

二是修改P2P软件所设定的TCP半开连接数

我们也不能把系统所限制的TCP半开连接数改得过大。因为每进行一次半开连接都会系统(包括路由器、防火墙、操作系统等)引入额外的开销,过多的半开连接数只会导致系统资源紧张、不稳定甚至崩溃,反而会影响网络的实际传输。其实这个才是影响BT下载时不能浏览网页的主要因素。再者,可能会被黑客利用,散布虚假资源信息或进行DDoS攻击等手段。虽然我还没有碰到过类似的攻击,但不得不防啊。

三是修改P2P软件所允许的最大TCP连接数

这里补充一下:无论是否修改系统所限制的半开连接数,都不会对下载文件的最高速率有影响。也就是说,不会提高下载的最高速率。如果已经建立了适当的连接,就没必要拥有更多的连接,这样反而可能造成网络负担。

到这里有人就说了,你说了半天又是在说废话。是啊,每个人的硬件和网络环境不一样,实在很难拿出一个两全的方案。那我就说一下我的情况吧:

我现在的操作系统是VISTA SP1,也破解了TCP半开连接数限制。不过,这个破解工具很好(远景论坛的),可以实时查看当前的连接有多少。我先是将半开连接数的限制修改到无限大,然后在下载文件的时候实时查看。在高速下载的情况下我发现,连接数有时候很少,只有4或者5;而有时候很大,会有113左右。所以,我重新将我的半开连接数限制改为了100。同样的,我也将P2P软件的半开连接数和连接数也要重新设置,这样也不会有4226事件了。

如何在linux下挂大于2TB的外设

Filed under: linux相关 — sunu @ 14:34:53

Copied from #here
如何在linux下挂大于2TB的外设

简单描述一下如何使用大于2TB的文件系统。
大家可能都和我一样遇到过如此问题,看到上面很多兄弟在争论,我也来说说看法。
就我的理解:
如果想在X86里面使用大于2TB的分区,是可以的,但是前提条件是使用安藤Itanium芯片的机器,在linux下用parted可以分出来大于2TB的分区,但是前提条件也是使用安藤芯片,简单理解就是64的芯片。在parted下标记出来GPT的label(也就是GUID的分区表,和MBR可不兼容,M$的一些产品,比如集群就不支持在GPT的分区中使用,所以在64位的机器中一定要小心了。)然后再分区。这样就支持很大很大的分区了。
如果你的机器不是64位的,那也没有问题,大家都知道目前文件系统早就突破了2TB的界限,所以,我们在32位的机器(比如Xeon基于IA32的)中,只需要使用lvm2就行了。lvm2支持在32位的系统下大于2TB的分区,它相当于在pci总线和文件系统中间了一个虚拟的层(大概这样理解,具体的理解看这里http://www.adaptec.com/pdfs/3759_2TB_WP.pdf)。这样就很容易的突破了2TB的分区。
对了,你要确定你的SCSI卡是64位的,否则即便你的disk array是>2TB的,你的机器还是认不出来,不过一般来说,现在的服务器都是64位的pci卡了,比如dell 1850 ,2850。
总结一下,想使用大于2TB的文件系统在linux下有2种方法:
1、使用64位的系统,比如安藤系统。然后在linux下用parted建立GPT的分区表(不是msdos[MBR]或者loop),然后建立超级大的分区,然后直接用XFS(我比较喜欢这个)format就行了。
2、使用32位的系统,比如Xeon,在linux下建立N个分区,然后用LVM2来做虚拟盘,比如20个400G的盘,算算看就知道是8TB。
这里还有一些归纳:
1、对于GUID分区表(GPT)磁盘,最多可创建128个主磁盘分区。
2、x86 使用msdos,Itanium 使用gpt。
3、Redhat要到As4,而且是pack1之后才支持,如果仅仅是as4,需要打补丁。当然如果大家用centos很方便了。2.4内核不支持,2.6内核要多少来着。。。忘记了,大家可以看As4 pack1发布时候的发布文档,里面说明了。
4、图省力,把/dev/sda直接格式化为一个分区,是绝对绝对不推荐的。大家一定要记主!绝对不要直接把块设备格式化了。至少也要有个sda1。否则没几天数据就都丢了,甚至当你重新启动机器的时候数据就没了。
5、http://wuarchive.wustl.edu/pub/centos4.64/NOTES/RELEASE-NOTES-U1-zh_CN.html 这里讲了为啥要用安藤;http://www.adaptec.com/pdfs/3759_2TB_WP.pdf这里讲了2TB的方案,从历史原因到现状。除了linux的还有如何在M$下使用大于2TB的磁盘。很详细的,建议初级作存储的兄弟都可以看看。
大概抄录一下:
Commonly, the firmware, BIOS, driver, and at least part of the
storage stack support 32-bit block numbers, thereby limiting
the storage to 2TB. However since most filesystems support
page sizes larger than 512 B, they actually already support volumes
greater than 2TB. In other words, a filesystem may have
only 32-bit block numbers, but those blocks are commonly
multiples of 512 bytes, such as 2KB, 4KB, 8KB, etc., allowing
the volume size to be 8TB, 16TB, 32TB, respectively. Of
course, the factors that go into defining the max volume size
are much more complicated than this, but block size certainly
is an important factor.
With drivers presenting up to 2TB volumes and filesystems
supporting greater than 2TB volumes, there is one piece of the
puzzle missing: a method for combining smaller drive volumes
into larger filesystem volumes. This is possible with the several
operating systems (OS) that have a virtualization layer in the
storage stack. Just like the array virtualization in a PCI RAID
controller, the OS virtualization layer is able to combine smaller
volumes (disks) into a larger volume (virtual disk) for
improved performance and increased capacity. This low-overhead,
high-performance operating system layer is the key to
the solution presented in this paper.

BTW:我随手写的哦,没有好好组织语言,大家凑或看看吧。CU的朋友也可以直接联系我:MSN
Erjing (at) hotmail.com,我有空的时候乐意帮大家解决问题。我不是做存储的,太专业的问题俺就:P

加一句,如果想使用LVM,用fdisk是不能给大于2TB的设备分区的,还是要用parted.
而且要gpt,就像这样:
mkpart primary ext2 0 200000
mkpart primary ext2 200001 400000
mkpart primary ext2 400001 600000
mkpart primary ext2 600001 800000
mkpart primary ext2 800001 1000000
mkpart primary ext2 1000001 1200000
mkpart primary ext2 1200001 1400000
mkpart primary ext2 1400001 1600000
mkpart primary ext2 1600001 1800000
mkpart primary ext2 1800001 2000000
mkpart primary ext2 2000001 2200000
mkpart primary ext2 2200001 2400000
mkpart primary ext2 2400001 2600000
mkpart primary ext2 2600001 2800000
mkpart primary ext2 2800001 3000000
如果你用
mkpart extended 0 3000000
mkpart logical ext2 0 200000
mkpart logical ext2 200001 400000
mkpart logical ext2 400001 600000
mkpart logical ext2 600001 800000
mkpart logical ext2 800001 1000000
mkpart logical ext2 1000001 1200000
mkpart logical ext2 1200001 1400000
mkpart logical ext2 1400001 1600000
mkpart logical ext2 1600001 1800000
mkpart logical ext2 1800001 2000000
mkpart logical ext2 2000001 2200000
mkpart logical ext2 2200001 2400000
mkpart logical ext2 2400001 2600000
mkpart logical ext2 2600001 2800000
mkpart logical ext2 2800001 3000000
会发生什么?最多到1T就分不下去了。
如果你用fdisk -l会看到什么?
Device Boot Start End Blocks Id System
/dev/sda1 1 267350 2147483647+ ee EFI GPT
是的,看不到你的分区,所以一定要养成用parted来看分区的习惯,忘记fdisk吧。

看看这里:
ls /dev/sda* -l
brw-rw—- 1 root disk 8, XXXXXXXXXXXX /dev/sda
brw-rw—- 1 root disk 8, XXXXXXXXXXXX /dev/sda1
brw-rw—- 1 root disk 8, XXXXXXXXXXXX /dev/sda10
brw-rw—- 1 root disk 8, XXXXXXXXXXXX /dev/sda11
brw-rw—- 1 root disk 8, XXXXXXXXXXXX /dev/sda12
brw-rw—- 1 root disk 8, XXXXXXXXXXXX /dev/sda13
brw-rw—- 1 root disk 8, XXXXXXXXXXXX /dev/sda14
brw-rw—- 1 root disk 8, XXXXXXXXXXXX/dev/sda15
brw-rw—- 1 root disk 8, XXXXXXXXXXXX /dev/sda2
brw-rw—- 1 root disk 8, XXXXXXXXXXXX /dev/sda3
brw-rw—- 1 root disk 8, XXXXXXXXXXXX /dev/sda4
brw-rw—- 1 root disk 8, XXXXXXXXXXXX/dev/sda5
brw-rw—- 1 root disk 8, XXXXXXXXXXXX /dev/sda6
brw-rw—- 1 root disk 8, XXXXXXXXXXXX /dev/sda7
brw-rw—- 1 root disk 8, XXXXXXXXXXXX /dev/sda8
brw-rw—- 1 root disk 8, XXXXXXXXXXXX/ dev/sda9
这才是你想要的。

以下是我处理的步骤,parted没有写成脚本,大家凑或用:)
mklabel gpt
mkpart primary ext2 0 200000 #用ext2也无所谓的,总之随便指定一个。200000就是200G了,我把3TB的内容划分成了15个200G的。
mkpart primary ext2 200001 400000
mkpart primary ext2 400001 600000
mkpart primary ext2 600001 800000
mkpart primary ext2 800001 1000000
mkpart primary ext2 1000001 1200000
mkpart primary ext2 1200001 1400000
mkpart primary ext2 1400001 1600000
mkpart primary ext2 1600001 1800000
mkpart primary ext2 1800001 2000000
mkpart primary ext2 2000001 2200000
mkpart primary ext2 2200001 2400000
mkpart primary ext2 2400001 2600000
mkpart primary ext2 2600001 2800000
mkpart primary ext2 2800001 3000000
然后在这些分区变成PV
pvcreate /dev/sda1
pvcreate /dev/sda2
pvcreate /dev/sda3
pvcreate /dev/sda4
pvcreate /dev/sda5
pvcreate /dev/sda6
pvcreate /dev/sda7
pvcreate /dev/sda8
pvcreate /dev/sda9
pvcreate /dev/sda10
pvcreate /dev/sda11
pvcreate /dev/sda12
pvcreate /dev/sda13
pvcreate /dev/sda14
pvcreate /dev/sda15

然后可以直接建立VG st00
vgcreate -s 256M st00 /dev/sda1 \
/dev/sda2 \
/dev/sda3 \
/dev/sda4 \
/dev/sda5 \
/dev/sda6 \
/dev/sda7 \
/dev/sda8 \
/dev/sda9 \
/dev/sda10 \
/dev/sda11 \
/dev/sda12 \
/dev/sda13 \
/dev/sda14 \
/dev/sda15

或者先建立,然后扩展
vgextend st00 \
/dev/sda2 \
/dev/sda3 \
/dev/sda4 \
/dev/sda5 \
/dev/sda6 \
/dev/sda7 \
/dev/sda8 \
/dev/sda9 \
/dev/sda10 \
/dev/sda11 \
/dev/sda12 \
/dev/sda13 \
/dev/sda14 \
/dev/sda15
在VG st00上,建立LV md00
lvcreate -L2.86T -nmd00 st00
建立分区
mkfs.xfs /dev/st00/md00
完毕.
扩充的方法我这里就不写了,LVM管理不是这篇文章的重点。

assert() 函数用法

Filed under: C/C++ — 标签:, — sunu @ 13:33:15

From http://hi.baidu.com/litomboy/blog/item/b339e1037c7cc4ef09fa9385.html

assert宏的原型定义在中,其作用是如果它的条件返回错误,则终止程序执行,原型定义:

#include 
void assert( int expression );

assert的作用是现计算表达式 expression ,如果其值为假(即为0),那么它先向stderr打印一条出错信息,然后通过调用 abort 来终止程序运行。
请看下面的程序清单badptr.c:

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
int main( void )
{
   FILE *fp;
   fp = fopen( "test.txt", "w" );  //以可写的方式打开一个文件,
                                              //如果不存在就创建一个同名文件
   assert( fp );                       //所以这里不会出错
   fclose( fp );
   fp = fopen( "noexitfile.txt", "r" ); //以只读的方式打开一个文件,
                                                  //如果不存在就打开文件失败
   assert( fp );                           //所以这里出错
   fclose( fp );                           //程序永远都执行不到这里来
   return 0;
}

[root@localhost error_process]# gcc badptr.c
[root@localhost error_process]# ./a.out
a.out: badptr.c:14: main: Assertion `fp' failed.
已放弃

使用assert的缺点是,频繁的调用会极大的影响程序的性能,增加额外的开销。
在调试结束后,可以通过在包含#include 的语句之前插入 #define NDEBUG 来禁用assert调用,示例代码如下:

#include <stdio.h>
#define NDEBUG
#include <assert.h>

用法总结与注意事项:
1) 在函数开始处检验传入参数的合法性,如:

//功能:改变缓冲区大小,
//参数:nNewSize 缓冲区新长度
//返回值:缓冲区当前长度
//说明:保持原信息内容不变     nNewSize<=0表示清除缓冲区
int resetBufferSize(int nNewSize)
{
  assert(nNewSize >= 0);
  assert(nNewSize <= MAX_BUFFER_SIZE);
  ...
}

2) 每个assert只检验一个条件,因为同时检验多个条件时,如果断言失败,无法直观的判断是哪个条件失败
不好: assert(nOffset>=0 && nOffset+nSize<=m_nInfomationSize);
好: assert(nOffset >= 0);
assert(nOffset+nSize <= m_nInfomationSize);

3) 不能使用改变环境的语句,因为assert只在DEBUG个生效,如果这么做,会使用程序在真正运行时遇到问题
错误: assert(i++ < 100)
这是因为如果出错,比如在执行之前i=100,那么这条语句就不会执行,那么i++这条命令就没有执行。
正确: assert(i < 100)
i++;
4) assert和后面的语句应空一行,以形成逻辑和视觉上的一致感
5) 有的地方,assert不能代替条件过滤

about libevent

Filed under: C/C++ — 标签: — sunu @ 13:26:21

libevent homepage
http://www.monkey.org/~provos/libevent/

libevent online document
http://www.monkey.org/~provos/libevent/doxygen-1.4.10/index.html
http://www.wangafu.net/~nickm/libevent-book/TOC.html(需翻墙)

samples
http://blog.gslin.info/2005/11/network-programming-using-libevent-i.html
http://blog.gslin.info/2005/11/network-programming-using-libevent-ii.html
http://blog.gslin.info/2005/11/network-programming-using-libevent-iii.html

2010-02-07

明天回家过年

Filed under: 不知所云 — sunu @ 23:28:06

2009年,折腾的一年,折腾了一年,终于TMD过去了。就先这样傻活着吧,只要想想还有一大群人过得比我更挫,我那不平衡的心立马就宁静下来了。

上大学以前回家基本不带书,以后回家倒是都装模作样地带几本回去啃,不过从来都是啃些没营养的工具书,功利得很。如果我是饭店的服务员,估计就会带几张菜单回去背诵。

过年不用走亲戚,不用会同学,挺轻松的。好像是有高中同学会,不过我已经很早就想好了借口。

Powered by WordPress