linux tcp 阻塞时间,为什么Linux上的非阻塞TCP connect()偶尔会这么慢?

我试图测量我正在编写的TCP服务器的速度,我注意到可能存在测量connect()调用速度的根本问题:如果我以非阻塞方式连接,请连接()操作在几秒钟后变得非常慢。以下是Python中的示例代码:

#! /usr/bin/python2.4

import errno

import os

import select

import socket

import sys

import time

def NonBlockingConnect(sock, addr):

#time.sleep(0.0001) # Fixes the problem.

while True:

try:

return sock.connect(addr)

except socket.error, e:

if e.args[0] not in (errno.EINPROGRESS, errno.EALREADY):

raise

os.write(2, '^')

if not select.select((), (sock,), (), 0.5)[1]:

os.write(2, 'P')

def InfiniteClient(addr):

while True:

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)

sock.setblocking(0)

sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

# sock.connect(addr)

NonBlockingConnect(sock, addr)

sock.close()

os.write(2, '.')

def InfiniteServer(server_socket):

while True:

sock, addr = server_socket.accept()

sock.close()

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)

server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

server_socket.bind(('127.0.0.1', 45454))

server_socket.listen(128)

if os.fork(): # Parent.

InfiniteServer(server_socket)

else:

addr = server_socket.getsockname()

server_socket.close()

InfiniteClient(addr)

使用NonBlockingConnect,大多数connect()操作都很快,但是每隔几秒就会发生一次connect()操作,至少需要2秒钟(由输出上的5个连续的P字母表示)。通过使用sock.connect而不是NonBlockingConnect,所有连接操作似乎都很快。

怎么可能摆脱这些慢连接()?

我正在使用标准PAE内核运行Ubuntu Karmic桌面:

Linux narancs 2.6.31-20-generic-pae #57-Ubuntu SMP Mon Feb 8 10:23:59 UTC 2010 i686 GNU/Linux

strace -f ./conn.py没有延迟,这很奇怪。

奇怪的是,如果我取消对速度非常快的ѭ7,就没有延迟。

奇怪的是,我的Ubuntu Hardy系统没有延迟:

所有这些系统都受到影响(运行Ubuntu Karmic,Ubuntu Hardy,Debian Etch):

Linux narancs 2.6.31-20-generic-pae #57-Ubuntu SMP Mon Feb 8 10:23:59 UTC 2010 i686 GNU/Linux

Linux t 2.6.24-grsec #1 SMP Thu Apr 24 14:15:58 CEST 2008 x86_64 GNU/Linux

Linux geekpad 2.6.24-24-generic #1 SMP Fri Sep 18 16:49:39 UTC 2009 i686 GNU/Linux

奇怪的是,以下Debian Lenny系统不受影响:

Linux t 2.6.31.5 #2 SMP Thu Nov 5 15:33:05 CET 2009 i686 GNU/Linux

FYI如果我使用AF_UNIX套接字,则没有延迟。

仅供参考我如果在C中实现客户端,我会得到相同的行为:

/* by pts@fazekas.hu at Sun Apr 25 20:47:24 CEST 2010 */

#include

#include

#include

#include

#include

#include

#include

#include

#include

static int work(void) {

fd_set rset;

fd_set wset;

fd_set eset;

socklen_t sl;

struct timeval timeout;

struct sockaddr_in sa;

int sd, i, j;

long l;

sd = socket(AF_INET, SOCK_STREAM, 0);

if (sd < 0) {

perror("socket");

return 2;

}

l = fcntl(sd, F_GETFL, 0);

if (l < 0) {

perror("fcntl-getfl");

close(sd);

return 2;

}

if (0 != fcntl(sd, F_SETFL, l | O_NONBLOCK)) {

perror("fcntl-setfl");

close(sd);

return 2;

}

memset(&sa, ' ', sizeof(sa));

sa.sin_family = AF_INET;

sa.sin_port = htons(45454);

sa.sin_addr.s_addr = inet_addr("127.0.0.1");

while (0 != connect(sd, (struct sockaddr*)&sa, sizeof sa)) {

if (errno != EAGAIN && errno != EINPROGRESS && errno != EALREADY) {

perror("connect");

close(sd);

return 2;

}

FD_ZERO(&rset);

FD_ZERO(&wset);

FD_ZERO(&eset);

j = 0;

do {

timeout.tv_sec = 0;

timeout.tv_usec = 100 * 1000; /* 0.1 sec */

FD_SET(sd, &wset);

FD_SET(sd, &eset);

i = select(sd + 1, &rset, &wset, &eset, &timeout);

if (i < 0) {

perror("select");

close(sd);

return 2;

}

if (++j == 5) {

(void)write(2, "P", 1);

j = 0;

}

} while (i == 0);

sl = sizeof i;

if (0 != getsockopt(sd, SOL_SOCKET, SO_ERROR, &i, &sl)) {

perror("getsockopt");

close(sd);

return 2;

}

if (i != 0) {

if (i == ECONNRESET) {

(void)write(2, "R", 1);

close(sd);

return -3;

}

fprintf(stderr, "connect-SO_ERROR: %sn", strerror(i));

close(sd);

return 2;

}

}

close(sd);

return 0;

}

int main(int argc, char**argv) {

int i;

(void)argc;

(void)argv;

while ((i = work()) <= 0) (void)write(2, ".", 1);

return i;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值