Chinaunix首页 | 论坛 | 博客
  • 博客访问: 5771680
  • 博文数量: 675
  • 博客积分: 20301
  • 博客等级: 上将
  • 技术积分: 7671
  • 用 户 组: 普通用户
  • 注册时间: 2005-12-31 16:15
文章分类

全部博文(675)

文章存档

2012年(1)

2011年(20)

2010年(14)

2009年(63)

2008年(118)

2007年(141)

2006年(318)

分类: C/C++

2010-04-11 13:36:29

转载注:测试代码和tcpdump的内容稍微改动了一下。

Linux connect(2)还有一个不怎么为人所知的属性:如果地址的family是AF_UNSPEC,对于TCP连接将通过发送RST包关闭连接,对于UDP连接将去掉目的地址关联,共同的结果是留下一个未连接的socket,这个socket和刚通过socket(2)创建的socket一样。这使得我们可以通过connect(2)到family是AF_UNSPEC的地址来替代close(2)关闭一个连接,并把这个连接的socket放到一个pool里面,以备后用,因为这能省去一个socket(2)调用的开销。

测试代码如下:
#include
#include
#include
#include
#include
#include
#include

#define xconnect(fd, addr, len) \
    do { \
        if (connect(fd, addr, len) < 0) { \
            fprintf(stderr, "connect error with: %s\n", \
                    strerror(errno)); \
            exit(EXIT_FAILURE); \
        } \
    } while (0)


int main(int argc, char *argv[])
{
        int retval;
        struct sockaddr_in addr;
        socklen_t len;

if(argc!=2)
{
printf("Usage: xconnect xx.xx.xx.xx\n");
return 0;
}

char *addr_str = argv[1];

        retval = socket(AF_INET, SOCK_STREAM, 0);
        memset(&addr, 0, sizeof(&addr));
        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = inet_addr(addr_str);
        addr.sin_port = htons(22);
        len = sizeof(addr);
        xconnect(retval, (struct sockaddr*)&addr, len);
        getsockname(retval, (struct sockaddr*)&addr, &len);
        printf("Old Port: %d\n", ntohs(addr.sin_port));

        addr.sin_family = AF_UNSPEC;
        xconnect(retval, (struct sockaddr*)&addr, len);

        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = inet_addr(addr_str);
        addr.sin_port = htons(22);
        xconnect(retval, (struct sockaddr*)&addr, len);
        getsockname(retval, (struct sockaddr*)&addr, &len);
        printf("New Port: %d\n", ntohs(addr.sin_port));

        return 0;
}

tcpdump的抓包如下:
debian-wangyao:/home/wangyao# tcpdump -i lo -nvv tcp
tcpdump: listening on lo, link-type EN10MB (Ethernet), capture size 96 bytes
13:27:48.919082 IP (tos 0x0, ttl 64, id 52187, offset 0, flags [DF], proto TCP (6), length 60)
    127.0.0.1.39206 > 127.0.0.1.22: Flags [S], cksum 0x0338 (correct), seq 629688948, win 32792, options [mss 16396,sackOK,TS val 24019375 ecr 0,nop,wscale 6], length 0
13:27:48.919108 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 60)
    127.0.0.1.22 > 127.0.0.1.39206: Flags [S.], cksum 0x51bd (correct), seq 637536356, ack 629688949, win 32768, options [mss 16396,sackOK,TS val 24019375 ecr 24019375,nop,wscale 6], length 0
13:27:48.919135 IP (tos 0x0, ttl 64, id 52188, offset 0, flags [DF], proto TCP (6), length 52)
    127.0.0.1.39206 > 127.0.0.1.22: Flags [.], cksum 0x38e0 (correct), seq 1, ack 1, win 513, options [nop,nop,TS val 24019375 ecr 24019375], length 0
--------------------------------------------------------------
第一次三次握手
--------------------------------------------------------------
13:27:48.919661 IP (tos 0x0, ttl 64, id 52189, offset 0, flags [DF], proto TCP (6), length 52)
    127.0.0.1.39206 > 127.0.0.1.22: Flags [R.], cksum 0x38dc (correct), seq 1, ack 1, win 513, options [nop,nop,TS val 24019375 ecr 24019375], length 0
--------------------------------------------------------------
RST中断第一个连接
--------------------------------------------------------------
13:27:48.919687 IP (tos 0x0, ttl 64, id 19416, offset 0, flags [DF], proto TCP (6), length 56)
    127.0.0.1.39207 > 127.0.0.1.22: Flags [S], cksum 0x9740 (correct), seq 629721719, win 32792, options [mss 16396,sackOK,TS val 24019375 ecr 0], length 0
13:27:48.919704 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 56)
    127.0.0.1.22 > 127.0.0.1.39207: Flags [S.], cksum 0xc014 (correct), seq 631516785, ack 629721720, win 32768, options [mss 16396,sackOK,TS val 24019375 ecr 24019375], length 0
13:27:48.919723 IP (tos 0x0, ttl 64, id 19417, offset 0, flags [DF], proto TCP (6), length 52)
    127.0.0.1.39207 > 127.0.0.1.22: Flags [.], cksum 0x1513 (correct), seq 1, ack 1, win 32792, options [nop,nop,TS val 24019375 ecr 24019375], length 0
--------------------------------------------------------------
第二次三次握手
--------------------------------------------------------------
13:27:48.920877 IP (tos 0x0, ttl 64, id 19418, offset 0, flags [DF], proto TCP (6), length 52)
    127.0.0.1.39207 > 127.0.0.1.22: Flags [F.], cksum 0x1512 (correct), seq 1, ack 1, win 32792, options [nop,nop,TS val 24019375 ecr 24019375], length 0
13:27:48.924008 IP (tos 0x0, ttl 64, id 45021, offset 0, flags [DF], proto TCP (6), length 52)
    127.0.0.1.22 > 127.0.0.1.39207: Flags [.], cksum 0x1529 (correct), seq 1, ack 2, win 32768, options [nop,nop,TS val 24019376 ecr 24019375], length 0
13:27:48.933517 IP (tos 0x0, ttl 64, id 45022, offset 0, flags [DF], proto TCP (6), length 84)
    127.0.0.1.22 > 127.0.0.1.39207: Flags [P.], seq 1:33, ack 2, win 32768, options [nop,nop,TS val 24019378 ecr 24019375], length 32
13:27:48.933539 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 40)
    127.0.0.1.39207 > 127.0.0.1.22: Flags [R], cksum 0x289f (correct), seq 629721721, win 0, length 0
--------------------------------------------------------------
最后只是由于程序关闭,用FIN关闭连接,接受到server端响应,由于程序已经关闭,协议栈响应RST
--------------------------------------------------------------

我们尽量在收到对方的FIN包,也就是read(2)等返回0的时候再调用connect(AF_UNSPEC)关闭连接,防止造成误会。
可能的应用:反向HTTP代理中,由代理服务器发往HTTP服务器的连接。
阅读(3796) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~