Socket通讯连接Server,并可设置连接超时时间
非阻塞模式:使用 ioctlsocket 将 socket 设置为非阻塞模式,这样 connect 调用不会阻塞主线程。
连接线程:在一个新线程中执行连接操作,使用 std::atomic 来检查连接是否成功。
超时逻辑:主线程使用一个循环来检查连接是否成功,若超出设定的超时时间则退出。
cpp
#include <iostream>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <thread>
#include <atomic>
#pragma comment(lib, "ws2_32.lib")
void ThreadConnect(SOCKET sock, struct sockaddr_in* server, std::atomic<bool>& connected)
{
if (connect(sock, (struct sockaddr*)server, sizeof(*server)) == SOCKET_ERROR)
{
connected = false;
}
else
{
connected = true;
}
}
bool ConnectServer()
{
WSADATA wsaData;
SOCKET sock;
struct sockaddr_in server;
// 初始化 Winsock
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
std::cerr << "Failed to initialize Winsock. Error: " << WSAGetLastError() << std::endl;
return false;
}
// 创建 socket
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET)
{
std::cerr << "Could not create socket. Error: " << WSAGetLastError() << std::endl;
WSACleanup();
return false;
}
// 设置 socket 为非阻塞模式
u_long mode = 1; // 1 表示非阻塞模式
ioctlsocket(sock, FIONBIO, &mode);
// 配置服务器地址
server.sin_family = AF_INET;
server.sin_port = htons(7999); // 服务器端口
inet_pton(AF_INET, "127.0.0.1", &server.sin_addr); // 服务器地址
std::atomic<bool> connected(false);
std::thread connectThread(ThreadConnect, sock, &server, std::ref(connected));
// 等待连接或超时
int connecTimeout = 1000;
DWORD startTime = GetTickCount();
while (GetTickCount() - startTime < connecTimeout)
{
if (connected)
{
break;
}
Sleep(100);
}
connectThread.join(); // 关闭连接线程
std::cout << "Connection time: " << (GetTickCount() - startTime) << " ms" << std::endl;
if (!connected)
{
std::cerr << "Connection timeout." << std::endl;
closesocket(sock);
WSACleanup();
return false;
}
mode = 0; // 设置为阻塞模式
ioctlsocket(sock, FIONBIO, &mode);
std::cout << "Connected to server!" << std::endl;
int sendTimeout = 1000; // 发送超时设置
int recvTimeout = 1000; // 接收超时设置
if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (const char*)&sendTimeout, sizeof(sendTimeout)) < 0)
{
std::cerr << "Failed to set send timeout. Error: " << WSAGetLastError() << std::endl;
closesocket(sock);
WSACleanup();
return false;
}
if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&recvTimeout, sizeof(recvTimeout)) < 0)
{
std::cerr << "Failed to set receive timeout. Error: " << WSAGetLastError() << std::endl;
closesocket(sock);
WSACleanup();
return false;
}
// 这里可以添加发送和接收数据的代码
// 关闭 socket
closesocket(sock);
WSACleanup();
return true;
}
int main()
{
ConnectServer();
std::cin.get();
return 0;
}