pcntl_signal 的第三个参数

缘起

当给进程安装一个信号处理程序,如果一个进程在执行一个系统调用的时候,突然收到一个信号,然后转到信号处理程序,当执行完信号处理程序后,系统调用会继续进行吗?

解答

不管在C还是其他语言,都有一个可选的方式,比如在PHP中,pcntl_signal有第三个参数(默认为true),可以继续未完成的系统调用(默认),也可以让系统调用返回失败(第三个参数设置为false);

这在有些时候是需要关心的,比如,fpm在退出的时候,先发送一个信号到每个子进程,子进程收到信号后不是立即死掉,而是先关闭输入,停止accept,然后设置 in_shutdown = 1; 然后信号处理例程执行完毕,返回继续原来的工作(如果原来在执行系统调用,则返回原来的系统调用),执行完一次请求后发现in_shutdown==1 则执行退出

putenv/getenv/$_ENV/phpinfo(INFO_ENVIRONMENT)

putenv/getenv, $_ENV, and phpinfo(INFO_ENVIRONMENT) are three completely distinct environment stores. doing putenv(“x=y”) does not affect $_ENV; but also doing $_ENV[“x”]=”y” likewise does not affect getenv(“x”). And neither affect what is returned in phpinfo().

putenv(); Adds setting to the server environment. The environment variable will only exist for the duration of the current request. At the end of the request the environment is restored to its original state.

Assuming the USER environment variable is defined as “dave” before running the following:

 

prints:

env is: dave
(doing: putenv fred)
env is: dave
getenv is: fred
(doing: set _env barney)
getenv is: fred
env is: barney
phpinfo()

Environment

Variable => Value

USER => dave

Response与Transfer-Encoding:chunked、Content-Length、Content-Encoding:gzip

缘起

了解HTTP 1.1和HTTP1.0的区别的同学都知道,Transfer-Encoding:chunked , Connection:keep-alive 都是HTTP 1.1的新特性;

Connection:keep-alive 使得一次连接可以干多次HTTP请求的活儿,而HTTP1.0协议每次tcp连接只能处理一个HTTP请求;

另外,对于HTTP 1.0来讲,如果一次HTTP的响应内容很多,而且又无法提前预知内容的多少,那么就不使用content-length ,输出完成后,直接关闭连接即可,一定程度上来讲,content-length对于HTTP 1.0来讲,是可有可无的;

而对于HTTP1.1 来讲,如果 connection: keep-alive ,而且又不能提前预知内容多少的话,该怎么办呢? 这就是为什么要有Transfer-Encoding:chunked 的原因了。

有了这些知识之后,我们再来看一种现象,为什么同样是HTTP1.1 ,有的请求就使用的是 content-length ,而又的请求就使用的Transfer-Encoding:chunked 呢? 需要什么特殊的设置吗?

可能请求输出的内容并不多,比如就10行,但是每行内容需要5s钟的时间来生成,如果能分块儿输出,是不是用户体验会好一些?那么又如何分块儿输出呢?

从协议上来讲,如果输出中有 content-length 则显然不是分块儿输出的,如果是Transfer-Encoding:chunked 则可能是分块儿输出的。

 

查资料:

一般服务器采用 Transfer-Encoding:chunked 有两种情况:

1. 应用程序已经输出给webserver很多内容(就是webserver的buffer满了),但是还是没有要结束的意思(就是还没输出完),则webserver放弃输出content-length,如果是HTTP1.0 ,则直接输出内容(输出完关闭连接就ok了);如果是HTTP1.1,则采用Transfer-Encoding:chunked 的方式输出。

2. 应用程序主动flush内容到客户端,如果是PHP,为: ob_flush(); flush(); (参看: http://php.net/flush )

 

所以: 对于页面服务,如果要输出的内容很多,可以生成一部分就flush一部分,让浏览器尽快渲染给用户,给用户一个更好的使用体验。

Content-Encoding:gzip

gzip是内容编码,是否压缩; 压缩式在传输之前进行的,所以传输的分块儿是按照压缩后的数据分块儿的(似乎有点儿废话了)

Nginx中如果启用了gzip压缩,则必然采用Transfer-Encoding:chunked 的方式输出,原因如下:

Nginx中Gzip模块和r->headers_out.content_length_n

r->headers_out.content_length_n :这个在Nginx内部用于表述请求返回内容的长度。但注意这不是完全相等的,只有在 r->headers_out.content_length_n >=0的时候,才有意义。比如说,通常后端的upstream(比如说PHP),如果没有在脚本中强制header输出content-length,则默认在nginx中 r->headers_out.content_length_n = -1。

Gzip模块也是一个典型的Filter模块。这里简单介绍下,后续可以详细描述。在header filter中会直接清空 r->headers_out.content_length_n和header中输出的content_length。为什么要清空呢?主要是因为gzip要对内容模块进行压缩处理,而在header filter的时候,gzip模块不可能计算出压缩后的内容长度(原因是在nginx中,header 输出和body的输出是完全两个不同的阶段),所以最好的办法就是在清空header中的content-length。这样结合之前的介绍的chunked模块,可以看出:在nginx中,如果采用gzip,如果是keep alive,则必然是chunked模式。

 

参考资料:

http://blog.xiuwz.com/tag/content-length/

http://lokki.iteye.com/blog/1072327

http://www.cnblogs.com/foxhengxing/archive/2011/12/02/2272387.html

 

 

测一下tcp的读写buffer有多大

测试办法:

1. 使用nc做一个server

nc -l localhost 8181

CTRL-Z

2. 使用nc做client

nc localhost 8181 </dev/zero

3. netstat -an |grep 8181

171008 就是读buffer的大小(约160KB), 1279872就是写buffer的大小(约1.2MB)

现在nc client被write给阻塞住了,如果nc client之发送小于 171008 + 1279872 的数据,则现在已经兴高采烈地quit了,然而,server端却连1个字节都没处理呢,如果在把server给杀掉,则这些数据就都算丢弃了。

 

 

linux网络编程之shutdown() 与 close()

引言

1. tcp是有read buffer和write buffer的,如何才能确保数据不会死在buffer里,虽然tcp是面向连接的可靠的协议,但是tcp没有可靠到这等程度,有些事情还是需要考应用层来保证的

 

正文

关于shutdown和close的一些说明:

1. 如果有多个进程共享一个套接字,close每被调用一次,计数减1,直到计数为0时,也就是所用进程都调用了close,套接字将被释放。
2. 在多进程中如果一个进程中shutdown(sfd, SHUT_RDWR)后其它的进程将无法进行通信. 如果一个进程close(sfd)将不会影响到其它进程. 得自己理解引用计数的用法了. 有Kernel编程知识的更好理解了.
3. 只要TCP栈的读缓冲里还有未读取(read)数据,则调用close时会直接向对端发送RST。
4. shutdown与socket描述符没有关系,即使调用shutdown(fd, SHUT_RDWR)也不会关闭fd,最终还需close(fd)。
5. 可以认为shutdown(fd, SHUT_RD)是空操作,因为shutdown后还可以继续从该socket读取数据,这点也许还需要进一步证实。
6. 在已发送FIN包后write该socket描述符会引发EPIPE/SIGPIPE。
7. 当有多个socket描述符指向同一socket对象时,调用close时首先会递减该对象的引用计数,计数为0时才会发送FIN包结束TCP连接。shutdown不同,只要以SHUT_WR/SHUT_RDWR方式调用即发送FIN包。
8. SO_LINGER与close,当SO_LINGER选项开启但超时值为0时,调用close直接发送RST(这样可以避免进入TIME_WAIT状态,但破坏了TCP协议的正常工作方式),SO_LINGER对shutdown无影响。
9. TCP连接上出现RST与随后可能的TIME_WAIT状态没有直接关系,主动发FIN包方必然会进入TIME_WAIT状态,除非不发送FIN而直接以发送RST结束连接。
参考资料:

关于rsyslog不可靠的原因

缘起

人说rsyslogd丢日志,却未言起因,今好奇而查之。

闲话不闲

近几天不知缘何想起一个问题: tcp是有buffer的,在发送端和接收端都有,我们可以通过kill -19 serverpid使得数据阻塞在server端,也可以通过iptable在server端drop掉数据包,而使得数据阻塞在client端,总之,client app并不知道这些事情的发生,那么,如果现在server意外死掉,则buffer中的数据岂不丢失。(应该是吧,未曾验证)

换言之,对于tcp传输大量数据而言,如果是无格式的数据,在传输部分数据之后,接收方不想再接收数据了(可能是磁盘要满了),只想把buffer中的数据处理完就Ok了,如何告知发送方不要再发送数据了?

查看文档

 

On the (un)reliability of plain tcp syslog…

http://blog.gerhards.net/2008/04/on-unreliability-of-plain-tcp-syslog.html  rsyslogd的作者写过这么一篇文章来解释了rsyslogd不可考的一些原因,其中一点刚好是“闲话不闲”说的那种情况.

redis 源码片段

 

1. redis的lru的使用

其中:

这个赋值是怎么体现lru的工作机制的?

 

2. 按照下面的调用过程来看redis对每个命令的处理过程:

至于redis协议中的每条指定对应server端的那一个函数,不会看到一个if..else.. 或者 switch结构的, 从 redisCommandTable 中来找就足够了(当然,quit命令找不到,似乎也只有quit命令)

 

3. 今天还了解一下细节

1) key和value都是作为redis的object来存储的,相同的value是重复使用的

2) 过期机制是通过将要过期的key写到一个过期table中来做的,这个是和memcache不同的

4. redis是支持认证机制的,当然,这样会多一次请求,而且认证请求不能和其它请求一起打包执行的

 

5. 关于Redis的LRU:

Redis的LRU是不精确的,不是在allkey中LRU的,而是在allkey中随机选取 maxmemory-samples 来LRU的,这一点要考虑一下是否满足需求。

redis_lru

 

(了解一下概率的计算方法吧)

摘录: http://oldblog.antirez.com/post/redis-as-LRU-cache.html

maxmemory-samples number_of_samples

The last config option is used to tune the algorithms precision. In order to save memory Redis just adds a 22 bits field to every object for LRU. When we need to remove a key we sample N keys, and remove the one that was idle for longer time. For default three keys are sampled, that is a reasonable approximation of LRU in the long run, but you can get more precision at the cost of some more CPU time changing the number of keys to sample.

Redis 2.2 的配置文件关于LRU的相关说明: