如何确定网络堆栈何时准备好再次打开相同 host/port 的套接字?
How can I determine when the network stack is ready to open socket to same host/port again?
我有以下 C 程序,其主要功能 runTCPConnectivityCheck
打开一个 TCP 套接字,向其发送一串字节并关闭它:
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
static int runTCPConnectivityCheck(const int port)
{
int fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0)
{
printf("socket failed\n");
return 1;
}
int reuseAddrTrue = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuseAddrTrue, sizeof(reuseAddrTrue)) != 0)
{
printf("setsockopt failed\n");
return 1;
}
struct sockaddr_in serv_addr = { 0 };
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port);
if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) != 1)
{
printf("inet_pton failed\n");
return 1;
}
if (connect(fd, (struct sockaddr*)(&serv_addr), sizeof(serv_addr)) != 0)
{
printf("connect failed\n");
return 1;
}
const char* message = "hello";
const size_t messageLength = strlen(message);
if (send(fd, message, messageLength, 0) != messageLength)
{
printf("send failed\n");
return 1;
}
shutdown(fd, SHUT_RDWR);
close(fd);
return 0;
}
int main()
{
for (int i = 0; i < 10; ++i)
{
printf("%s\n", runTCPConnectivityCheck(5555) == 0 ? "success" : "failure");
//sleep(1);
}
}
如果我尝试重复测试同一个端口,第一次调用 runTCPConnectivityCheck
工作正常,但所有后续调用都会在调用 connect
时失败。如果我在 sleep
中添加调用,那么它也有效。据推测,1 秒的延迟给了网络堆栈足够的时间来清理套接字,以便我可以再次连接到同一个端口。
首先:我是否正确关闭了插座?其次:如果我正确关闭它,确定网络堆栈何时准备好再次连接到同一主机和端口的标准方法是什么(而不是我目前使用的蹩脚 sleep
)?
更新
更多详细信息:connect
失败,错误代码为 61 或 ECONNREFUSED
,而 strerror
正在返回 "Connection refused"。
本例中的服务器是 netstat
/nc
命令 运行 在与测试程序相同的机器上循环:
#!/bin/bash
while true; do
nc -l 5555
done
程序现在是真正的 C。
普遍认为客户端代码没有特别的错误。事实证明我的测试服务器跟不上我的客户端:
#!/bin/bash
while true; do
nc -l 5555
done
我在 Python 中编写了一个分叉服务器,它能够毫无困难地为所有客户端连接提供服务。
我有以下 C 程序,其主要功能 runTCPConnectivityCheck
打开一个 TCP 套接字,向其发送一串字节并关闭它:
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
static int runTCPConnectivityCheck(const int port)
{
int fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0)
{
printf("socket failed\n");
return 1;
}
int reuseAddrTrue = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuseAddrTrue, sizeof(reuseAddrTrue)) != 0)
{
printf("setsockopt failed\n");
return 1;
}
struct sockaddr_in serv_addr = { 0 };
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port);
if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) != 1)
{
printf("inet_pton failed\n");
return 1;
}
if (connect(fd, (struct sockaddr*)(&serv_addr), sizeof(serv_addr)) != 0)
{
printf("connect failed\n");
return 1;
}
const char* message = "hello";
const size_t messageLength = strlen(message);
if (send(fd, message, messageLength, 0) != messageLength)
{
printf("send failed\n");
return 1;
}
shutdown(fd, SHUT_RDWR);
close(fd);
return 0;
}
int main()
{
for (int i = 0; i < 10; ++i)
{
printf("%s\n", runTCPConnectivityCheck(5555) == 0 ? "success" : "failure");
//sleep(1);
}
}
如果我尝试重复测试同一个端口,第一次调用 runTCPConnectivityCheck
工作正常,但所有后续调用都会在调用 connect
时失败。如果我在 sleep
中添加调用,那么它也有效。据推测,1 秒的延迟给了网络堆栈足够的时间来清理套接字,以便我可以再次连接到同一个端口。
首先:我是否正确关闭了插座?其次:如果我正确关闭它,确定网络堆栈何时准备好再次连接到同一主机和端口的标准方法是什么(而不是我目前使用的蹩脚 sleep
)?
更新
更多详细信息:connect
失败,错误代码为 61 或 ECONNREFUSED
,而 strerror
正在返回 "Connection refused"。
本例中的服务器是 netstat
/nc
命令 运行 在与测试程序相同的机器上循环:
#!/bin/bash
while true; do
nc -l 5555
done
程序现在是真正的 C。
普遍认为客户端代码没有特别的错误。事实证明我的测试服务器跟不上我的客户端:
#!/bin/bash
while true; do
nc -l 5555
done
我在 Python 中编写了一个分叉服务器,它能够毫无困难地为所有客户端连接提供服务。