c - 为 connect() winsock2 设置固定超时
问题描述
我正在为客户端-服务器通信基础设施编写一个 C 程序。
我的基本目标是允许连接试验至少在超时前持续 15 秒。这意味着,在连接到服务器时,我希望客户端最多等待 15 秒,以便服务器响应并接受此连接试验。在没有成功连接的 15 秒后,我想返回超时指示。
到目前为止,我能够使用 ioctlsocket() 使套接字非阻塞,然后使用 select() 等待 15 秒。我一直在使用 Remy Lebeau 的功能:
但是,我的问题是在这 15 秒内尝试从客户端连接到服务器时,服务器尚未打开。我尝试在客户端尝试连接服务器时而不是之前(在 15 秒内)打开服务器,但似乎“exceptfds”集首先被“发出信号”并扰乱了分配给超时的时间。
如果我不使用“exceptfds”,而只使用“writefds”,我可以等待 15 秒超时,但在 15 秒内无法连接到服务器 - 所以我只是遇到超时期间,不能用它来连接。
我已经在某处读到 select() 即使已达到超时也会返回,如果其中一组是“已发出信号” - 有没有办法克服这个问题?我也不想使用任何时间库。
这是我的代码:
non_blocking_ret_val connect_non_blocking(SOCKET sock, const char *ip_addr, u_short port_num){
int ret = 0;
SOCKADDR_IN server = { 0 };
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr(ip_addr);
server.sin_port = htons(port_num);
// ipaddr valid?
if (server.sin_addr.s_addr == INADDR_NONE) {
printf_s("Error in converting ip address. Terminating...\n");
return CONNECTION_ERROR;
}
// put socket in non-blocking mode...
if (SOCKET_ERROR == set_blocking(sock, FALSE))
return SOCKET_ERROR;
if (connect(sock, (struct sockaddr *)&server, sizeof(server)) == SOCKET_ERROR)
{
if (WSAGetLastError() != WSAEWOULDBLOCK)
{
// connection failed
//close_socket_and_deinit_wsa(sock);
printf_s("Making the connect function a non-blocking one failed, %ld. Terminating...\n", WSAGetLastError());
return CONNECTION_ERROR;
}
// connection pending
fd_set setW, setE;
FD_ZERO(&setW);
FD_SET(sock, &setW);
FD_ZERO(&setE);
FD_SET(sock, &setE);
TIMEVAL time_out = { 0 };
time_out.tv_sec = CLIENT_CONNECT_TIMEOUT;
time_out.tv_usec = 0;
ret = select(0, NULL, &setW, &setE, &time_out);
if (ret <= 0)
{
// select() failed or connection timed out
if (ret == 0) {
WSASetLastError(WSAETIMEDOUT);
return CONNECTION_TIMEOUT;
}
//close_socket(sock);
printf_s("select() function has unexpectedly failed. Terminating...\n");
return CONNECTION_ERROR;
}
if (FD_ISSET(sock, &setE))
{
// connection failed
int err = 0;
getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, sizeof(err));
WSASetLastError(err);
printf_s("Connection to server has failed. Terminating...\n");
return CONNECTION_FAILED;
}
}
// connection successful
// put socket in blocking mode...
if (SOCKET_ERROR == set_blocking(sock, TRUE))
return CONNECTION_ERROR;
return CONNECTION_SUCCEEDED;
}
int set_blocking(SOCKET m_socket, BOOL is_blocking){
unsigned long non_blocking = 1;
unsigned long blocking = 0;
int result = ioctlsocket(m_socket, FIONBIO, is_blocking ? &blocking : &non_blocking);
if (result == SOCKET_ERROR)
printf_s("Error no.%ld in using ioctlsocket(). Terminating...\n", WSAGetLastError());
return result;
}
谢谢!
解决方案
推荐阅读
- postgresql - 使用spring data rest与postgresql和缓存作为redis
- c++ - 0-1 背包 C++ 没有返回正确的值
- android - 如何在适配器类的 onBindViewHolder 中绑定整数值
- java - 使用 Java 中的流和 lambda 使用 for 循环重写笛卡尔积
- kotlin - 有没有办法在 Ktor 中热重载静态文件?
- jquery - 被另一个 masterrow 剑道网格折叠时仍选择上一个 masterrow
- package - 如何在 Monorepo 中运行多个开发包
- python - 从 graphicsView.bidvalue 中获取价值
- windows - Elecronjs 全局键盘快捷键在 make 后不起作用(使用电子锻造)
- javascript - 使用 Redux、NextJS 和 SSR 从 API 获取数据