gpt4 book ai didi

C++ Winsock SO_REUSEADDR : accept() not returning socket on connection

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:16:37 26 4
gpt4 key购买 nike

我是 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 << "\r\n" << err;
}
struct sockaddr_in* sin = (struct sockaddr_in*)sa;
std::cout << "\r\nConnected 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 << "\r\n" << 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 << "\r\nError 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 << "\r\nSocket 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 OK\r\nServer: myServer\r\nContent-Type: text/html\r\nConnection: close\r\nContent-Length: " + std::to_string(content.length()) + "\r\n\r\n" + content;
std::cout << "\r\n" << send(socket0, response.c_str(), strlen(response.c_str())*sizeof(char), 0);
Sleep(1000);
std::cout << "\r\n" << closeSocket(socket0);
}
WSACleanup();
}

最佳答案

这是您的代码应该如何工作:

主要功能:

  1. 打开监听套接字。
  2. 绑定(bind)它。
  3. 打电话听。
  4. 调用接受。
  5. 分派(dispatch)一个线程来处理我们刚刚接受的套接字。
  6. 转到第 4 步。

请注意,线程永远不会接触监听套接字。

关于C++ Winsock SO_REUSEADDR : accept() not returning socket on connection,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32788986/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com