Winsock SO_REUSEADDR: accept()在连接时没有返回套接字
C++ Winsock SO_REUSEADDR: accept() not returning socket on connection
我对Winsock完全陌生,并且一直在尝试编写一个小型HTTP服务器,主要用于教育目的。目前,服务器只是返回一个网页给任何连接到它的人,而不解析任何请求。
从逻辑上讲,在我完成客户端并关闭连接后,我必须始终侦听侦听端口上的新连接(我在这里选择81),所以我已经搜索了相当多,发现我应该为此目的使用SO_REUSEADDR,但也许我错了。我使用Firefox作为客户端。
第一次连接总是顺利进行。但是,当客户端第二次尝试连接时,accept函数似乎不接受连接。另一方面,我可以看到连接是在使用监视本地端口的实用程序(CurrPorts)建立的。我已经找了几个小时的解决方案,并试图使插座非阻塞,但没有运气。我做错了什么?
#pragma comment(lib,"Ws2_32.lib")
#include <WinSock2.h>
#include <iostream>
#include <thread>
#include <string>
#include <array>
#include <ctime>
#include <winerror.h>
inline std::string getAddress(sockaddr_in* sin)
{
std::string res = std::to_string(sin->sin_addr.S_un.S_un_b.s_b1) + '.' + std::to_string(sin->sin_addr.S_un.S_un_b.s_b2) + '.' + std::to_string(sin->sin_addr.S_un.S_un_b.s_b3) + '.' + std::to_string(sin->sin_addr.S_un.S_un_b.s_b4);
return res;
}
void acceptTCP(SOCKET& origSock)
{
SOCKET tempSock = SOCKET_ERROR;
struct sockaddr* sa = new sockaddr();
int size = sizeof(*sa);
while (tempSock == SOCKET_ERROR)
{
tempSock = accept(origSock, sa, &size);
int err = WSAGetLastError();
if (err != 0 && err != WSAEWOULDBLOCK) std::cout << "rn" << err;
}
struct sockaddr_in* sin = (struct sockaddr_in*)sa;
std::cout << "rnConnected to " << getAddress(sin) << ":" << htons(sin->sin_port);
origSock = tempSock;
}
int closeSocket(SOCKET socket)
{
shutdown(socket, 2); //I've tried using 0
std::clock_t start = std::clock();
char buf[1];
while ((std::clock() - start) / (double)CLOCKS_PER_SEC < 5)
{
int res = recv(socket, buf, strlen(buf), IPPROTO_TCP);
//std::cout << "rn" << res;
bool br = false;
switch (res)
{
case 0: br = true; break; //client closed connection
case -1:
{
int err = WSAGetLastError();
if (err != WSAEWOULDBLOCK && err != WSAEINTR) //client closed connection
{
br = true;
break;
}
else std::cout << "rnError on close socket: " << err;
}
default: exit(1); //data is being sent after shutdown request
};
if (br) break;
//if (res == -1) std::cout << ": " << WSAGetLastError();
//else std::cout << ": " << buf;
//Sleep(1000);
}
return closesocket(socket);
}
int main()
{
WSADATA WsaDat;
if (WSAStartup(MAKEWORD(1, 1), &WsaDat) != 0) std::cout << "???";
while (true)
{
SOCKET socket0 = socket(AF_INET, SOCK_STREAM, 0);
if (socket0 == INVALID_SOCKET) std::cout << "Invalid socket!";
struct sockaddr_in saServer;
saServer.sin_family = AF_INET;
saServer.sin_port = htons(81);
saServer.sin_addr.S_un.S_un_b.s_b1 = 127;
saServer.sin_addr.S_un.S_un_b.s_b2 = 0;
saServer.sin_addr.S_un.S_un_b.s_b3 = 0;
saServer.sin_addr.S_un.S_un_b.s_b4 = 1;
int enable = 1;
if (setsockopt(socket0, SOL_SOCKET, SO_REUSEADDR, (const char*)&enable, sizeof(int)) < 0)
std::cout << "setsockopt(SO_REUSEADDR) failed";
u_long iMode = 1;
ioctlsocket(socket0, FIONBIO, &iMode);
if (bind(socket0, (SOCKADDR*)&saServer, sizeof(saServer)) == SOCKET_ERROR) std::cout << "rnSocket Error " << WSAGetLastError();
else std::cout << "Socket bound!";
listen(socket0, 1);
std::thread threadConnection(&acceptTCP, std::ref(socket0)); //I use a thread in case I will want to handle more than one connection at a time in the future, but it serves no purpose here
threadConnection.join();
std::string content = "<!DOCTYPE html><html><head><title>test</title></head><body><p>test</p></body></html>";
std::string response = "HTTP/1.1 200 OKrnServer: myServerrnContent-Type: text/htmlrnConnection: closernContent-Length: " + std::to_string(content.length()) + "rnrn" + content;
std::cout << "rn" << send(socket0, response.c_str(), strlen(response.c_str())*sizeof(char), 0);
Sleep(1000);
std::cout << "rn" << closeSocket(socket0);
}
WSACleanup();
}
你的代码应该是这样工作的:
主要功能:
- 打开监听套接字。
- 绑定它。
- 叫听。
- 调用接受。
- 调度一个线程来处理我们刚刚接受的套接字。
- 转到步骤4
相关文章:
- 当套接字连接断开时检测C/C++Unix
- 套接字连接"Operation not permitted"错误,甚至使用升压/平发器根.cpp
- C++套接字客户端到 Python 服务器未创建连接
- 在不知道套接字的情况下关闭网络连接
- 当对套接字 send() 的同步调用由于连接另一端丢失而被阻止时,如何恢复?
- 当客户端在 write() 期间终止连接时,由对等套接字错误重置连接
- 从网链套接字请求连接设备的列表
- C++ TCP 套接字通信 - 连接按预期工作,几秒钟后失败,没有收到新数据,read() 和 recv() 块
- 如何在 2 台主机之间保持 UDP 套接字连接打开
- C++关闭套接字以启动新连接
- Opencv 不适用于套接字连接
- 使用单个套接字处理多个传入的 UDP 连接
- 连接UDP套接字,但仍然接收来自其他源的数据报
- C++通过套接字连接发送矢量
- 为什么我在蓝牙连接()上收到"java.io.IOException:读取失败,套接字可能关闭或超时,读取re
- boost1.62 在 docker 容器中重新连接后套接字损坏
- 尝试连接到 TCP 套接字 (Linux) 时连接被拒绝
- 仅通过建立一次TCP连接将Recv从客户端发送到服务器套接字
- 接受套接字,但m_socket.远程终结点引发 传输终结点未连接
- 提振.Asio:对每个连接/套接字使用“io_service”是件好事吗?