5

我正在为我的客户端和服务器使用阻塞 TCP 套接字。每当我阅读时,我首先使用select. 我总是一次读写 40 个字节。虽然大多数读取需要几毫秒或更短的时间,但有些只需要半秒以上。在我知道套接字上有可用数据之后。

我也在使用TCP_NODELAY

可能是什么原因造成的?

编辑 2

我分析了每个发送和接收的数据包的时间戳,发现只有当客户端在服务器写入下一个对象之前尝试读取对象时才会发生这种延迟。例如,服务器写入对象编号 x,然后客户端尝试读取对象 x,然后服务器才能够开始写入对象编号 x+1。这让我怀疑服务器端正在发生某种合并。

编辑

服务器正在侦听 3 个不同的端口。客户端一一连接到这些端口中的每一个。

有三种连接:一种是频繁地从服务器向客户端发送一些数据。第二个只将数据从客户端发送到服务器。第三个很少用于发送单字节数据。我面临第一次连接的问题。我正在使用select()该连接上可用的数据进行检查,然后当我为 40 字节读取添加时间戳时,我发现该读取花费了大约半秒。

任何有关如何分析此内容的指示都会非常有帮助

在 Linux 上使用 gcc。

rdrr_server_start(void) {
int rr_sd; int input_sd; int ack_sd; int fp_sd;

startTcpServer(&rr_sd, remote_rr_port); startTcpServer(&input_sd, remote_input_port); startTcpServer(&ack_sd, remote_ack_port); startTcpServer(&fp_sd, remote_fp_port);

connFD_rr = getTcpConnection(rr_sd); connFD_input = getTcpConnection(input_sd); connFD_ack= getTcpConnection(ack_sd); connFD_fp=getTcpConnection(fp_sd); }

static int getTcpConnection(int sd) { socklen_t l en;
struct sockaddr_in clientAddress; len = sizeof(clientAddress); int connFD = accept(sd, (struct sockaddr*) &clientAddress, &len); nodelay(connFD); fflush(stdout); return connFD; }

static void startTcpServer(int *sd, const int port) { *sd= socket(AF_INET, SOCK_STREAM, 0); ASSERT(*sd>0);

// Set socket option so that port can be reused int enable = 1; setsockopt(*sd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int));

struct sockaddr_in a; memset(&a,0,sizeof(a)); a.sin_family = AF_INET; a.sin_port = port; a.sin_addr.s_addr = INADDR_ANY; int bindResult = bind(*sd, (struct sockaddr *) &a, sizeof(a)); ASSERT(bindResult ==0); listen(*sd,2); } static void nodelay(int fd) { int flag=1; ASSERT(setsockopt(fd, SOL_TCP, TCP_NODELAY, &flag, sizeof flag)==0); }

startTcpClient() { connFD_rr = socket(AF_INET, SOCK_STREAM, 0); connFD_input = socket(AF_INET, SOCK_STREAM, 0); connFD_ack = socket(AF_INET, SOCK_STREAM, 0); connFD_fp= socket(AF_INET, SOCK_STREAM, 0);

struct sockaddr_in a; memset(&a,0,sizeof(a)); a.sin_family = AF_INET; a.sin_port = remote_rr_port; a.sin_addr.s_addr = inet_addr(remote_server_ip);

int CONNECT_TO_SERVER= connect(connFD_rr, &a, sizeof(a)); ASSERT(CONNECT_TO_SERVER==0) ;

a.sin_port = remote_input_port; CONNECT_TO_SERVER= connect(connFD_input, &a, sizeof(a)); ASSERT(CONNECT_TO_SERVER==0) ;

a.sin_port = remote_ack_port; CONNECT_TO_SERVER= connect(connFD_ack, &a, sizeof(a)); ASSERT(CONNECT_TO_SERVER==0) ;

a.sin_port = remote_fp_port; CONNECT_TO_SERVER= connect(connFD_fp, &a, sizeof(a)); ASSERT(CONNECT_TO_SERVER==0) ;

nodelay(connFD_rr); nodelay(connFD_input); nodelay(connFD_ack); nodelay(connFD_fp); }

4

5 回答 5

1

我会怀疑这行代码:

ASSERT(setsockopt(fd, SOL_TCP, TCP_NODELAY, &flag, sizeof flag)==0);  

如果您正在运行发布版本,那么 ASSERT 很可能被定义为空,因此实际上不会进行调用。setsockopt 调用不应出现在 ASSERT 语句中。相反,应该在断言语句中验证返回值(在变量中)。 带有副作用的断言通常是一件坏事。所以即使这不是问题,也应该改变它。

于 2012-05-25T14:06:09.747 回答
0

一个客户端和多个连接?

一些套接字函数可能会阻止您的执行(即等待函数的结果)。我建议为每个连接打开一个新线程(在服务器端),这样它们就不会相互干扰......

但我在黑暗中拍摄;你需要发送一些额外的信息......

于 2012-05-25T10:30:01.107 回答
0

您可以尝试将TCP_CORK(CORK'ed 模式)与内核扩展一起使用GROGSOTSO通过以下方式禁用ethtool

  • TCP_CORK标记的会话中发送将确保数据不会在部分段中发送

  • 禁用generic-segmentation-offloadgeneric-receive-offloadtcp-segmentation-offload确保内核在将数据移入/移出用户空间之前不会引入人为延迟来收集额外的 tcp 段

于 2013-08-12T10:16:10.490 回答
0

您的陈述仍然令人困惑,即“只有一个客户端的多个 tcp 连接”。显然,您有一台服务器在一个端口上侦听。现在,如果您有多个连接,这意味着有多个客户端连接到服务器,每个客户端都连接到不同的 tcp 客户端端口。现在服务器运行选择并响应任何有数据的客户端(意味着客户端在他的套接字上发送了一些数据)。现在如果两个客户端同时发送数据,服务器只能按顺序处理它们。因此,在服务器完成第一个处理之前,不会处理第二个客户端。

Select 仅允许服务器监视多个描述符(套接字)并处理曾经有可用数据的进程。它不像它并行处理。为此,您需要多个线程或进程。

于 2012-05-25T10:52:18.527 回答
0

也许这与timeout论点有关。

你为调用timeout参数设置了select什么?

尝试将超时参数更改为更大的参数并观察延迟。有时,超时时间太短,而且系统调用通常会扼杀吞吐量。如果您假设更大的延迟,也许您可​​以获得更好的结果,这是可以实现的。

我怀疑超时或一些代码错误。

于 2012-05-25T11:23:08.097 回答