Я совершенно новичок в Winsock и стараюсь писать небольшой HTTP-сервер, который в основном слушает локальный хост для образовательных целей. В настоящее время сервер просто возвращает веб-страницу тому, кто подключается к нему, без разбора какого-либо запроса.C++ Winsock SO_REUSEADDR: accept() не возвращает сокет при подключении
Логично, что я всегда должен слушать новые подключения к порту прослушивания (я выбрал 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();
}
Слуховой сокет должен быть создан за пределами цикла while. –
Я тоже пробовал это, и программа, похоже, входит в бесконечный цикл, забирающий всю память и процессор, и компьютер падает ... –
Так исправить ошибку, которая вызывает это. Но вышеприведенный код не может работать. Кроме того, 'strlen (response.c_str()) * sizeof (char)' - серьезно ?! –