i new winsock , have been trying write small http server listening on localhost educational purposes mainly. server returns web page whoever connects it, without parsing request.
logically, must listening new connections on listening port (i chose 81 here) after finish client , close connection, i've googled quite bit , found should using so_reuseaddr purpose, maybe got wrong. using firefox client.
the first connection goes without hitch. however, second time client attempts connect, accept function doesn't seem accept connection. on other hand, can see connection established @ time using utility watches local ports (currports). i've looked hours solution , have tried make socket non-blocking, no luck. did wrong?
#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 " << 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 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 thread in case want handle more 1 connection @ time in future, 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(); }
here's how code should work:
main function:
- open listening socket.
- bind it.
- call listen.
- call accept.
- dispatch thread handle socket accepted.
- go step 4.
note thread never touches listening socket.
Comments
Post a Comment