黑客通常通过获取一个HTTP Response,然后解析出HTTP Response Header来知道对方用的是什么web 服务器软件,如下:

HTTP/1.1 200 OKServer: Microsoft-IIS/5.0Date: Thu, 07 Jul 2005 13:08:16 GMTContent-Length: 1270对于IIS来说有一个工具(URLScan)可以用来修改这个HTTP Response Header,让黑客得到假的Header信息,URLScan的地址:http://learn.iis.net/page.aspx/473/using-urlscan

对于Tomcat,Header一般会暴露如下信息:
Server: Apache-Coyote/1.1

修改是在conf/server.xml,在Connector 元素中设置server属性即可。如下:


对于apache呢?
只要在httpd.conf中配上如下两个参数:
ServerSignature Off
ServerTokens Prod


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/dctfjy/archive/2009/06/05/4244321.aspx
黑客通常通过获取一个HTTP Response,然后解析出HTTP Response Header来知道对方用的是什么web 服务器软件,如下:

HTTP/1.1 200 OKServer: Microsoft-IIS/5.0Date: Thu, 07 Jul 2005 13:08:16 GMTContent-Length: 1270对于IIS来说有一个工具(URLScan)可以用来修改这个HTTP Response Header,让黑客得到假的Header信息,URLScan的地址:http://learn.iis.net/page.aspx/473/using-urlscan

对于Tomcat,Header一般会暴露如下信息:
Server: Apache-Coyote/1.1

修改是在conf/server.xml,在Connector 元素中设置server属性即可。如下:


对于apache呢?
只要在httpd.conf中配上如下两个参数:
ServerSignature Off
ServerTokens Prod


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/dctfjy/archive/2009/06/05/4244321.aspx
Tsic506这个能达到 ±0.1℃温感集成块还没有到货的时候,我们开始用市面上最为普通的DS18B20来进行原理图设计实验。DS18B20温感集成块的精度只有±0.5℃,虽然便宜(只要7元人民币),但是它与昂贵的Tsic506(100元人民币)使用的是同样的单总线结构,所以用来做原理图设计实验,足够了。

在查DS18B20相关的资料的时候,无意中发现一个惊喜:看到一篇文章《DS18B20的高精度温度传感器设计》,提供了如何降低误差的方法,并且表明 “可得到误差在0.1℃以内的温度精度” 。大学老师的大作,满篇图形、公式、矩阵……,一看就感觉让人信服!

兴奋啊,想想,100元 vs. 7元!如果能提高精度,别说±0.1℃,只要能到±0.2℃就行,这可是93元的成本差别啊!

于是,仔细研读。

……

……

好景不长,因为,疑窦丛生:

1.前面四章讲的都是DS18B20原理,可以略过。第五章名为“采用最小二乘估计降低线性误差”,嗯,这是正题。
可是,一开始就感觉不对头。
第五章一上来就说“通过以上方法理论上可以得到0.1℃范围内的误差,但由于受各种因数的影响.往往误差范围能达到0.5℃。通过分析.得知误差主要来源于芯片内部半导体热噪声。其类型为线性误差,并随温度的上升而误差增大……”。这是哪儿跟哪儿啊?前四章讲的都是该芯片的内部功能结构,凭什么理论作者们可以得到“


DS18B20官方文档上的误差曲线
点击在新窗口中浏览此图片

通过以上方法理论上可以得到0.1℃范围内的误差”这个结论?!基于这个不靠谱的结论,又说“通过分析.得知误差主要来源于芯片内部半导体热噪声。其类型为线性误差,并随温度的上升而误差增大”,凭什么?凭什么得到这几个结论啊?
2.看看DS18B20官方的文档中的误差曲线(见右图),就可以更加证明了,这篇文章的这几个推导(尤其是上面灰色字体中带下划线的部分)根本是错的!推导错了,这不是最严重的问题,这段话最严重的问题在于:没有论据,就敢如此推断!

3.作者们根据以上结论(不靠谱的结论),建立了误差模型:“为了提高估计精度,对于不同的温度区间应采用不同的修正系数.设该系统的线性误差模型如下:
T=KTγ+C
其中,T为测量值,Tγ为真实值(采用更高精度MS6506测量而得).K为随温度变化的线性误差修正系数,C为误差补偿参数……”
而后,就是大学老师擅长的一堆高数理论,最小二乘估计、矩阵、维度、极限、梯度,一顿眼花缭乱的分析,得出结论“K=1.0408.C=-1.5256,该修正系数是在25℃~40℃温度下得到的。其他温度范围内也可采用相同方法获得修正系数。根据计算得到的修正系 数编写相应的单片机程序,就可得到误差在0.1℃以内的温度精度。基于以上的理论基础,可以设计出高精度、低性价比的温度传感器”。
我们来看看灰色字体部分中那些带下划线的部分:

“K=1.0408.C=-1.5256”,如果我们用上面的这个官方的平均误差图来看,就知道这个结论是不准确的,比如说,假如我们用DS18B20去测一个30℃的温度,那么官方结论是:平均测量温度应该是在29.82℃。如果用这篇论文的计算方法,T=1.0408Tγ-1.5256,测量温度应该在29.6984℃。
“采用更高精度MS6506测量而得”。纵观整篇论文,其实验与推断的关键点在于:建立误差模型,然后通过测试,得到误差模型中的参数。所以,最后结论的准确性其实质是依赖测试的准确性。于是,我对这篇文章中两次被提及的“高精度MS6506”产生了兴趣:如果不贵,万元左右的,买一台,进行温感探头的校准,还是挺值得的,实在不行,租也可以啊。到网上一查,我的天,才几百元!几百元的温度测量设备,就能称作“高精度”?再查查,OMG,淘宝里大把的,你猜猜精度是多少?不是±0.01℃,也不是±0.1℃,也不是±0.5℃,而是±1℃!
拿±1℃的温度计去校准±0.5℃的温感探头?!这简直是太滑稽了吧!
难怪这篇文章里如此模糊地去提及这个测试设备啊,故意的吧!
不是故意的?那你这学术文章,也太不严谨了吧!






echo [$(date +%Y/%m/%d\ %H:%M:%S)]
[2019/06/18 11:23:55]



sh funlog.sh
[2019/06/18 11:28:32]: INFO a message

=============================================================================


shell时间:
a=`date +%Y%m%d`
echo $a;


# sh data.sh
20101028




#!/bin/sh
#log
MYDATE=`date +%d%m%y`
#append MYDATE to the variable LOGFILE that holds the actual filename of the log
LOGFILE=/root/test_log.$MYDATE
#create the file
>$LOGFILE
MYTIME=`date +%d%R`
LOGFILE2=/root/test_logtime.$MYTIME
#create the file
>$LOGFILE2


会生成俩文件:

ls /root/test_log.281010
/root/test_log.281010


ls /root/test_logtime.2819:26

/root/test_logtime.2819:26
来源:http://liubin.blog.51cto.com/282313/166927
对用户号码分为1000个表,0--->999,咋个通过awk去管理里面的一些号码呢,那就是用如下的方法,构造SQL语句:
881607843494
8881575730024
888844538713
8881547203329
8881551222564
8881620264123
8881098097115
8881622129944
8881311344768
8881609513205
8881643662199
8881652446787
8881664232709
8881623970620
8881642895112
8881436794690
8881359061975


cat QQ.txt |awk '{print "select * from Tbl_User_"$1%1000 "where FQQ='\''" $1 "'\'';"}'

执行了后显示如下结果:
select * from Tbl_User_494where FQQ='1607843494';
select * from Tbl_User_24where FQQ='1575730024';
select * from Tbl_User_713where FQQ='844538713';
select * from Tbl_User_329where FQQ='1547203329';
select * from Tbl_User_564where FQQ='1551222564';
select * from Tbl_User_123where FQQ='1620264123';
select * from Tbl_User_115where FQQ='1098097115';
select * from Tbl_User_944where FQQ='1622129944';
select * from Tbl_User_768where FQQ='1311344768';
select * from Tbl_User_205where FQQ='1609513205';
select * from Tbl_User_199where FQQ='1643662199';
select * from Tbl_User_787where FQQ='1652446787';
select * from Tbl_User_709where FQQ='1664232709';
select * from Tbl_User_620where FQQ='1623970620';
select * from Tbl_User_112where FQQ='1642895112';
select * from Tbl_User_690where FQQ='1436794690';
select * from Tbl_User_975where FQQ='1359061975';
这个应该是这样的,在你上次调试的时候,chwh.exe 没有正常退出(可以通过任务管理器查看出此进程是否正在运行).
//那个error主要是在进程里通过任务管理器查看出此进程还在运行,终止就行了,在我这就可以运行

int类型究竟占几个字节:
最近在看深入理解计算机系统这本书,上面提到了在32位机器和64机器中int类型都占用4个字节。后来,查了The C Programming language这本书,里面有一句话是这样的:Each compiler is free to choose appropriate sizes for its own hardware, subject only to the restriction that shorts and ints are at least 16bits, longs are at least 32bits, and short is no longer than int, which is no longer than long.意思大致是编译器可以根据自身硬件来选择合适的大小,但是需要满足约束:short和int型至少为16位,long型至少为32位,并且short型长度不能超过int型,而int型不能超过long型。这即是说各个类型的变量长度是由编译器来决定的,而当前主流的编译器中一般是32位机器和64位机器中int型都是4个字节(例如,GCC)。
From: https://blog.51cto.com/charlesxie/939680


字节(Byte)是存储数据的基本单位,并且是硬件所能访问的最小单位。前面说过,CPU 只能直接处理内存数据,不能直接处理硬盘数据。硬盘数据必须先调入内存条中才可以运行。内存中存储数据的最小单位是“位(Bit)”。字节是存储数据的基本单位,位是存储数据的最小单位,不要混淆了。

内存里面存放的全是二进制代码。内存里面有很多“小格子”,每个“格子”中只能存放一个 0 或 1。一个“小格子”就是一位,所以“位”要么是 0,要么是 1,不可能有比位更小的单位。那么字节和位是什么关系呢?8 个“小格子”就是一字节,即一字节等于 8 位。
那么为什么硬件所能访问的最小单位是字节,而不是位呢?因为硬件是通过地址总线访问内存的,而地址是以字节为单位进行分配的,所以地址总线只能精确到字节。那如何控制到它的某一位呢?这个只能通过“位运算符”,即通过软件的方式来控制。

字节换算
常见的存储单位主要有bit(位)、B(字节)、KB(千字节)、MB(兆字节)、GB(千兆字节)。它们之间主要有如下换算关系:

1B=8bit
1KB=1024B
1MB=1024KB
1GB=1024MB

其中 B 是 Byte 的缩写。

https://blog.csdn.net/wydyd110/article/details/84589541


Long(长整型)变量存储为 32 位(4 个字节)有符号的数值形式,
有符号的数值形式,其范围从 -2,147,483,648 到 2,147,483,647(约为21亿)。

对32位cpu来说
整型的范围为 -2147483648~~~2147483647  这个应该对吧?
那无符号整型为:0 ~~~ 4694967295  对吧
按理说 我定义个  unsigned int aaa=2147483648;  没有越界阿  
不知道为什么得到的结果不对!!
printf("%ld\n",aaa); 得到的结果是:
-2147483648
帮忙给解释一下吧 !!


printf("%ld\n",aaa); 得到的结果是:
-2147483648
帮忙给解释一下吧 !!



这一打印就对了:

printf("%u\n",aaa);



特别注意:
程序在编译时分配内存,所以比如int型占多少内存是看编译器的,在TC2.0里,int占用2个字节,在VC6.0或WinGW是占4个字节的。其它类型的内存占用问题类似。而C-Free是一个IDE(集成开发环境),将许多的工具(比如:编译器、调试器……)集成在一起,形成一个比较方便的开发工具,其中编译器用的是WInGW,所以是占4个字节!
Linux下stdio.h调用系统的动态库查看:

编译:jackxiang@72.46.128.82:~/echo# gcc helo.c

说明调用的是:libc.so.6 这个动态库。
一、静态库的创建和使用:阅读全文
Tags: ,
今天没事写了个小demo, 根据域名获取http响应报文, 程序也不是很完善
其实主要是要练习一下非阻塞I/O处理.

上代码:

/*
* Author: looyao
*/

#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <fcntl.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>

static int set_fl(int fd, int flags)
{
int val;

if ((val = fcntl(fd,F_GETFL,0)) < 0) {
printf("fcntl F_GETFL error\n");
return -1;
}

val |= flags;

if (fcntl(fd,F_SETFL,val) < 0) {
printf("fcntl F_SETFL error\n");
return -1;
}

return 0;
}

void timeout()
{
printf("time out\n");
exit(0);
}

int main(int argc, char **argv)
{
int sockfd;
struct sockaddr_in servaddr;
struct hostent *host;
char *msg = strdup("GET / HTTP/1.1\r\nHOST: ");
char rbuf[32], res_header[1024];
char *host_ip, *ptr, *pos;
int ntowrite, nwrite, nread, nread_res_header = 0, content_length, nread_content_length = 0;

signal(SIGALRM, timeout);

if (argc < 2) {
printf("请输入域名参数\n");
exit(0);
} else if (argc > 2) {
printf("输入的参数过多\n");
exit(0);
}

msg = realloc(msg, strlen(msg) + strlen(argv[1]) + sizeof("\r\n\r\n"));
sprintf(msg + strlen(msg), "%s\r\n\r\n", argv[1]);

sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("socket");
exit(0);
}

host = gethostbyname(argv[1]);
if (host == NULL) {
printf("无法获取此域名IP\n");
goto END;
}

host_ip = inet_ntoa(*((struct in_addr *)host->h_addr));

bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(80);
inet_pton(AF_INET, host_ip, &servaddr.sin_addr);
if( connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) {
perror("connect");
exit(0);
}

if (set_fl(sockfd, O_NONBLOCK) < 0) {
printf("set nonblock error");
goto END;
}

ntowrite = strlen(msg);
ptr = msg;
alarm(10);
while (ntowrite > 0) {
nwrite = write(sockfd, ptr, ntowrite);
if (nwrite <= 0) {
perror("write:");
goto END;
}
ptr += nwrite;
ntowrite -= nwrite;
}
alarm(0);

/* read response header */
ptr = res_header;
alarm(10);
while (1) {
errno = 0;
nread = read(sockfd, ptr, sizeof(res_header) - nread_res_header);
if(nread < 0){
if(errno == EAGAIN){
continue;
}
perror("read");
goto END;
}
nread_res_header += nread;
ptr += nread;
if((pos = strstr(res_header, "\r\n\r\n")) != NULL || nread_res_header == sizeof(res_header)){
break;
}
}
alarm(0);

if (!(pos = strstr(res_header, "Content-Length:"))) {
printf("响应报文错误");
goto END;
} else {
pos += 16;
if (!(ptr = strstr(pos, "\r\n"))) {
printf("响应报文错误");
goto END;
}
char buf[10];
snprintf(buf, (ptr - pos) > 10 ? 10 : (ptr - pos) + 1, "%s", pos);
content_length = atoi(buf);
}

write(STDOUT_FILENO, res_header, nread_res_header);
if ((pos = strstr(ptr, "\r\n\r\n"))) {
pos += 4;
nread_content_length = nread_res_header - (pos - res_header);
} else {
/* 此处有bug, 如果响应头很长, 没有读到\r\n\r\n, 但是, 先这样吧 :D */
goto END;
}

alarm(10);
while (1) {
errno = 0;
memset(rbuf, 0, sizeof(rbuf));
nread = read(sockfd, rbuf, sizeof(rbuf));
if (nread < 0) {
if (errno == EAGAIN) {
continue;
}
perror("read");
goto END;
}
write(STDOUT_FILENO, rbuf, nread);
nread_content_length += nread;
if (nread_content_length >= content_length){
break;
}
}
alarm(0);

END:
close(sockfd);
free(msg);
return 0;
}


编译后运行 ./demo www.baidu.com
响应的报文如下:
HTTP/1.1 200 OK
Date: Thu, 29 Apr 2010 08:57:48 GMT
Server: BWS/1.0
Content-Length: 3521
Content-Type: text/html;charset=gb2312
Cache-Control: private
Expires: Thu, 29 Apr 2010 08:57:48 GMT
Set-Cookie: BAIDUID=4573491A3ED9E0B16CA37586CFB9460E:FG=1; expires=Thu, 29-Apr-40 08:57:48 GMT; path=/; domain=.baidu.com
P3P: CP=" OTI DSP COR IVA OUR IND COM "

<!doctype html><html><head><meta http-equiv="Content-Type" content="text/html;charset=gb2312"><title>百度一下,你就知道      </title><style>body{font:12px arial;text-align:center;background:#fff}body,p,form{margin:0;padding:0}body,form,#lg{position:relative}td{text-align:left}img{border:0}a{color:#00c}a:active{color:#f60}#u{padding:7px 10px 3px 0;text-align:right}#m{width:650px;margin:0 auto}#nv{font-size:16px;margin:0 0 4px -32px}#nv a,#nv b,#su,#lk{font-size:14px}#lg{margin:-17px 0 9px}#fm{padding-left:111px;text-align:left}#kw{width:391px;line-height:16px;padding:3px 1px;margin:0 6px 0 0;font:16px arial}#su{width:78px;height:28px;line-height:24px}#kw,#su{vertical-align:middle}#lk{margin:33px 0}#lk span{font:14px "宋体"}#lm{height:60px}#lh{margin:16px 0 5px;font:12px "宋体"}#lh a{font:12px arial}#hp{position:absolute;line-height:14px;margin:0 0 0 6px;top:-1px;*top:2px}#cp,#cp a{color:#77c}</style></head>
<body><p id="u"><a href="http://passport.baidu.com/?login&tpl=mn">登录</a></p><div id="m"><p id="lg"><img src="http://www.baidu.com/img/baidu_logo.gif" width="270" height="129" usemap="#mp"></p><p id="nv"><a href="http://news.baidu.com">新&nbsp;闻</a> <b>网&nbsp;页</b> <a href="http://tieba.baidu.com">贴&nbsp;吧</a> <a href="http://zhidao.baidu.com">知&nbsp;道</a> <a href="http://mp3.baidu.com">MP3</a> <a href="http://image.baidu.com">图&nbsp;片</a> <a href="http://video.baidu.com">视&nbsp;频</a> <a href="http://map.baidu.com">地&nbsp;图</a></p><div id="fm"><form name="f" action="s"><input type="text" name="wd" id="kw" maxlength="100"><input type="submit" value="百度一下" id="su"><span id="hp"><a href="/gaoji/preferences.html">设置</a><br><a href="/gaoji/advanced.html">高级</a></span></form></div>
<p id="lk"><a href="http://hi.baidu.com">空间</a> <a href="http://baike.baidu.com">百科</a> <a href="http://www.hao123.com">hao123</a><span> | <a href="/more/">更多&gt;&gt;</a></span></p><p id="lm"></p><p><a id="st" onClick="this.style.behavior='url(#default#homepage)';this.setHomePage('http://www.baidu.com')" href="http://utility.baidu.com/traf/click.php?id=215&url=http://www.baidu.com">把百度设为主页</a></p><p id="lh"><a href="http://e.baidu.com/?refer=888">加入百度推广</a> | <a href="http://top.baidu.com">搜索风云榜</a> | <a href="http://home.baidu.com">关于百度</a> | <a href="http://ir.baidu.com">About Baidu</a></p><p id="cp">&copy;2010 Baidu <a href="/duty/">使用百度前必读</a> <a href="http://www.miibeian.gov.cn" target="_blank">京ICP证030173号</a> <img src="http://gimg.baidu.com/img/gs.gif"></p></div><map name="mp"><area shape="rect" coords="43,22,227,91" href="http://hi.baidu.com/baidu/" target="_blank" title="点此进入 百度的空间"></map></body>
<script>var w=window,d=document,n=navigator,k=d.f.wd,a=d.getElementById("nv").getElementsByTagName("a");if(n.userAgent.indexOf("MSIE")==-1||window.opera){d.getElementById("st").style.display="none"};for(var i=0;i<a.length;i++){a[i].onclick=function(){if(k.value.length>0){var o=this,h=o.href,q=encodeURIComponent(k.value);if(h.indexOf("q=")!=-1){o.href=h.replace(/q=[^&$]*/,"q="+q)}else{this.href+="?q="+q}}}};(function(){if(/q=([^&]+)/.test(location.search)){k.value=decodeURIComponent(RegExp.$1)}})();if(n.cookieEnabled&&!/sug?=0/.test(d.cookie)){d.write('<script src=http://www.baidu.com/js/bdsug.js?v=1.0.3.0><\/script>')};if(w.attachEvent){w.attachEvent("onload",function(){k.focus();})}else{w.addEventListener('load',function(){k.focus()},true)};w.onunload=function(){}</script></html><!--ae75535d4a224623-->


非阻塞要不断的轮询, 浪费了CPU时间, 但是说与使用select机制相比, 到底那个机制更快,
也需要看情况, 我会继续试验.
对于read的结束条件, 具体看通信的协议.
http协议主要是看Content-Length, 还有一种是Transfer-Encoding: chunked,
我这个小demo实现的是根据Content-Length判断read结束.
over, 未完待续...
来源:http://hi.baidu.com/teng0210/blog/item/4955e8946e992b47d0135e2a.html


C语言HTTP请求GET,因对《所谓黑客揭秘》,大家都攻击代码的要求。所以我开始了为期两周的C/C++学习。由于没有任何C/C++基础,而是临时突击,所以代码肯定漏洞甚多,请观者见谅。同时欢迎拍砖或者支出代码错误,以求大家共同进步。:



来自:http://blog.csdn.net/aofengdaxia/article/details/5984431
静态库其实就是一堆.o文件的集合.
下面引用一个例子来说说静态库的创建与使用

//1.c中有一个简单的输出函数 func1
#include <stdio.h>

void func1()
{
printf("call func1\n");
}

//2.c中也有一个简单的输出函数 func2
#include <stdio.h>

void func2()
{
printf("call func2\n");
}


gcc生成目标文件
gcc -c 1.c 2.c
这样会生成1.o 2.o

接下来  我们创建静态库
使用ar命令
ar rv libmytest.a 1.o 2.o
这样就生成了静态库libmytest.a

使用静态库
//test.c
int main()
{
func1();
func2();
return 0;
}

编译
gcc -o test test.c libmytest.a
这样就生成了可执行文件
./test
call func1
call func2


PS:说说ar的简单使用
ar r test.a 1.o 2.o  r选项是插入  将1.o, 2.o插入到test.a中 加上v 会打印提示
ar d test.a 1.o      d选项是删除  将1.o从test.a中删除
ar t test.a          t选项是列出详细信息  打印出test.a中的包含的文件
ar x test.a          x选项是解压  解压出test.a中的文件

来源:http://hi.baidu.com/teng0210/blog/item/8df32a7ae666e3f90ad18780.html

上面的创建是没有问题的,但是你发现没有,1.c 2.c里面都有#include "stdio.h",而这时候对大规模开发程序是没有得到重复用的,
把它放到一个文件里,于是头文件出现了.h文件:
如下目录结构:
include/  lib/  libprint.a  main*  main.cpp  Makefile  print.cpp  run.sh
print.cpp:注意没有包含 stdio.h

#include "print.h"
void printhello(){
printf("Hello, world\n");
}



vi include/print.h :包含了stdio.h
#include <stdio.h>
//#include <cstdio>
void printhello();


vi main.cpp 这儿得包含了print.h了。


#include "print.h"
using namespace std;
int main(void)
{
    printhello();
    return 0;
}


编译如下:
g++ -o ./lib/print.o -c print.cpp -I/root/c++/include
ar q  ./lib/libprint.a  ./lib/print.o
g++  main.cpp -o main  -I/root/c++/include  -L/root/c++/lib  -lprint



./main
Hello, world


把上面的print.cpp 里面的#include "print.h"修改为:#include <stdio.h>,去掉main.cpp里面的#include "print.h",后按照上面开头那样用g++编译,会在最后报错:

# gcc main.cpp ./lib/print.o  
main.cpp: In function ¡®int main()¡¯:
main.cpp:5: error: ¡®printhello¡¯ was not declared in this scop

所以,建议还是加上.h头文件为好!

g++ -c print.cpp -o lib/print.o
cd lib/
ar q libprint.a print.o
cd ..
g++ main.cpp ./lib/libprint.a  
main.cpp: In function ¡®int main()¡¯:
main.cpp:5: error: ¡®printhello¡¯ was not declared in this s sco

全变为:.c后用:
gcc -c print.c -o lib/print.o
cd lib/
ar q libprint.a print.o
cd ..
gcc main.c ./lib/libprint.a

Ok了:
./main
Hello, world
PHP中有一种数据类型非常重要,它就是关联数组,又称为哈希表(hash table),是一种非常好用的数据结构。

在程序中,我们可能会遇到需要消重的问题,举一个最简单的模型:

有一份用户名列表,存储了 10000 个用户名,没有重复项;
还有一份黑名单列表,存储了 2000 个用户名,格式与用户名列表相同;
现在需要从用户名列表中删除处在黑名单里的用户名,要求用尽量快的时间处理。

这个问题是一个小规模的处理量,如果实际一点,2 个表都可能很大,比如有 2 亿条记录。

我最开始想到的方法,就是做一个嵌套的循环,设用户名表有 M 条记录,黑名单列表有 N 条记录,那么,循环的次数是 M * N 次!
PHP 版代码:


01 <?php  
02 foreach($arrayM as $keyM => $nameM) {  
03 foreach($arrayN as $nameN) {  
04 if ($nameM == $nameN) {  
05 // 本行执行了 M * N 次!  
06 unset($arrayM[$keyM]);  
07 }  
08 }  
09 }  
10 return $arrayM;  
11 ?>

另一种方式,利用数组索引。

PHP 是一种弱类型的语言,不像 C 语言那样有严格的变量类型限制。C 语言的数组,每一个元素的类型必须一致,而且索引都是从 0 开始。
PHP 的数组,可以用字符串作为索引,也称为关联数组。
数组索引,有一个天然的限制就是不会重复,而且访问的时候不需要查找,可以直接定位。

还是刚才的那个问题,我们采用另一种办法。

把黑名单列表的用户名组织到一个数组里,数组的索引就是用户名。

然后,遍历用户列表的时候,只需直接用 isset 查询那个用户名是否存在即可。

PHP 版代码:


01 <?php  
02 $arrayHash = array();  
03 foreach($arrayN as $nameN) {  
04 // 本行执行了 N 次。  
05 $arrayHash[$nameN] = 1;  
06 }  
07  
08 foreach($arrayM as $keyM => $nameM) {  
09 if (isset($arrayHash[$nameM])) {  
10 // 本行执行了 M 次!  
11 unset($arrayM[$keyM]);  
12 }  
13 }  
14 return $arrayM;  
15 ?>

可以看到,优化过的代码,循环次数是 M + N 次。

假如 M 和 N 都是 10000,优化前,循环了 1 亿次;优化后,只循环了 20000 次,差了 5000 倍!
如果第二个程序耗时 1 秒,则第一个程序需要将近一个半小时!

=========================================================================
hash一个貌似比较复杂的东西,实际上理解起来并不那么夸张,这里做个笔记。

hash,中文翻译成杂乱的东西,有人也叫它杂凑,或者翻译成什么都不是的音译“哈希”。

简单说来,hash就是为了把一个复杂的字串,通过一定的转换,得到一个简单的数字(通常是数字)。
如"abcd" 用各个字符的值直接相加,再取对10的余数,既(a+b+c+d)%10,来得到一个数字,比方说结果为5,那么这个5就能在一定意义上代表这个字串 abcd了。或者说这个5也可以说是这个字串的一个标记性的东西,而且是简化了的标记,所以又有人叫这个5为字串的摘要,或指纹。
这个5,有一个好的用处就是可以作为一个数组的下标来用,如我自己构造一个指针数组void* hash_array[10],那么我就可以把5那个位置上填上一个指针,如指向abcd字串。
这样的话,我如果要去查询一个字串是否存在,就不需要对一个数组使用字符串循环对比这样的慢操作,而直接先得到某个字串的hash值,再用这个hash值,在数组下标里直接找,这样速度要快上很多,特别是数据比较多的时候。

可以看到上面计算hash值时,出来的结果,可能并不是从0开始的,如我们算出的就是5。也就是说,这个5是在数组中的某个不确定的位置,或者可以叫做是一个杂凑出来的位置。其他位置可能一直就空着在。这就是这个数组或表格叫hash表的原因了。

但有个问题,上面的转换方法,直接相加,再取个余数,在字符串变为abdc时,结果得到的还是数字5。这个就是上面这个算法的一个问题了,即它不能保证一个唯一性。所以就出现了很多hash算法的研究,如MD4,MD5,SHA-1等,来保证唯一性。
但上面这个算法还是可以使用的,做法就是在abdc经过hash得到5后,去检查5是否被占用,如果占用了,那么就把数字加1,即为6,如果6没被占用,就填上值。如果后面某个字串算出一个值是6,但6已经被占用了,那么就再加1,再存。
取数据的时候,可以先算出hash值后,再看里面的内容是不是你想要的,如果不是,就加1去看,最后得到一个。

所以这里hash表的内容并不是象一般的数组最开始就组织好了的,而是后续慢慢往里增加的。
hash表里存的内容一般可以是一个指针,这个指针可以指向一个大的结构也是可以的。这个结构里可以有key, value信息。
hash表也可以不是数组,你可以把它组织成一个链表,链表里的node的结构中可以有一个参数就是那个数字的hash_value,用来快速查找用。

虽然在很多时候hash被用在加密等场合,但在一般的应用程序代码中,也可以用它来存贮简单的数据,这样代码的效率会高很多。
转载:http://hi.baidu.com/kuien_jiang/blog/item/4dbe2adcf9d9bba6cc116600.html
Loadrunner对Linux的监控点不是很多,分析起来很费力,看到不少人都提到了nmon就试用了一下,感觉还不错,就是有个缺点,与Loadrunner的场景执行时间有个时间差的问题,但是个人认为最终数据虽然会有些偏差,但是不影响性能分析,这个因素可以忽略掉
nmon用起来很简单,无需安装,解压后直接就可以使用了
一、下载
nmon下载地址:http://www-941.haw.ibm.com/collaboration/wiki/display/WikiPtype/nmon
nmon还带了个分析工具,下载地址:http://www-941.haw.ibm.com/collaboration/wiki/display/Wikiptype/nmonanalyser
二、安装
下载完成后,把压缩包解压,上传到服务器的任意目录,如/usr/local/nmon
我的服务器是Redhat server 5.3的,发现虽然没有对应的5.3的版本,下载5.2的也可以使用
三、启动
打开nmon所在的目录:cd /usr/local/nmon
修改启动文件的访问权限:chmod 755 nmon_x86_rhel52
启动nmon:./nmon_x86_rhel52
如果要采样nmon的数据保存成文件,可以
./nmon_x86_rhel52 -fT -s 30 -c 120
其中30表示每隔30秒nmon取一次系统性能数据,120表示取120次;
这样nmon将会在运行开始算起连续取得30sX120=60分钟,可根据实际需要时间调整;当运行以上命令后该目录下会生成一个.nmon文件,该文件会根据间隔时间被写入性能数据,当一段时间后再查看该文件,文件字节变大

利用nmonanalyser分析.nmon文件


当测试结束的同时ftp到服务器上将.nmon文件get下来,
打开nmon_analyser.zip 包下的nmon analyser v338.xls 文件,点击Analyse nomn data按钮,选择之前get来下的.nmon文件。
(如果报告以下宏的安全级别太高错误,则在“工具 -- 宏 --安全性”里把级别调低,然后重新打开 nmon analyser v338.xls 文件)
待分析结束后会生成性能分析结果文件(文件格式为.xls,其中包括CPU,IO,内存等性能分析报告)。
分析结果中有很多数据和图形,简要介绍主要的性能参数图像


4.1 系统汇总(对应excel标签的‘SYS_SUMM’)
蓝线为cpu占有率变化情况;
粉线为磁盘IO的变化情况;

4.2磁盘读写情况汇总(对应excel标签的‘DISK_SUMM’)
蓝色为磁盘读的速率KB/sec
紫色为磁盘写的速率KB/sec

4.3内存情况汇总(对应excel标签的‘MEM’)
曲线表示内存剩余量(MB)
分析数据得到的报告文件(.xls)中包含很多性能分析结果数据,根据自己的需要查看。


五、nmon运行本身就消耗系统资源的;
另外如果取到.nmon文件后确定不再需要nmon继续收集信息则应kill掉nmon;
命令:

ps -A | grep nmon #得到pid

kill -9 pid


suse10 enterprise sp2:

nmon_x86_rhel3

使用对应的操作系统文件:
chmod +x nmon_x86_ubuntu810
mv nmon_x86_ubuntu810 /usr/local/bin/nmon

对于 Debian 还要做以下操作(不做也同样能运行):
apt-get install lsb-release
lsb_release -d | sed 's/Description:\t//' > /etc/debian_release

然后直接运行 nmon 即可。

采集数据并生成报表:
采集数据:
nmon -s10 -c60 -f -m /home/

参数解释:
-s10 每 10 秒采集一次数据。
-c60 采集 60 次,即为采集十分钟的数据。
-f 生成的数据文件名中包含文件创建的时间。
-m 生成的数据文件的存放目录。

这样就会生成一个 nmon 文件,并每十秒更新一次,直到十分钟后。
生成的文件名如: hostname_090824_1306.nmon ,"hostname" 是这台主机的主机名。

生成报表:
下载 nmon analyser (生成性能报告的免费工具):
http://www.ibm.com/developerworks/wikis/display/Wikiptype/nmonanalyser

把之前生成的 nmon 数据文件传到 Windows 机器上,用 Excel 打开分析工具 nmon analyser v33C.xls 。点击 Excel 文件中的 "Analyze nmon data" 按钮,选择 nmon 数据文件,这样就会生成一个分析后的结果文件: hostname_090824_1306.nmon.xls ,用 Excel 打开生成的文件就可以看到结果了。

如果宏不能运行,需要做以下操作:
工具 -> 宏 -> 安全性 -> 中,然后再打开文件并允许运行宏。

自动按天采集数据:
在 crontab 中增加一条记录:
0 0 * * * root nmon -s300 -c288 -f -m /home/ > /dev/null 2>&1

300*288=86400 秒,正好是一天的数据。


采样文件越来越大:
jackxiang@172.25.39.***:~/nmon# ./nmon -s1 -c33 -f        
jackxiang@172.25.39.***:~/nmon#
jackxiang@172.25.39.***:~/nmon# du  -sh *
8.0K    AD39_***_sles10_101207_1046.nmon
160K    nmon
jackxiang@172.25.39.***:~/nmon# du  -sh *
12K     AD39_***_sles10_101207_1046.nmon
160K    nmon
jackxiang@172.25.39.***:~/nmon# du  -sh *
16K     AD39_***_sles10_101207_1046.nmon
160K    nmon
jackxiang@172.25.39.***:~/nmon# du  -sh *
20K     AD39_***_sles10_101207_1046.nmon
160K    nmon
jackxiang@172.25.39.***:~/nmon# du  -sh *
20K     AD39_***_sles10_101207_1046.nmon
160K    nmon
什么是库

库文件是一些预先编译好的函数的集合,那些函数都是按照可再使用的原则编写的。它们通常由一组互相关联的用来完成某项常见工作的函数构成,从本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。

无论在Windows平台还是在Linux平台下都存在大量的库,但由于Windows和Linux的本质不同,因此二者的库的二进制是不兼容的。

库的分类

Windows下的库有两种:静态库(.lib)和动态链接库(.dll)。
Linux下的库有两种:静态库(.a)和共享库(.so)。
Linux下的静态库的名字一般为libxxxx.a,其中xxxx是该lib的名称
Linux下的动态库的名字一般为libxxxx.so.major.minor,xxxx是该lib的名称,major是主版本号,minor是副版本号。

Windows下的库与Linux下的库的异同

Linux的共享库(.so)就象Windows的动态链接库(.dll),它里面包含有很多程序常用的函数。为了方便程序开发和减少程序的冗余,程序当中就不用包含每个常用函数的拷贝,只是在需要时调用共享库中常函数即可。这种方式我们称之为动态链接(Dynamically Linked)。而有时我们不希望叫程序去调用共享库的函数,而是把库函数代码直接链接进程序代码中,也就是说,在程序本身拥有一份共享库中函数的副本。这种方式我们称之为静态链接(Statically Linked)。

所以,简单的讲静态库和共享库(动态库)的不同点在于代码被载入的时刻不同。

静态库的代码在编译过程中已经被载入可执行程序,因此体积较大。

共享库的代码是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,因此代码体积较小。

Windows下的动态链接库(.dll)与Linux下的共享库(.so)的差别

.dll文件事实上和.exe文件一样,同属 PE 格式的执行文件。对于隐式的引用外部符号,需要把外部符号所在的位置写在PE头上。PE加载器将从PE头上找到依赖的符号表,并加载依赖的其它.dll文件。

而在Linux 上并非如此!.so文件大多为elf执行文件格式。当它们需要的外部符号,可以不写明这些符号所在的位置。也就是说,通常.so文件本身并不知道它依赖的那些符号在哪些.so里面。这些符号是由调用dlopen的进程运行时提供的。

我们在Windows下做一个.dll文件时还需要携带一个.lib文件;而在Linux下一般只需要有相应的头文件就够了。对于编写新的.so,找不到的符号可以就让它在那里,直到最终执行文件来把所有需要的符号联合到一起。windows 可以存在一个.dll对另一个.dll的隐式依赖;而Linux下一般不需要让.so和.so有隐式依赖关系。
丹麦哲学家布里丹曾写过一则寓言:有头毛驴,在干枯的草原上极为幸运地找到两堆
草,由于不知道先吃哪一堆好,结果在无限的选择和徘徊中饿死了。这被称为“布里丹效
应”。
这个寓言多年来一直是针对人类的选择而言的,即面对多种选择,人们往往无从选择。
但我现在看它,心境已完全不一样,社会发展到现在,物质生活极为丰富,人的自由度也
大了许多,已经到了可以有更多选择,追求更多选择的时代。以上面的寓言为例,在仅有
的两堆草里选,而且是在此后也不知道哪里还有草的情况下,这不叫选择,更不是我们现
在所说的更多选择。反而更像标准之选,是只能二取一的抉择,非左即右,非生即死。
什么是更多选择呢,我认为应该像大型超市,即使是最普通的商品,超市也会摆满货
架,琳琅满目,比如牛奶,有众多品牌、众多类型的口味和包装,每个人都可以根据自己
的偏好进行选择。但这种选择是建立在统一的牛奶标准之上的,因为标准统一,我们需要
考虑的只是自己的偏好,也可以在众多选择中放任自己的偏好,还可以随时改变自己的偏
好,正是在这种种偏好的满足下,我们才成就了“我们决定自己的口袋,我们决定我们的
购物篮”的“上帝”之感。假设牛奶的标准不一致,我们才真会感到无所适从。可以说,
多个标准往往会让我们无从选择,反而限制了我们选择的自由。我曾举过手机充电器的例
子,每个厂家都有自己的充电器标准,甚至每个型号都有自己的充电器标准,我们又何曾
多了更多选择。
多标准不仅会限制我们的选择,在很多时候,还可能造成极大的危害。因为多标准而
造成的教训有很多,比如:
1904 年的巴尔的摩火灾,因每个城市的水管标准都不同,所以从别的城市赶来救援的
消防队员只能望“火”兴叹,最终 80 个街区被烧为平地。
同样在美国,据说铁路规格不同是美国南部输掉美国南北战争的重要原因之一。

近期的教训也有,因为测量单位英式与公制的区别,美国航空局曾丢失了一个价值 1.25
亿美元的火星轨道飞行器。
在我国,以办公软件为例,多年来,封闭文档格式的存在严重阻碍了各中文办公软件
之间的文档互通,用户几乎是别无选择地被长期锁定在某一软件上。这不仅不利于国产软
件的发展,对于用户本身来说,长期被锁定一家软件会对文档的长期保存带来极大隐患。
正因为如此,制定统一的中文文档格式国家标准 UOF 成为我们共同的诉求。
我一直坚持这样的观点,更多的选择应建立在统一的开放的标准基础之上。

在这里,我想到近期的一个新闻热点——蓝光 DVD 和 HDDVD 的对垒。这两种格式
的 DVD 厚度不同,互不兼容,统一的标准一直难以出现,市场和用户都出现观望态势,
两者的推广之路都受到标准不统一的阻碍。目前,这种状况有了突破,华纳兄弟宣布放弃
HDDVD转而支持蓝光 DVD,使蓝光阵营进一步壮大,舆论一致认为 HDDVD格式处于劣
势,占据上风的蓝光有望成为新一代 DVD 标准。但也有意见指出,电子市场变化迅猛,
如果标准的市场化不紧跟上,即使成为统一标准,也面临严峻挑战。多年受困于标准之乱
的 DVD行业,可能已经错过了他们最好的发展时期,借标准一统天下的目标或许能实现,
但天下已经不是从前的天下了,近几年崛起的视频网络的发展已经改变众多消费者的观影
习惯,对于 DVD的发展可以说是雪上加霜。
与 DVD 标准情况相似,标准推广和市场化的时机极为重要。UOF 出台后,惟有真正
应用起来,推广开去,才能发挥其作用。目前正值微软技术转型,用户的使用习惯经历巨
变,需要重新建立,这将为国产软件的发展创造良好的机遇。可以说,这一机遇的把握与
否将直接关乎国产软件乃至我国信息产业的发展成败
1.此刻打盹,你将做梦;而此刻学习,你将圆梦。
2.我荒废的今日,正是昨日殒身之人祈求的明日。
3.觉得为时已晚的时候,恰恰是最早的时候。
4.勿将今日之事拖到明日。
5.学习时的苦痛是暂时的,未学到的痛苦是终生的。
6.学习这件事,不是缺乏时间,而是缺乏努力。
7.幸福或许不排名次,但成功必排名次。
8.学习并不是人生的全部。但既然连人生的一部分——学习也无法征服,还能做什么呢?
9.请享受无法回避的痛苦。
10.只有比别人更早、更勤奋地努力,才能尝到成功的滋味。
11.谁也不能随随便便成功,它来自彻底的自我管理和毅力。
12.时间在流逝。
13.现在流的口水,将成为明天的眼泪。
14.狗一样地学,绅士一样地玩。
15.今天不走,明天要跑。
16.投资未来的人,是忠于现实的人。
17.受教育程度代表收入。
18.一天过完,不会再来。
19.即使现在,对手也不停地翻动书页。
20.没有艰辛,便无所获。
[1]好好规划自己的路,不要跟着感觉走!根据个人的理想决策安排,绝大部分人并不指望成为什么院士或教授,而是希望活得滋润一些,爽一些。那么,就需要慎重安排自己的轨迹。从哪个行业入手,逐渐对该行业深入了解,不要频繁跳槽,特别是不要为了一点工资而转移阵地,从长远看,这点钱根本不算什么,当你对一个行业有那么几年的体会,以后钱根本不是问题。频繁地动荡不是上策,最后你对哪个行业都没有摸透,永远是新手!
[2]可以做技术,切不可沉湎于技术。千万不可一门心思钻研技术!给自己很大压力,如果你的心思全部放在这上面,那么注定你将成为孔乙己一类的人物!适可而止,因为技术只不过是你今后前途的支柱之一,而且还不是最大的支柱,除非你只愿意到老还是个注册安全工程师!

[3]不要去做技术高手,只去做综合素质高手!在企业里混,我们时常瞧不起某人,说他“什么都不懂,凭啥拿那么多钱,凭啥升官!”这是普遍的典型的注册安全工程师的迂腐之言。某某人很牛吗?人家能上去必然有他的本事,而且是你没有的本事。你想想,老板搞经营那么多年,难道见识不如你这个新兵?人家或许善于管理,善于领会老板意图,善于部门协调等等。因此务必培养自己多方面的能力,包括管理,亲和力,察言观色能力,攻关能力等,要成为综合素质的高手,则前途无量,否则只能躲在角落看显示器!技术以外的技能才是更重要的本事!!从古到今,美国、日本,一律如此!

[4]多交社会三教九流的朋友!不要只和注册安全工程师交往,认为有共同语言,其实更重要的是和其他类人物交往,如果你希望有朝一日当老板或高层管理,那么你整日面对的就是这些人。了解他们的经历,思维习惯,爱好,学习他们处理问题的模式,了解社会各个角落的现象和问题,这是以后发展的巨大的本钱,没有这些以后就会笨手笨脚,跌跌撞撞,遇到重重困难,交不少学费,成功的概率大大降低!

[5]知识涉猎不一定专,但一定要广!多看看其他方面的书,金融,财会,进出口,税务,法律等等,为以后做一些积累,以后的用处会更大!会少交许多学费!

[6]抓住时机向技术管理或市场销售方面的转变!要想有前途就不能一直搞技术,适当时候要转变为管理或销售,前途会更大,以前搞技术也没有白搞,以后还用得着。搞管理可以培养自己的领导能力,搞销售可以培养自己的市场概念和思维,同时为自己以后发展积累庞大的人脉!应该说这才是前途的真正支柱!!!

[7]逐渐克服自己的心里弱点和性格缺陷!多疑,敏感,天真(贬义,并不可爱),犹豫不决,胆怯,多虑,脸皮太薄,心不够黑,教条式思维。。。这些注册安全工程师普遍存在的性格弱点必须改变!很难吗?只在床上想一想当然不可能,去帮朋友守一个月地摊,包准有效果,去实践,而不要只想!不克服这些缺点,一切不可能,甚至连项目经理都当不好--尽管你可能技术不错!

[8]工作的同时要为以后做准备!建立自己的工作环境!及早为自己配置一个工作环境,一方面接触市场,培养市场感觉,同时也积累资金,更重要的是准备自己的产品,咱搞技术的没有钱,只有技术,技术的代表不是学历和证书,而是产品,拿出象样的产品,就可技术转让或与人合作搞企业!先把东西准备好,等待机会,否则,有了机会也抓不住!

[9]要学会善于推销自己!不仅要能干,还要能说,能写,善于利用一切机会推销自己,树立自己的品牌形象,很必要!要创造条件让别人了解自己,不然老板怎么知道你能干?外面的投资人怎么相信你?提早把自己推销出去,机会自然会来找你!搞个个人主页是个好注意!!特别是培养自己在行业的名气,有了名气,高薪机会自不在话下,更重要的是有合作的机会...

[10]该出手时便出手!永远不可能有100%把握!!!条件差不多就要大胆去干,去闯出自己的事业,不要犹豫,不要彷徨,干了不一定成功,但至少为下一次冲击积累了经验,不干永远没出息,而且要干成必然要经历失败。不经历风雨,怎么见彩虹,没有人能随随便便成功!

TCP握手协议

WEB2.0 jackxiang 2010-10-25 18:50
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状态,完成三次握手。
  完成三次握手,客户端与服务器开始传送数据,在上述过程中,还有一些重要的概念:
  未连接队列:在三次握手协议中,服务器维护一个未连接队列,该队列为每个客户端的SYN包(syn=j)开设一个条目,该条目表明服务器已收到SYN包,并向客户发出确认,正在等待客户的确认包。这些条目所标识的连接在服务器处于Syn_RECV状态,当服务器收到客户的确认包时,删除该条目,服务器进入 ESTABLISHED状态。
  Backlog参数:表示未连接队列的最大容纳数目。
  SYN-ACK 重传次数服务器发送完SYN-ACK包,如果未收到客户确认包,服务器进行首次重传,等待一段时间仍未收到客户确认包,进行第二次重传,如果重传次数超过系统规定的最大重传次数,系统将该连接信息从半连接队列中删除。注意,每次重传等待的时间不一定相同。
  半连接存活时间:是指半连接队列的条目存活的最长时间,也即服务从收到SYN包到确认这个报文无效的最长时间,该时间值是所有重传请求包的最长等待时间总和。有时我们也称半连接存活时间为Timeout时间、SYN_RECV存活时间。

  syn_send         a   syn=j       ---> b
         a   syn=k ack=j+1
  ESTABLISHED      a   ack=k+1     --->b        ESTABLISHED

TCP连接的建立与中止
1.连接的建立
  在建立连接的时候,客户端首先向服务器申请打开某一个端口(用SYN段等于1的TCP报文),然后服务器端发回一个ACK报文通知客户端请求报文收到,客户端收到确认报文以后再次发出确认报文确认刚才服务器端发出的确认报文(绕口么),至此,连接的建立完成。这就叫做三次握手。如果打算让双方都做好准备的话,一定要发送三次报文,而且只需要三次报文就可以了。
  可以想见,如果再加上TCP的超时重传机制,那么TCP就完全可以保证一个数据包被送到目的地。
2.结束连接
  TCP 有一个特别的概念叫做half-close,这个概念是说,TCP的连接是全双工(可以同时发送和接收)连接,因此在关闭连接的时候,必须关闭传和送两个方向上的连接。客户机给服务器一个FIN为1的TCP报文,然后服务器返回给客户端一个确认ACK报文,并且发送一个FIN报文,当客户机回复ACK报文后(四次握手),连接就结束了。
3.最大报文长度
  在建立连接的时候,通信的双方要互相确认对方的最大报文长度(MSS),以便通信。一般这个SYN长度是MTU减去固定IP首部和TCP首部长度。对于一个以太网,一般可以达到1460字节。当然如果对于非本地的IP,这个MSS可能就只有536字节,而且,如果中间的传输网络的MSS更佳的小的话,这个值还会变得更小。
4.TCP的状态迁移图(如下:)

点击在新窗口中浏览此图片


  说明: ---->实线箭头说明客户的正常状态变迁
        ---->虚线箭头说明服务器的正常状态变迁
        应用进程:说明当应用执行某种操作时发生的状态变迁
        收:说明当收到TCP报文段时状态的变迁
        发:说明为了进行某个状态变迁要发送的TCP报文段

  状态迁移图,包含了两个部分---服务器的状态迁移和客户端的状态迁移,如果从某一个角度出发来看这个图,就会清晰许多,这里面的服务器和客户端都不是绝对的,发送数据的就是客户端,接受数据的就是服务器。
  4.1.客户端应用程序的状态迁移图
    客户端的状态可以用如下的流程来表示:
    CLOSED->SYN_SENT->ESTABLISHED->FIN_WAIT_1->FIN_WAIT_2->TIME_WAIT->CLOSED
    以上流程是在程序正常的情况下应该有的流程,从图中可以看到,在建立连接时,当客户端收到SYN报文的ACK以后,客户端就打开了数据交互地连接。而结束连接则通常是客户端主动结束的,客户端结束应用程序以后,需要经历FIN_WAIT_1,FIN_WAIT_2等状态,这些状态的迁移就是前面提到的结束连接的四次握手。
  4.2.服务器的状态迁移图
    服务器的状态可以用如下的流程来表示:
    CLOSED->LISTEN->SYN收到->ESTABLISHED->CLOSE_WAIT->LAST_ACK->CLOSED
    在建立连接的时候,服务器端是在第三次握手之后才进入数据交互状态,而关闭连接则是在关闭连接的第二次握手以后(注意不是第四次)。而关闭以后还要等待客户端给出最后的ACK包才能进入初始的状态。
  4.3.其他状态迁移
    图还有一些其他的状态迁移,这些状态迁移针对服务器和客户端两方面的总结如下
    LISTEN->SYN_SENT,对于这个解释就很简单了,服务器有时候也要打开连接的嘛。
    SYN_SENT->SYN收到,服务器和客户端在SYN_SENT状态下如果收到SYN数据报,则都需要发送SYN的ACK数据报并把自己的状态调整到SYN收到状态,准备进入ESTABLISHED
    SYN_SENT->CLOSED,在发送超时的情况下,会返回到CLOSED状态。
    SYN_收到->LISTEN,如果受到RST包,会返回到LISTEN状态。
    SYN_收到->FIN_WAIT_1,这个迁移是说,可以不用到ESTABLISHED状态,而可以直接跳转到FIN_WAIT_1状态并等待关闭。
  4.4.2MSL等待状态
    图里面,有一个TIME_WAIT等待状态,这个状态又叫做2MSL状态,说的是在TIME_WAIT2发送了最后一个ACK数据报以后,要进入 TIME_WAIT状态,这个状态是防止最后一次握手的数据报没有传送到对方那里而准备的(注意这不是四次握手,这是第四次握手的保险状态)。这个状态在很大程度上保证了双方都可以正常结束,但是,问题也来了。
    由于插口的2MSL状态(插口是IP和端口对的意思,socket),使得应用程序在 2MSL时间内是无法再次使用同一个插口的,对于客户程序还好一些,但是对于服务程序,例如httpd,它总是要使用同一个端口来进行服务,而在2MSL时间内,启动httpd就会出现错误(插口被使用)。为了避免这个错误,服务器给出了一个平静时间的概念,这是说在2MSL时间内,虽然可以重新启动服务器,但是这个服务器还是要平静的等待2MSL时间的过去才能进行下一次连接。
  4.5.FIN_WAIT_2状态
    这就是著名的半关闭的状态了,这是在关闭连接时,客户端和服务器两次握手之后的状态。在这个状态下,应用程序还有接受数据的能力,但是已经无法发送数据,但是也有一种可能是,客户端一直处于FIN_WAIT_2状态,而服务器则一直处于WAIT_CLOSE状态,而直到应用层来决定关闭这个状态。
5.RST,同时打开和同时关闭
  RST是另一种关闭连接的方式,应用程序应该可以判断RST包的真实性,即是否为异常中止。而同时打开和同时关闭则是两种特殊的TCP状态,发生的概率很小。
6.TCP服务器设计
  UDP的服务器完全不需要所谓的并发机制,它只要建立一个数据输入队列就可以。但是TCP不同,TCP服务器对于每一个连接都需要建立一个独立的进程(或者是轻量级的,线程),来保证对话的独立性。所以TCP服务器是并发的。而且TCP还需要配备一个呼入连接请求队列(UDP服务器也同样不需要),来为每一个连接请求建立对话进程,这也就是为什么各种TCP服务器都有一个最大连接数的原因。而根据源主机的IP和端口号码,服务器可以很轻松的区别出不同的会话,来进行数据的分发。

三次握手:
  1:服务器必须准备好接受外来的连接,这通过调用socket,bind,和listen函数来完成,称为被动打开
  2:客户通过调用connect 进行主动打开,这引起客户TCP发送一个SYN分节。一般情况下,SYN分节不携带数据,它只含有一个IP头部,一个TCP头部,及可能的TCP选项。
  3:服务器必须确认客户的SYN,同时自己也得发送一个SYN分节,包含同一连接中发送数据的一个系列号,服务器以单个分节向客户发送SYN和对客户SYN的ACK.
  4:客户确认ACK.
分页: 156/339 第一页 上页 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 下页 最后页 [ 显示模式: 摘要 | 列表 ]