存档

2011年8月 的存档

linux下tcp选项TCP_DEFER_ACCEPT详解

2011年8月28日 没有评论

原创文章,转载请注明: 转载自pagefault

本文链接地址: linux下tcp选项TCP_DEFER_ACCEPT详解

TCP_DEFER_ACCEPT这个选项可能大家都知道,不过我这里会从源码和数据包来详细的分析这个选项。要注意,这里我所使用的内核版本是3.0.

首先看man手册中的介绍(man 7 tcp):

TCP_DEFER_ACCEPT (since Linux 2.4)
Allow a listener to be awakened only when data arrives on the socket. Takes an integer value (seconds), this can bound the maximum number of attempts TCP will make to complete the connection. This option should not be used in code intended to be portable.

我先来简单介绍下,这个选项主要是针对server端的服务器,一般来说我们三次握手,当客户端发送syn,然后server端接收到,然后发送syn + ack,然后client接收到syn+ack之后,再次发送ack(client进入establish状态),最终server端收到最后一个ack,进入establish状态。

而当正确的设置了TCP_DEFER_ACCEPT选项之后,server端会在接收到最后一个ack之后,并不进入establish状态,而只是将这个socket标记为acked,然后丢掉这个ack。此时server端这个socket还是处于syn_recved,然后接下来就是等待client发送数据, 而由于这个socket还是处于syn_recved,因此此时就会被syn_ack定时器所控制,对syn ack进行重传,而重传次数是由我们设置TCP_DEFER_ACCEPT传进去的值以及TCP_SYNCNT选项,proc文件系统的tcp_synack_retries一起来决定的(后面分析源码会看到如何来计算这个值).而我们知道我们传递给TCP_DEFER_ACCEPT的是秒,而在内核里面会将这个东西转换为重传次数.

这里要注意,当重传次数超过限制之后,并且当最后一个ack到达时,下一次导致超时的synack定时器还没启动,那么这个defer的连接将会被加入到establish队列,然后通知上层用户。这个也是符合man里面所说的(Takes an integer value (seconds), this can bound the maximum number of attempts TCP will make to complete the connection.) 也就是最终会完成这个连接.

阅读全文…

Share
分类: kernel, 协议 标签: , ,

nginx中upstream的设计和实现(五)

2011年8月17日 2 条评论

原创文章,转载请注明: 转载自pagefault

本文链接地址: nginx中upstream的设计和实现(五)

这次主要来分析upstream中的发送数据给client, 以及当buf不足,将一部分写到temp file的部分,他们对应的函数分别是ngx_event_pipe_write_to_downstream和ngx_event_pipe_write_chain_to_temp_file.

先来看ngx_event_pipe_write_to_downstream,这个函数顾名思义,就是写buf到临时文件。而所写的buf就是p->in,也就是将要发送给client的数据。
这个函数,它会处理两类的情况,一类是cache打开,一类是cache未打开。我们这里主要来分析cache关闭的情况。

首先来看这个函数的第一部分的代码,这部分代码主要是遍历p->in,然后计算能写多少buf到文件(temp file的size是有限制的).

//out就是将要保存到file的数据
    if (p->buf_to_file) {
//cache打开的情况
        fl.buf = p->buf_to_file;
        fl.next = p->in;
        out = &fl;

    } else {
//得到数据
        out = p->in;
    }
//如果cache没有打开
    if (!p->cacheable) {

        size = 0;
        cl = out;
        ll = NULL;

        ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0,
                       "pipe offset: %O", p->temp_file->offset);
//开始遍历out
        do {
//计算大小
            bsize = cl->buf->last - cl->buf->pos;
.....................................................
//看是否超过限制限制
            if ((size + bsize > p->temp_file_write_size)
               || (p->temp_file->offset + size + bsize > p->max_temp_file_size))
            {
                break;
            }

            size += bsize;
            ll = &cl->next;
            cl = cl->next;

        } while (cl);

        ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "size: %z", size);

        if (ll == NULL) {
            return NGX_BUSY;
        }
//cl存在则说明只有一部分buf能够写入到temp file,此时p->in保存剩下的chain
        if (cl) {
           p->in = cl;
           *ll = NULL;

        } else {
//否则说明所有的buf都写入到了temp file,此时p->in则设置为空
           p->in = NULL;
           p->last_in = &p->in;
        }

    } else {
//cache打开的情况,可以看到和上面类似.
        p->in = NULL;
        p->last_in = &p->in;
    }

阅读全文…

Share
分类: nginx, server 标签: , ,

nginx中upstream的设计和实现(四)

2011年8月6日 没有评论

原创文章,转载请注明: 转载自pagefault

本文链接地址: nginx中upstream的设计和实现(四)

这此主要是分析发送数据到客户端的部分以及buffering状态下,nginx接收upstream数据的部分,这也是upstream的最复杂的部分,这里我还是忽略了cache部分,以后我会专门写blog来分析nginx的cache部分。

这部分的函数入口是ngx_http_upstream_send_response,这里有一个很重要的标记,那就是u->buffering,这个标记的含义就是nginx是否会尽可能多的读取upstream的数据。如果关闭,则就是一个同步的发送,也就是接收多少,发送给客户端多少。默认这个是打开的。也就是nginx会buf住upstream发送的数据。

不管buffering是否打开,后端发送的头都不会被buffer,首先会发送header,然后才是body的发送,而body的发送就需要区分buffering选项了。如下图所示:

upstream_ac
阅读全文…

Share
分类: nginx, server 标签: