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的相关说明:

 

如何spawn多个外部程序并且accept同一个socket

缘起

学习fastcgi的时候,多个fcgi进程的启动和管理是个无法回避的问题;有一个叫做spawn-fcgi的程序,可以启动多个php-cgi进程,并且同时accept同一个socket,因为spawn-fcgi和php-cgi是两个项目中的程序,那么他们是如何配合的如此默契的呢?

资料: http://redmine.lighttpd.net/projects/spawn-fcgi    其中主要是: http://redmine.lighttpd.net/projects/spawn-fcgi/repository/entry/trunk/src/spawn-fcgi.c

 

分析

从代码来看,spawn-fcgi负责lisent一个socket,然后开始fork指定数量的子进程,每个子进程中先把socket的fd复制到FCGI使用的fd(似乎是约定好的一个fd),然后就把后续的事情通过exec交给外部的进程(如:php-cgi)了

下面看一下PHP中fastcgi的相关逻辑, 文件 sapi/cgi/fastcgi.c 中的 int fcgi_init(void);函数体现了如何识别是否fastcgi的逻辑,大致意思为: 如果标准输入为一个socket(不是fileno),则认为是fastcgi,代码片段如下:

 

注意其中 getpeername(…)的使用,如果 errno == ENOTCONN 才可能认为是fastcgi,那么,如果刚好该socket处于连接状态不就不能视为fastcgi环境了吗?  或许吧

 

通过fcgi-kit来学习fastcgi

工具下载地址: http://www.fastcgi.com/dist/fcgi.tar.gz

工具使用文档:  http://www.fastcgi.com/devkit/doc/fcgi-devel-kit.htm

命令:

 

命令: 连接一个真是存在的fcgi server

这里只写了两个环境变量,不过,也至少要有这两个:

windows 下使用nginx心得

1. 如果使用fastcgi,则没有一个好的fastcgi进程管理程序,lighttpd中有一个Spawn-Fcgi.exe http://en.wlmp-project.net/

2. 当nginx放在windows上,而fastcgi进程在linux上时,需要注意一个问题,root目录可能不对,如下:

如果nginx是在D: 盘的话,则fastcgi看到的$document_root 为: d:/home/phpor/www ,而且会认为是一个相对目录,这样,自然是找不到要执行的文件的,可修改如下:

3. nginx 天生是不支持cgi的,所以想配个cgi也不成的

4. nginx 放在windows上仅仅学习而用

 

再见了msn

如果你再安装msn,安装完毕登录时,会要求你更新,更新后的是skype,skype整合了msn: http://skype.tom.com/

 

微软的outlook配置hotmail邮箱的时候还需要一个单独的OutlookConnector.exe需要安装,下载地址: http://download.microsoft.com/download/0/0/D/00DF5174-E7FB-4F70-B843-83CBDE509491/OutlookConnector.exe

而且,该地址还被墙了,或者说,微软的很多东西都被墙了,晕