Why https?
- 保证用户信息的传输安全。包括用户名、密码、cookie、用户保存的服务器端信息等等
- 很大程度上免遭DNS劫持
Why not https?
- 更多的cpu资源的消耗
- 证书校验的时间消耗
- 证书校验可能因一些问题导致验证失败
DevOps
java线程管理是JVM的一部分,虽然大部分JVM直接映射java线程到底层系统线程,但是还是java的线程管理决定谁有机会运行
|
1 |
The thread scheduler is the part of the JVM (although most JVMs map Java threads directly to native threads on the underlying OS) that decides which thread should run at any given moment, and also takes threads out of the run state. Assuming a single processor machine, only one thread can actually run at a time. Only one stack can ever be executing at one time. And it's the thread scheduler that decides which thread—of all that are eligible—will actually run. |
1. Java线程学习和总结: http://blog.csdn.net/fantian830211/article/details/784597
1. 安装tomcat
http://tomcat.apache.org/download-70.cgi
2. 安装eclipse的tomcat插件
http://www.eclipsetotale.com/tomcatPlugin.html
3. Servlet总结
http://www.iteye.com/topic/766418 Servlet的一些基本概念
http://www.iteye.com/topic/80171 从Servlet的各个部件、功能、框架方面介绍的深入浅出,需要看看
http://www.iteye.com/topic/952866 主要介绍了Servlet的生命周期
http://www.cnblogs.com/qingblog/archive/2012/08/10/2632099.html
http://www.eoeandroid.com/thread-83566-1-1.html
http://blog.chinaunix.net/uid-9688646-id-1998387.html
http://blog.csdn.net/stonecao/article/details/6417364
使用php的file_get_contents(…) 函数从广州发送一个http请求到北京,该请求的请求头和响应头如下:
|
1 2 3 4 5 6 7 8 9 10 |
GET / HTTP/1.1 Host: phpor.net HTTP/1.1 200 OK Date: Fri, 11 Jan 2013 11:11:19 GMT Server: Apache Content-Length: 5 Connection: close hello |
现在,从广州到北京的一次数据的往返时间(就是ping的时间)为34ms,请求的执行时间为6ms; 因为请求头和相应头都非常小,分别一次tcp数据包就够,这样的话,一次http请求时间为: 34 + 34 + 6 = 74ms , 而实际却稳定在108ms左右,还有大约34ms不知去向
根据这个丢失的时间长度来看,大概是多了一次数据的发送和接收; 通过tcpdump抓包发现如下现象:
file_get_contents(…)中实现的http请求,首先把请求行发送出去,收到请求行数据包的ack包后继续发送后续的请求头; 这样的话就凭空多出一次网络时间,其各种原因,有时间再看看PHP源码中为何如此实现吧。
测试了一下curl,没有这个问题。
看了一下如下脚本:
|
1 2 |
$ strace -T -e network php a.php socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP) = -1 EAFNOSUPPORT (Address family not supported by protocol) <0.005651> |
一次IPv6支持的检测需要5ms+的时间,成本是比较大的,但是,同一个进程中只检测一次,所以对于httpd进程来讲,这个是没有问题的
这是一个可好的东西了,怎么个好法呢。。。
http://www.percona.com/docs/wiki/tcprstat:start
火狐浏览器下,父框架是GBK编码,子框架是utf8编码,这时,子框架中提交表单时,提交的编码为GBK编码;如果把子框架拿出来,然后提交表单,就是utf8编码了
1. 通过对链路层的抓包,了解网络结构及网关、路由的概念
10.49.4.65 和 10.49.4.64为同一个网段
1. 在10.49.4.65上抓包
2. 从10.49.4.65上ping 10.4.4.64
|
1 2 3 4 5 6 7 8 9 10 11 |
# tcpdump -i eth1 -e -nn host 10.49.4.64 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth1, link-type EN10MB (Ethernet), capture size 96 bytes 17:54:36.804406 00:13:72:65:65:e1 > 00:19:a9:3b:ec:00, ethertype IPv4 (0x0800), length 98: 10.49.4.65 > 10.49.4.64: ICMP echo request, id 35935, seq 1, length 64 17:54:36.805908 00:18:8b:2d:ef:79 > ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806), length 60: arp who-has 10.49.4.65 tell 10.49.4.64 17:54:36.805927 00:13:72:65:65:e1 > 00:18:8b:2d:ef:79, ethertype ARP (0x0806), length 42: arp reply 10.49.4.65 is-at 00:13:72:65:65:e1 17:54:36.806013 00:18:8b:2d:ef:79 > 00:13:72:65:65:e1, ethertype IPv4 (0x0800), length 98: 10.49.4.64 > 10.49.4.65: ICMP echo reply, id 35935, seq 1, length 64 17:54:37.804893 00:13:72:65:65:e1 > 00:19:a9:3b:ec:00, ethertype IPv4 (0x0800), length 98: 10.49.4.65 > 10.49.4.64: ICMP echo request, id 35935, seq 2, length 64 17:54:37.805035 00:18:8b:2d:ef:79 > 00:13:72:65:65:e1, ethertype IPv4 (0x0800), length 98: 10.49.4.64 > 10.49.4.65: ICMP echo reply, id 35935, seq 2, length 64 17:54:38.805104 00:13:72:65:65:e1 > 00:19:a9:3b:ec:00, ethertype IPv4 (0x0800), length 98: 10.49.4.65 > 10.49.4.64: ICMP echo request, id 35935, seq 3, length 64 17:54:38.805209 00:18:8b:2d:ef:79 > 00:13:72:65:65:e1, ethertype IPv4 (0x0800), length 98: 10.49.4.64 > 10.49.4.65: ICMP echo reply, id 35935, seq 3, length 64 |
1. 第一个数据包,数据首先从10.49.4.65发送给网关; 因为路由表中有如下设置(大写G标志为经过网关):
|
1 |
10.49.0.0 10.49.1.1 255.255.0.0 UG 0 0 0 eth1 |
(没有更精确匹配 10.49.4.64的路由了)
2. 10.49.4.64 上有如下路由配置(没有大写G,说明不需要经过网关):
|
1 |
10.49.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth1 |
(没有更精确匹配 10.49.4.65的路由了)
所以10.49.4.64可以直接回包给10.49.4.65; 但是10.49.4.64不知道10.49.4.65的mac地址是多少,于是先发了一个广播(第二个数据包,arp类型的),询问了一下; 10.49.4.65 回复了10.49.4.64的询问(第三个数据包,arp类型的),然后10.49.4.64就给出了icmp的响应包(第四个数据包)
1. 添加一条路由,网关和接口至少指定一个
2. 只有同一个局域网下,才可以不经过网关(网关基本是有至少两块网卡的,用来连接不同的网络)
3. 指定网关的时候一般不需要同时指定接口
1. 经过网关
|
1 |
/sbin/route add -host 10.49.4.64 gw 10.49.1.1 |
2. 不经过网关
|
1 |
/sbin/route add -host 10.49.4.64 eth1 |
转自:http://blog.csdn.net/sherlockhua/article/details/5365873
在上一篇关于如何将套接口绑定到网络接口上的文章中,我曾经以为采用 SO_DONTROUTE 套接口选项能够实现和SO_BINDTODEVICE 选项同样的功能。但是实践证明不是这样。那么,其原因到底是为什么呢? SO_DONTROUTE 套接口选项真正的作用是什么呢?本文将对此予以解答。
在 socket(7) 中对 SO_DONTROUTE 选项的说明如下:
SO_DONTROUTE
Don’t send via a gateway, only send to directly connected hosts.
The same effect can be achieved by setting the MSG_DONTROUTE
flag on a socket send(2) operation. Expects an integer boolean
flag.
这段话的核心意思是 SO_DONTROUTE 选项将导致数据包不经由网关发送,而是发往直接相连的主机。该套接口选项合法的值是整数形式的布尔标志值。
上述说明看起来似乎很明了,但是我 google 到的一些资料又说这个套接口选项将会绕过( bypass )路由表发送数据包,而且连 W. Richard Stevens 也是这样说的:“此选项规定发出的分组将旁路底层协议的正常路由机制。例如,对于 IPv4,分组被指向适当的本地接口,也就是目的地址的网络和子网部分所确定的本地接口。如果本地接口不能由目的地址确定(例如,目的主机不再一个点对点链路的另一端上,也不在一个共享网络上),则返回 ENETUNREACH 错误。……此选项经常由路由守护进程( routed 和 gated )用来旁路路由表(路由表不正确的情况下),强制一个分组从某个特定接口发出。” [UNIX 网络编程(第 1 卷),清华大学出版社,第 157 页 ] 。我不得不承认,正是这里的最后一句话,直接导致我认为可以通过 SO_DONTROUTE 套接口选项完成和 SO_BINDTODEVICE 同样的功能。但是实际上却并不是这样的。
为了解决这个问题,我编写了一个测试程序 udpsend2.c 。该程序要求要有三个参数,其中,第二个参数是数据包目的地的 IP 地址,第三个参数是一个开关,当为 on 时开启 SO_DONTROUTE 选项,当为 off 时关闭 SO_DONTROUTE 选项,默认情况下该选项是打开的。如果您理解该程序有困难,请先阅读《 UNIX 网络编程(第 1 卷)》。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
/* * $file: udpsend2.c * $func: test SO_DONTROUTE socket option, * sending UDP packets. * $author: rockins * $email: ybc2084@163.com * $date: Sat Jan 20 16:38:23 CST 2007 * $all copyleft, say, completely free */ #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <net/if.h> #include <unistd.h> #include <signal.h> #define BUFF_SIZE 512 /*data buffer size*/ #define REMOTE_PORT 9999 /*remote port, not important*/ signed int len = 0; /*sending bytes in once time*/ int main(int argc, char *argv[]) { int sock; struct sockaddr_in remote_addr; int dontroute = 1; unsigned char buff[BUFF_SIZE]; int i; /*check arguments*/ if (argc != 3) { printf("usage: a.out <REMOTE_IP> [on | off]/n" "default is switch on SO_DONTROUTE option/n"); exit(-1); } /*determine switch SO_DONTROUTE or not*/ if (!strcmp(argv[2], "on")) dontroute = 1; else if (!strcmp(argv[2], "off")) dontroute = 0; /*stuff buffer*/ for (i = 0; i < BUFF_SIZE; i++) { buff[i] = 'X'; } /*create socket*/ if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("socket()"); exit(-1); } /*set SO_DONTROUTE option*/ if (setsockopt(sock, SOL_SOCKET, SO_DONTROUTE, &dontroute, sizeof(dontroute)) < 0) { perror("setsockopt()"); exit(-1); } /*remote address structure*/ memset(&remote_addr, 0, sizeof(struct sockaddr_in)); remote_addr.sin_family = AF_INET; remote_addr.sin_port = htons(REMOTE_PORT); remote_addr.sin_addr.s_addr = inet_addr(argv[1]); /*data sending process*/ len = sendto(sock, buff, BUFF_SIZE, 0, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr_in)); if (len < 0) { perror("sendto()"); exit(-1); } printf("send %d to remote end.../n", len); return (0); } |
如下编译程序:
[root@cyc src]# gcc -g -o udpsend2 udpsend2.c
首先介绍一下初始时刻测试环境的设置情况,如下所示:
[root@cyc src]# uname -a
Linux cyc 2.4.20-8 #4 Sat Jan 20 19:42:09 CST 2007 i686 i686 i386 GNU/Linux
[root@cyc src]# ifconfig
eth0 Link encap:Ethernet HWaddr 00:0D:87:EA:E3:AF
inet addr:202.115.26.224 Bcast:202.115.26.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:40016 errors:0 dropped:0 overruns:0 frame:0
TX packets:85327 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
RX bytes:3063524 (2.9 Mb) TX bytes:36469606 (34.7 Mb)
Interrupt:11 Base address:0xc000
[root@cyc src]# route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
202.115.26.0 * 255.255.255.0 U 0 0 0 eth0
default 202.115.26.1 0.0.0.0 UG 0 0 0 eth0
这里,作者所在的子网为 202.115.26.0/24 ,默认网关为 202.115.26.1 ,用于发送数据包的主机为 202.115.26.224 。用于接收数据的两台远端主机的 IP 地址分别为 202.115.26.193 和 202.112.14.184 。 202.115.26.193 与发送主机 202.115.26.224 位于同一网段内,通过交换机相连;而 202.112.14.184 则与发送主机 202.115.26.224 之间没有直接相连,中间通过多个路由器连接。连接示意图如下所示:
首先测试的是 202.115.26.193 。路由表设置如下所示:
[root@cyc src]# route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
202.115.26.0 * 255.255.255.0 U 0 0 0 eth0
default 202.115.26.1 0.0.0.0 UG 0 0 0 eth0
如下启动程序:
[root@cyc src]# ./udpsend2 202.115.26.193 on
send 512 to remote end…
程序报告发送了 512 字节的数据给 202.115.26.193 ,尽管对方并没有真正接收数据包。如我们所知, UDP 是无连接的,它只负责将数据包发出去,至于对方有没有接收到, UDP 是不管的。
接下来,去掉路由表中的默认路由:
[root@cyc src]# route del default
[root@cyc src]# route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
202.115.26.0 * 255.255.255.0 U 0 0 0 eth0
再次运行 udpsend2 ,结果如下:
[root@cyc src]# ./udpsend2 202.115.26.193 on
send 512 to remote end…
结论:当目的主机与发送主机处于同一个网段内时,无论内核是否设置了默认路由,数据包总能发送给目的主机(尽管目的主机可能并没有在等待接收数据包)。但是,子网必须要在路由表中。比如,如果上面将子网 202.115.26.0 所在的路由表项也删除的话,就会得到网络不可达的结果,这一点是很容易理解的。
其次来测试当发送主机与目的主机位于不同网段时的情况,此时的目的主机为 202.112.14.184 。发送主机上的路由表设置如下,并且发送主机能够 ping 通目的主机。这表明虽然 202.112.14.184 与 202.115.26.224 之间虽然并没有直接相连,但是能够通过路由器转发数据包来完成通信:
[root@cyc src]# route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
202.115.26.0 * 255.255.255.0 U 0 0 0 eth0
default 202.115.26.1 0.0.0.0 UG 0 0 0 eth0
[root@cyc src]# ping 202.112.14.181
PING 202.112.14.181 (202.112.14.181) 56(84) bytes of data.
64 bytes from 202.112.14.181: icmp_seq=1 ttl=125 time=0.364 ms
运行程序 udpsend2 ,结果显示如下:
[root@cyc src]# ./udpsend2 202.112.14.181 on
sendto(): Network is unreachable
将默认路由(也即网关地址)从路由表中删除,再次运行程序:
[root@cyc src]# ./udpsend2 202.112.14.181 on
sendto(): Network is unreachable
结论:无论路由表中是否包含了默认路由(也即网关地址),当两主机之间没有直接相连时(即使能够通过中间路由器通信),设置了 SO_DONTROUTE 也将导致网络不可达错误。而网络不可达错误通常程序中有函数返回 ENETUNREACH 的结果。在本例中, ENETUNREACH 错误是由 sendto() 函数引发的。
根据上面的测试结果,我认为: SO_DONTROUTE 套接口选项并没有完全绕过路由表,而只是绕过了路由表中网关(或者说默认路由)所在的表项。因此, Linux 的 socket(7) 中的说明是正确并且无歧义的,而《 UNIX 网络编程(第 1卷)》中的说法则带有一定的歧义性,容易给人造成误解。当然,这也可能是译者翻译不准确的缘故。总的来讲,当目的主机与发送方直接相连时,可以通过 SO_DONTROUTE 来实现从指定的网络接口发出数据包。但是,当接受者与发送方并没有直接相连时,就不能这样做了。而需要考虑通过 SO_BINDTODEVICE 选项或者 RAW 套接口或者 PACKET 套接口来实现。(注: RAW 套接口能实现网络层的直接数据访问,而 PACKET 套接口则能实现链路层的直接数据访问)。
相关参考: http://blog.csdn.net/namelcx/article/details/8063543