Exact order of actions when running a server with threads - c++

I need to create a server in c++, where it can respond to more than 1 customer, thus use threads.
This is my class Socket, where the actual communication is done:
typedef struct addrinfo addinfo;
class Socket
{
private:
WSADATA _wsaData;
int _iResult;
SOCKET _ListenSocket;
addrinfo* _result;
addrinfo _hints;
int _iSendResult;
char _recvbuf[BUF_LEN];
int _recvbuflen;
std::vector<SOCKET> _ClientSockets;
public:
Socket();
bool Setup();
bool CreateSocket();
bool Bind();
bool Listen();
bool Accept();
bool Send();
bool Shutdown();
~Socket();
};
Socket::Socket()
{
_ListenSocket = INVALID_SOCKET;
_ClientSockets.push_back(INVALID_SOCKET);
_result = NULL;
_recvbuflen = BUF_LEN;
}
bool Socket::Setup() {
_iResult = WSAStartup(MAKEWORD(2, 2), &_wsaData);
if (_iResult != 0) {
std::cout << "WSAStartup failed with error: " << _iResult << std::endl;
return false;
}
ZeroMemory(&_hints, sizeof(_hints));
_hints.ai_family = AF_INET;
_hints.ai_socktype = SOCK_STREAM;
_hints.ai_protocol = IPPROTO_TCP;
_hints.ai_flags = AI_PASSIVE;
_iResult = getaddrinfo(NULL, DEFAULT_PORT, &_hints, &_result);
if (_iResult != 0) {
std::cout << "getaddrinfo failed with error: " << _iResult << std::endl;
WSACleanup();
return false;
}
return true;
}
bool Socket::CreateSocket() {
_ListenSocket = socket(_result->ai_family, _result->ai_socktype, _result->ai_protocol);
if (_ListenSocket == INVALID_SOCKET) {
std::cout << "socket failed with error: " << WSAGetLastError() << std::endl;
freeaddrinfo(_result);
WSACleanup();
return false;
}
return true;
}
bool Socket::Bind() {
_iResult = bind(_ListenSocket, _result->ai_addr, (int)_result->ai_addrlen);
if (_iResult == SOCKET_ERROR) {
std::cout << "bind failed with error: " << WSAGetLastError() << std::endl;
freeaddrinfo(_result);
closesocket(_ListenSocket);
WSACleanup();
return false;
}
freeaddrinfo(_result);
return true;
}
bool Socket::Listen() {
_iResult = listen(_ListenSocket, SOMAXCONN);
if (_iResult == SOCKET_ERROR) {
std::cout << "listen failed with error: " << WSAGetLastError() << std::endl;
closesocket(_ListenSocket);
WSACleanup();
return false;
}
return true;
}
bool Socket::Accept() {
_ClientSockets.push_back(accept(_ListenSocket, NULL, NULL));
if (_ClientSockets[_ClientSockets.size() - 1] == INVALID_SOCKET) {
std::cout << "accept failed with error: " << WSAGetLastError() << std::endl;
closesocket(_ListenSocket);
WSACleanup();
return false;
}
return true;
}
bool Socket::Send() {
closesocket(_ListenSocket);
_iResult = recv(_ClientSockets[_ClientSockets.size() - 1], _recvbuf, _recvbuflen, 0);
if (_iResult > 0) {
_iSendResult = send(_ClientSockets[_ClientSockets.size() - 1], "Accepted", strlen("Accepted"), 0);
if (_iSendResult == SOCKET_ERROR) {
std::cout << "send failed with error: " << WSAGetLastError() << std::endl;
closesocket(_ClientSockets[_ClientSockets.size() - 1]);
WSACleanup();
return false;
}
}
else if (_iResult == 0)
std::cout << "Connection closing..." << std::endl;
else {
std::cout << "recv failed with error: " << WSAGetLastError() << std::endl;
closesocket(_ClientSockets[_ClientSockets.size() - 1]);
WSACleanup();
return false;
}
return true;
}
bool Socket::Shutdown() {
_iResult = shutdown(_ClientSockets[_ClientSockets.size() - 1], SD_SEND);
if (_iResult == SOCKET_ERROR) {
std::cout << "shutdown failed with error: " << WSAGetLastError() << std::endl;
closesocket(_ClientSockets[_ClientSockets.size() - 1]);
WSACleanup();
return false;
}
closesocket(_ClientSockets[_ClientSockets.size() - 1]);
WSACleanup();
return true;
}
Socket::~Socket()
{
}
this is the main file:
void interact(Socket* socket);
int main() {
Socket* socket = new Socket();
socket->Setup();
socket->CreateSocket();
socket->Bind();
socket->Listen();
while (1) {
socket->Accept();
std::thread trd(interact, socket);
trd.join();
system("PAUSE");
}
socket->Shutdown();
system("PAUSE");
return 0;
}
void interact(Socket* socket) {
std::cout << "Accepted" << std::endl;
socket->Send();
}
Communicating with the first client is fine, but after I try to get back to listening and finish communication with the last client, it gives me error code 10038 for accept and 10093 for recv. I can't understand what the error codes actually mean in my code. I suspect it might be with the way I'm using Accept. Is it supposed to be in the interact function, or before i call the thread? Can I have some directing?

So your effective control flow is:
while (1) {
socket->Accept(); // uses socket->_ListenSocket
interact(socket); // calls socket->Send()
socket->Send(); // calls closesocket(_ListenSocket);
since you deliberately closed the listening socket, why would you expect a subsequent call to accept to work?
Other notes:
you're passing the entire server socket to each client thread, which is much more than it needs. Each client task should only need its own client socket, and would then be unable to damage your server socket as it does here.
you're currently serializing everything by joining the thread, but if you want parallelism, you need to detach this instead. This will further break the existing model of each thread taking the last client socket from the Socket's array (without synchronization).
It's often a better idea to have a thread pool for processing tasks, and make each task a client request with its own socket. This way you're not creating and destroying threads all the time, and it forces you to think about what constitutes a self-contained task

Related

c++ multithreaded tcp server using futures and async

I recently started studying c++ and I'm following some tutorials. I was looking into sockets and I decided as a side project to create a small multithreaded server as you can see below.
I was trying to close the servers listening socket once CLIENTS_MAX_NUM reached and then reopen it once a socket disconnects, however this is giving me an error 10022 (WSAEINVAL) and I'm not quite sure what I'm doing wrong.
In case you want to reproduce the error just connect using telnet and close the client connection (ctrl+] , quit).
Any help would be greatly appreciated.
#include <iostream>
#include <vector>
#include <string>
#include <future>
#include <chrono>
#include <WS2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
static constexpr const unsigned int PORT = 5000;
static constexpr const unsigned int CLIENTS_MAX_NUM = 1;
static constexpr const unsigned int CLIENTS_QUEUE_NUM = 10;
SOCKET server_sock;
std::vector<std::future<void>> futures;
std::mutex mtx;
void initialize_winsock() {
WSAData wsData;
WORD ver = MAKEWORD(2, 2);
int wsResult = WSAStartup(ver, &wsData);
if (wsResult != 0) {
std::cerr << WSAGetLastError() << std::endl;
WSACleanup();
exit(EXIT_FAILURE);
}
}
void bind_server_socket() {
int keep_alive = 1;
int re_use = 1;
if (setsockopt(server_sock, SOL_SOCKET, SO_KEEPALIVE, (const char*)&keep_alive, sizeof(keep_alive)) == SOCKET_ERROR) {
closesocket(server_sock);
WSACleanup();
exit(EXIT_FAILURE);
}
if (setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&re_use, sizeof(re_use)) == SOCKET_ERROR) {
closesocket(server_sock);
WSACleanup();
exit(EXIT_FAILURE);
}
sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(PORT);
server.sin_addr.S_un.S_addr = INADDR_ANY;
memset(&server.sin_zero, 0, 8);
if (bind(server_sock, (sockaddr*)&server, sizeof(sockaddr)) == SOCKET_ERROR) {
std::cerr << WSAGetLastError() << std::endl;
closesocket(server_sock);
WSACleanup();
exit(EXIT_FAILURE);
}
}
void open_server_socket(bool &listening) {
server_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (server_sock == INVALID_SOCKET) {
std::cerr << WSAGetLastError() << std::endl;
listening = false;
WSACleanup();
exit(EXIT_FAILURE);
}
listening = true;
}
void close_server_socket(bool &listening) {
closesocket(server_sock);
listening = false;
}
void handle_client(SOCKET client_sock, sockaddr_in client) {
char buf[4096];
char host[NI_MAXHOST];
char service[NI_MAXHOST];
memset(host, 0, NI_MAXHOST);
memset(service, 0, NI_MAXHOST);
//std::cout << std::this_thread::get_id() << std::endl;
if (getnameinfo((sockaddr*)&client, sizeof(client), host, NI_MAXHOST, service, NI_MAXSERV, 0) == 0) {
std::cout << host << " connected on port " << service << std::endl;
}
else {
inet_ntop(AF_INET, &client.sin_addr, host, NI_MAXHOST);
std::cout << host << " connected on port " << ntohs(client.sin_port) << std::endl;
}
while (true) {
memset(&buf, 0, 4096);
const int bytes_received = recv(client_sock, buf, 4096, 0);
if (bytes_received == SOCKET_ERROR) {
std::cerr << WSAGetLastError() << std::endl;
WSACleanup();
}
else if (bytes_received == 0) {
std::cout << "client disconnected" << std::endl;
break;
}
else {
send(client_sock, buf, bytes_received + 1, 0);
}
}
}
int main(int argc, const char* argv[]) {
bool listening = false;
initialize_winsock();
open_server_socket(listening);
bind_server_socket();
// -----------------------------------------------------------
if (listen(server_sock, CLIENTS_QUEUE_NUM) == SOCKET_ERROR) {
std::cerr << WSAGetLastError() << std::endl;
closesocket(server_sock);
WSACleanup();
exit(EXIT_FAILURE);
}
else {
std::cout << "listening for incoming connections on port " << PORT << std::endl;
while (true) {
unsigned int removed = 0;
for (int i = 0; i < futures.size(); i++) {
auto status = futures.at(i).wait_for(std::chrono::milliseconds(0));
if (status == std::future_status::ready) {
futures.erase(futures.begin() + i);
removed++;
}
}
if (removed > 1) {
std::cout << removed << " clients removed" << std::endl;
}
else if (removed) {
std::cout << removed << " client removed" << std::endl;
}
if (futures.size() < CLIENTS_MAX_NUM && !listening) {
std::cout << "re-opening server socket" << std::endl;
open_server_socket(listening);
// BOOM <--- 10022 (WSAEINVAL) - https://learn.microsoft.com/en-us/windows/win32/winsock/windows-sockets-error-codes-2
}
if (listening) {
sockaddr_in client;
memset(&client.sin_zero, 0, 8);
int client_size = sizeof(client);
SOCKET client_sock = accept(server_sock, (sockaddr*)&client, &client_size);
if (client_sock == INVALID_SOCKET) {
std::cerr << WSAGetLastError() << std::endl;
closesocket(server_sock);
WSACleanup();
exit(EXIT_FAILURE);
}
else {
futures.emplace_back(std::async(std::launch::async, &handle_client, client_sock, client));
if (futures.size() >= CLIENTS_MAX_NUM && listening) {
std::cout << "closing server socket" << std::endl;
close_server_socket(listening);
}
std::cout << futures.size() << " clients connected" << std::endl;
}
}
}
}
// ----------------------------------------------------------
std::cout << "bye!" << std::endl;
WSACleanup();
exit(EXIT_SUCCESS);
}
After some digging I found a couple silly errors, below is the working code:
update
Also fixed the vector loop
#include <iostream>
#include <vector>
#include <string>
#include <future>
#include <chrono>
#include <WS2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
static constexpr const unsigned int PORT = 5000;
static constexpr const unsigned int CLIENTS_MAX_NUM = 5;
static constexpr const unsigned int CLIENTS_QUEUE_NUM = 0;
void handle_client(SOCKET client_sock, sockaddr_in client) {
char buf[4096];
char host[NI_MAXHOST];
char service[NI_MAXHOST];
memset(host, 0, NI_MAXHOST);
memset(service, 0, NI_MAXHOST);
//std::cout << std::this_thread::get_id() << std::endl;
if (getnameinfo((sockaddr*)&client, sizeof(client), host, NI_MAXHOST, service, NI_MAXSERV, 0) == 0) {
std::cout << host << " connected on port " << service << std::endl;
}
else {
inet_ntop(AF_INET, &client.sin_addr, host, NI_MAXHOST);
std::cout << host << " connected on port " << ntohs(client.sin_port) << std::endl;
}
while (true) {
memset(&buf, 0, 4096);
const int bytes_received = recv(client_sock, buf, 4096, 0);
if (bytes_received == SOCKET_ERROR) {
std::cerr << WSAGetLastError() << std::endl;
WSACleanup();
}
else if (bytes_received == 0) {
std::cout << "client disconnected" << std::endl;
break;
}
else {
send(client_sock, buf, bytes_received + 1, 0);
}
}
}
void initialize_winsock() {
WSAData wsData;
WORD ver = MAKEWORD(2, 2);
int wsResult = WSAStartup(ver, &wsData);
if (wsResult != 0) {
std::cerr << WSAGetLastError() << std::endl;
WSACleanup();
exit(EXIT_FAILURE);
}
}
void bind_server_socket(SOCKET &server_sock) {
int keep_alive = 1;
int re_use = 1;
if (setsockopt(server_sock, SOL_SOCKET, SO_KEEPALIVE, (const char*)&keep_alive, sizeof(keep_alive)) == SOCKET_ERROR) {
closesocket(server_sock);
WSACleanup();
exit(EXIT_FAILURE);
}
if (setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&re_use, sizeof(re_use)) == SOCKET_ERROR) {
closesocket(server_sock);
WSACleanup();
exit(EXIT_FAILURE);
}
sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(PORT);
server.sin_addr.S_un.S_addr = INADDR_ANY;
memset(&server.sin_zero, 0, 8);
if (bind(server_sock, (sockaddr*)&server, sizeof(sockaddr)) == SOCKET_ERROR) {
std::cerr << WSAGetLastError() << std::endl;
closesocket(server_sock);
WSACleanup();
exit(EXIT_FAILURE);
}
}
void open_server_socket(SOCKET &server_sock, bool &accepting) {
server_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (server_sock == INVALID_SOCKET) {
std::cerr << WSAGetLastError() << std::endl;
accepting = false;
WSACleanup();
exit(EXIT_FAILURE);
}
accepting = true;
}
void close_server_socket(SOCKET &server_sock, bool &accepting) {
closesocket(server_sock);
accepting = false;
}
void clear_futures(std::vector<std::future<void>> &futures) {
std::vector<std::future<void>>::iterator it = futures.begin();
while (it != futures.end()) {
auto status = (*it).wait_for(std::chrono::milliseconds(0));
if (status == std::future_status::ready) {
it = futures.erase(it);
}
else {
++it;
}
}
}
void wait_for_connections(std::vector<std::future<void>> &futures, SOCKET &server_sock, bool& accepting) {
if (listen(server_sock, CLIENTS_QUEUE_NUM) == SOCKET_ERROR) {
std::cerr << WSAGetLastError() << std::endl;
closesocket(server_sock);
WSACleanup();
exit(EXIT_FAILURE);
}
else {
std::cout << "accepting for incoming connections on port " << PORT << std::endl;
while (true) {
if (futures.size() < CLIENTS_MAX_NUM && !accepting) {
std::cout << "re-opening server socket" << std::endl;
open_server_socket(server_sock, accepting);
bind_server_socket(server_sock);
wait_for_connections(futures, server_sock, accepting);
break;
}
if (accepting) {
sockaddr_in client;
memset(&client.sin_zero, 0, 8);
int client_size = sizeof(client);
SOCKET client_sock = accept(server_sock, (sockaddr*)&client, &client_size);
if (client_sock == INVALID_SOCKET) {
std::cerr << WSAGetLastError() << std::endl;
closesocket(server_sock);
WSACleanup();
exit(EXIT_FAILURE);
}
clear_futures(futures);
futures.emplace_back(std::async(std::launch::async, &handle_client, client_sock, client));
if (futures.size() >= CLIENTS_MAX_NUM && accepting) {
std::cout << "closing server socket" << std::endl;
close_server_socket(server_sock, accepting);
}
std::cout << futures.size() << " clients connected" << std::endl;
}
}
}
}
int main(int argc, const char* argv[]) {
std::vector<std::future<void>> futures;
bool accepting = false;
SOCKET server_sock;
initialize_winsock();
open_server_socket(server_sock, accepting);
bind_server_socket(server_sock);
wait_for_connections(futures, server_sock, accepting);
std::cout << "bye!" << std::endl;
WSACleanup();
exit(EXIT_SUCCESS);
}

std::Invoke, No matching overloaded function found

I'm trying to create a thread that handles client-server communication using a socket in C++.
The program throws an error
std::Invoke, No matching overloaded function found
Error C2893 Failed to specialize function template 'unknown-type std::invoke(_Callable &&,_Types &&...) noexcept(<expr>)'
I'm unable to debug the program since it crashes at startup.
Is there anything wrong in thread initialization with two parameters? Or am I missing some library, class import?
Can anyone help me out, what am I missing here?
Here's my code
#include <ws2tcpip.h>
#include <iostream>
#include <string>
#include <thread>
using namespace std;
#pragma comment (lib, "Ws2_32.lib")
#define DEFAULT_BUFLEN 512
PCSTR IP_ADDRESS = "192.168.1.100";
#define DEFAULT_PORT "3504"
struct client_type
{
SOCKET socket;
int id;
char received_message[DEFAULT_BUFLEN];
};
int process_client(client_type& new_client);
int main();
int process_client(client_type& new_client)
{
while (1)
{
memset(new_client.received_message, 0, DEFAULT_BUFLEN);
if (new_client.socket != 0)
{
int iResult = recv(new_client.socket, new_client.received_message, DEFAULT_BUFLEN, 0);
if (iResult != SOCKET_ERROR)
cout << new_client.received_message << endl;
else
{
//cout << "recv() failed: " << WSAGetLastError() << endl;
break;
}
}
}
if (WSAGetLastError() == WSAECONNRESET)
cout << "The server has disconnected" << endl;
return 0;
}
int main()
{
WSAData wsa_data;
struct addrinfo* result = NULL, * ptr = NULL, hints;
string sent_message = "";
client_type client = { INVALID_SOCKET, -1, "" };
int iResult = 0;
string message;
cout << "Starting Client...\n";
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsa_data);
if (iResult != 0) {
cout << "WSAStartup() failed with error: " << iResult << endl;
return 1;
}
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
cout << "Connecting...\n";
// Resolve the server address and port
iResult = getaddrinfo(IP_ADDRESS, DEFAULT_PORT, &hints, &result);
if (iResult != 0) {
cout << "getaddrinfo() failed with error: " << iResult << endl;
WSACleanup();
system("pause");
return 1;
}
// Attempt to connect to an address until one succeeds
for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {
// Create a SOCKET for connecting to server
client.socket = socket(ptr->ai_family, ptr->ai_socktype,
ptr->ai_protocol);
if (client.socket == INVALID_SOCKET) {
cout << "socket() failed with error: " << WSAGetLastError() << endl;
WSACleanup();
system("pause");
return 1;
}
// Connect to server.
iResult = connect(client.socket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (iResult == SOCKET_ERROR) {
closesocket(client.socket);
client.socket = INVALID_SOCKET;
continue;
}
break;
}
freeaddrinfo(result);
if (client.socket == INVALID_SOCKET) {
cout << "Unable to connect to server!" << endl;
WSACleanup();
system("pause");
return 1;
}
cout << "Successfully Connected" << endl;
//Obtain id from server for this client;
recv(client.socket, client.received_message, DEFAULT_BUFLEN, 0);
message = client.received_message;
if (message != "Server is full")
{
client.id = atoi(client.received_message);
thread my_thread(process_client, client);
while (1)
{
getline(cin, sent_message);
iResult = send(client.socket, sent_message.c_str(), strlen(sent_message.c_str()), 0);
if (iResult <= 0)
{
cout << "send() failed: " << WSAGetLastError() << endl;
break;
}
}
//Shutdown the connection since no more data will be sent
my_thread.detach();
}
else
cout << client.received_message << endl;
cout << "Shutting down socket..." << endl;
iResult = shutdown(client.socket, SD_SEND);
if (iResult == SOCKET_ERROR) {
cout << "shutdown() failed with error: " << WSAGetLastError() << endl;
closesocket(client.socket);
WSACleanup();
system("pause");
return 1;
}
closesocket(client.socket);
WSACleanup();
system("pause");
return 0;
}```
I boiled your program down to a minimal, reproducible example:
#include <thread>
struct client_type
{
};
int process_client(client_type& new_client)
{
return 0;
}
int main()
{
client_type client;
std::thread my_thread(process_client, client);
}
This small snippet fails to compile, and trying to compile gives the error you mention.
Why does this fail? Lets look at the std::thread constructor. In the notes section we find this:
The arguments to the thread function are moved or copied by value. If
a reference argument needs to be passed to the thread function, it has
to be wrapped (e.g., with std::ref or std::cref).
And indeed std::thread my_thread(process_client, std::ref(client)); compiles without issue.

advise for safely using remote client without exhausting ports

I am working on a remote client program for Windows that sends data from a sensor unit to a server application over ethernet / internet connection. The client logs into the server with a username and password. Per the protocol the client then sends data one way to the server without ever expecting a response from the server. All works fine untill the wireless internet connection at a client gets broken. In my first version of the client I retried making a connect attept each loop but very often would run out of ports as Windows standard timeout was 4 minutes. I tried changing one client the other day. I set Windows registry to "TcpTimedWaitDelay" to 1 and rewrote the client app to close its socket on error then wait 1 second before attempting a reconnect. This seemed to be working but I did loose that client for a while today. I can't be certain if the wireless went down for the whole time it was offline or not.
I'm looking for advise on a good method when using this type of client that can be used reliably. Is there another way to prevent port exhaustion within the application code or is modifing Windows registry almost always needed? I can add pieces of my code but I have gone over my code itself in a recent question here. I'm looking for a more broad suggestion here.
void checkConnect(NTRIP& server)
{
time_f functionTime = getTimePrecise();
//1st check for recv or gracefully closed socket
char databuf[SERIAL_BUFFERSIZE];
fd_set Reader, Writer, Err;
TIMEVAL Timeout;
Timeout.tv_sec = 1; // timeout after 1 seconds
Timeout.tv_usec = 0;
FD_ZERO(&Reader);
FD_ZERO(&Err);
FD_SET(server.socket, &Reader);
FD_SET(server.socket, &Err);
int iResult = select(0, &Reader, NULL, &Err, &Timeout);
if(iResult > 0)
{
if(FD_ISSET(server.socket, &Reader) )
{
int recvBytes = recv(server.socket, databuf, sizeof(databuf), 0);
if(recvBytes == SOCKET_ERROR)
{
cout << "socket error on receive call from server " << WSAGetLastError() << endl;
closesocket(server.socket);
server.connected_IP = false;
}
else if(recvBytes == 0)
{
cout << "server closed the connection gracefully" << endl;
closesocket(server.socket);
server.connected_IP = false;
}
else //>0 bytes were received so read data if needed
{
cout << "received " << recvBytes << " bytes of data" << endl;
}
}
if(FD_ISSET(server.socket, &Err))
{
cout << "ip thread select returned socket in error group" << endl;
closesocket(server.socket); //what if dont close this socket, leave open for another loop
server.connected_IP = false;
}
}
else if(iResult == SOCKET_ERROR)
{
cout << "ip thread select returned SOCKET_ERROR " << WSAGetLastError() << endl;
closesocket(server.socket);
server.connected_IP = false;
}
//2nd check hard disconnect
if(server.connected_IP == true && functionTime - timer_send_keepalive >= 15.0)
{
timer_send_keepalive = functionTime;
char buf1[] = "hello";
cout << "checking send for error" << endl;
iResult = send(server_main.socket, buf1, sizeof(buf1), 0);
if(iResult == SOCKET_ERROR)
{
int lasterror = WSAGetLastError();
if(lasterror == WSAEWOULDBLOCK)
{
cout << "server send WSAEWOULDBLOCK" << endl;
}
else if(lasterror != WSAEWOULDBLOCK)
{
cout << "server testing connection send function error " << lasterror << endl;
closesocket(server.socket);
server.connected_IP = false;
}
}
else
{
cout << "sent out keep alive " << iResult << " bytes" << endl;
}
}//end send keep alive
}
send function
bool sendData(CHAR_MESSAGE& data)
{
bool check = false;
if(data.flag_toSend == true)
{
if(WaitForSingleObject(data.mutex, 0) != WAIT_FAILED)
{
if(server_main.connected_IP == true)
{
int iResult = send(server_main.socket, data.buffer, data.bufferLength, 0);
if(iResult == SOCKET_ERROR)
{
int lasterror = WSAGetLastError();
if(lasterror == WSAEWOULDBLOCK)
{
cout << "main server send WSAEWOULDBLOCK" << endl;
check = false;
}
if(lasterror != WSAEWOULDBLOCK)
{
cout << "server main send error " << lasterror << endl;
closesocket(server_main.socket);
server_main.connected_IP = false;
check = false;
}
}
else
{
check = true;
server_main.lastDataSendTime = getTimePrecise();
//{cout << "sent data to main server" << endl;}
}
}
if(server_backup.connected_IP == true)
{
int iResult = send(server_backup.socket, data.buffer, data.bufferLength, 0);
if(iResult == SOCKET_ERROR)
{
int lasterror = WSAGetLastError();
if(lasterror == WSAEWOULDBLOCK)
{
cout << "backup server send WSAEWOULDBLOCK" << endl;
//check = false;
}
if(lasterror != WSAEWOULDBLOCK)
{
cout << "server backup send error " << lasterror << endl;
closesocket(server_backup.socket);
server_backup.connected_IP = false;
}
}
else
{
server_backup.lastDataSendTime = getTimePrecise();
//{cout << "sent data to backup server" << endl;}
}
}
data.flag_toSend = false;
ReleaseMutex(data.mutex);
}//end obtained mutex
}//end data flag to send is true
return check;
}
login function
bool loginServer(NTRIP& datasource )
{
std::string sLogin = buildLogin(datasource);
char databuf[1030];
int iResult = send(datasource.socket, sLogin.c_str(), sLogin.length(), 0);
if(iResult == SOCKET_ERROR)
{
cout << "Send error = " << WSAGetLastError() << endl;
closesocket(datasource.socket);
return false;
}
else //not socket error
{
int flags = 0;
fd_set Read, Err;
TIMEVAL Timeout;
FD_ZERO(&Read);
FD_ZERO(&Err);
FD_SET(datasource.socket, &Read);
FD_SET(datasource.socket, &Err);
Timeout.tv_sec = 1;
Timeout.tv_usec = 0;
iResult = select(0, &Read, NULL, &Err, &Timeout);
if(iResult == 0)
{
cout << "loginServer function, select timeout" << endl;
closesocket(datasource.socket);
return false;
}
else if(FD_ISSET(datasource.socket, &Read) )
{
int recvBytes = recv(datasource.socket, databuf, sizeof(databuf), flags);
if(recvBytes == SOCKET_ERROR)
{
cout << "loginServer function, Error recv call " << WSAGetLastError() << endl;
closesocket(datasource.socket);
return false;
}
else if(recvBytes == 0) //server closed connection
{
cout << "loginServer function, server reclosed connection" << endl;
closesocket(datasource.socket);
return false;
}
else if(recvBytes > 0) //process response
{
std::string tempString;
for(int n=0; n<recvBytes; n++)
{
tempString += databuf[n];
}
if(tempString.compare(CONNECT_OK) || tempString.compare(HTTP_OK) )
{
cout << "server connected" << endl;
return true;
}
else if(tempString.compare(ERROR_1))
{
MessageBox(NULL, ERROR_1, "NTRIP connect Error", MB_OK);
closesocket(datasource.socket);
return false;
}
else if(tempString.compare(ERROR_2))
{
MessageBox(NULL, ERROR_2, "NTRIP connect Error", MB_OK);
closesocket(datasource.socket);
return false;
}
else if(tempString.compare(ERROR_3))
{
MessageBox(NULL, ERROR_3, "NTRIP connect Error", MB_OK);
closesocket(datasource.socket);
return false;
}
else if(tempString.compare(ERROR_4))
{
MessageBox(NULL, ERROR_4, "NTRIP connect Error", MB_OK);
closesocket(datasource.socket);
return false;
}
}
}
else if(FD_ISSET(socket, &Err) )
{
cout << "loginServer function, select call error" << endl;
closesocket(datasource.socket);
return false;
}
}//end not socket error on send login
closesocket(datasource.socket);
return false;
}
open a new socket
bool clientOpenSocket_connectServer(SOCKET& Socket, const char* serverADDR, const char* serverPORT)
{
int check;
if(Socket != INVALID_SOCKET) //if not closed then close socket
{
closesocket(Socket);
Socket = INVALID_SOCKET;
}
time_f timer = getTimePrecise();
while(getTimePrecise() - timer < 5.0){} //wait 5 second before reconnect attempt
//set Windows reg to 1 second TcpTimedWaitDelay
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET; //use IPv4
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
//get socket memory address info
check = getaddrinfo(serverADDR , serverPORT, &hints, &result);
if ( check != 0)
{
printf("Winsock getaddrinfo failed. %d\n", WSAGetLastError());
return false;
}
//prepare socket, sets IP4 or IP6, sock type and protocol used
for(ptr=result; ptr!=NULL; ptr=ptr->ai_next)
{
Socket = socket( result->ai_family, result->ai_socktype, result->ai_protocol);
if (Socket == INVALID_SOCKET)
{
printf("Socket failed initializing %d %d.\n", Socket, WSAGetLastError());
freeaddrinfo (result);
return false;
}
//now have a valid socket
check = ioctlsocket(Socket, FIONBIO, &NonBlock);
if (check == SOCKET_ERROR)
{
printf("client socket could not set nonblocking, with error: %d\n", WSAGetLastError());
closesocket(Socket);
freeaddrinfo(result);
return false;
}
//set sockets to no-linger on close
char value = 0;
check = setsockopt( Socket, SOL_SOCKET, SO_DONTLINGER, &value, sizeof( value ) );
if (check == SOCKET_ERROR)
{
cout << "client socket could not set options no-linger " << WSAGetLastError() << endl;
}
//disable nagle algorithym
if(disableNagleSockets == true)
{
value = 1;
check = setsockopt( Socket, IPPROTO_TCP, TCP_NODELAY, &value, sizeof( value ) );
if (check == SOCKET_ERROR)
{
cout << "client socket could not set options " << WSAGetLastError() << endl;
}
else{cout << "Nagle Sockets set disabled" << endl;}
value = 0;
check = setsockopt( Socket, IPPROTO_TCP, SO_SNDBUF, &value, sizeof( value ) );
if (check == SOCKET_ERROR)
{
cout << "client socket could not set options " << WSAGetLastError() << endl;
}
}
//attempt connect
cout << "attempting connect" << endl;
check = connect(Socket, ptr->ai_addr, ptr->ai_addrlen);
if(check == SOCKET_ERROR )
{
check = WSAGetLastError();
if(check == WSAEWOULDBLOCK) // then set a timeout
{
fd_set Write, Err;
TIMEVAL Timeout;
int TimeoutSec = 10; // timeout after 10 seconds
FD_ZERO(&Write);
FD_ZERO(&Err);
FD_SET(Socket, &Write);
FD_SET(Socket, &Err);
Timeout.tv_sec = TimeoutSec;
Timeout.tv_usec = 0;
check = select(0, NULL, &Write, &Err, &Timeout);
if(check == 0)
{
printf("connect call to server, select call timeout elapsed\r\n");
closesocket(Socket);
freeaddrinfo(result);
return false;
}
else
{
if(FD_ISSET(Socket, &Write) )
{
freeaddrinfo(result);
cout << "socket opened to server, after wait" << endl;
return true;
}
if(FD_ISSET(Socket, &Err) )
{
printf("connect call to server, select call error state\r\n");
closesocket(Socket);
freeaddrinfo(result);
return false;
}
}
}
else if(check == WSAECONNREFUSED)
{
cout << "no server program at requested address " << serverADDR << endl;
closesocket(Socket);
freeaddrinfo(result);
return false;
}
else if(check == WSAEHOSTDOWN || check == WSAETIMEDOUT)
{
cout << "no server present at requested address " << serverADDR << endl;
closesocket(Socket);
freeaddrinfo(result);
return false;
}
else
{
cout << "connect call WSA error code " << check << endl;
closesocket(Socket);
freeaddrinfo(result);
return false;
}
}//end socket error
//else instant connection is good
cout << "socket opened to server" << endl;
freeaddrinfo(result);
return true;
}//end search for a socket address to use
freeaddrinfo(result); //no socket opened here
return false;
}//end of setup TCP port
So as of now it waits 5 seconds snce the last failed connection before attempting another. My earlier version tried a new connection each loop untill it connected. It seems right now that it may be working with the 5 second delay and setting Windows registry to close a port after 1 second.
Use the connection until it breaks, and then create another one.
If it breaks so often that you encounter port exhaustion you have a network problem, not a programming problem.
If you get a connect error you should sleep for increasing amounts of time on each failure, e.g. 1,2,4,8,... seconds.

Winsock single client server send and receive simultaneously

I have a problem with simple Winsock chat application in C++. I've written a code that enables the user to choose if he wants to send data or receive the data and depending on users choice, the appropriate functions are executed. What I would like to achieve, is that the user can BOTH send and receive data. How could I approach it? Please note that I don't want to use multiple client, I just want to send and receive data by server and send and receive data by client simultaneously.
Edit: I added my code.
#include <WinSock2.h>
#include <Windows.h>
#include <iostream>
#include <string>
#include <stdio.h>
#include <ctime>
int main()
{
string IP;
int userType;
// Ask the user if he is server or client
cout << "Hi, which type of user are you? 1 - Server, 2 - Client" <<endl;
cin >> userType;
// depending on the declared user type, execute the appropriate code
if (userType == 1)
{
//initialize winsock and create a socket
WSAData wsaData; // initialize
iResult = WSAStartup(MAKEWORD(2,1), &wsaData);
if (iResult != NO_ERROR) // check for errors
cout << "Error at WSAStartup()" <<endl;
else
cout << "WSAStartup() is OK." <<endl;
// create socket
sockSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); // create a socket
if (sockSocket == INVALID_SOCKET) // check for errors
{
cout << "Error at socket(): " << WSAGetLastError();
WSACleanup();
return true;
}
else
cout << "Socket() is OK." <<endl;
return true;
// bind to socket
service.sin_addr.s_addr = inet_addr("0.0.0.0");
service.sin_family = AF_INET;
service.sin_port = htons(55555);
if (bind(sockSocket, (SOCKADDR*)&service, sizeof(service)) == SOCKET_ERROR) // cheking for errors
{
cout << "Bind() failed." << endl;
closesocket(sockSocket);
return true;
}
else
cout << "Bind() is OK." <<endl;
// listen
listen(sockSocket, SOMAXCONN);
if (listen(sockSocket, 10) == SOCKET_ERROR) // check for errors
{
cout << "Error listening on socket." << endl;
return true;
}
else
cout << "Listen() is OK." <<endl;
//accept connection
servlen = sizeof(service);
cout << "Waiting for user to connect..." << endl;
acceptSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(acceptSocket = accept(sockSocket, (SOCKADDR*)&service, &servlen))
{
cout << "A coonnection was found" <<endl<<endl;
}
sockSocket = acceptSocket;
// receive messages
do
{
std::string message;
char Buffer[512];
iResult = recv(sockSocket, Buffer, 512, 0);
Buffer[iResult] = '\0';
message = Buffer;
currentDate();
std::cout << Buffer <<endl<<endl;
}while(iResult>0);
closesocket(sockSocket);
WSACleanup();
}
else if (userType == 2)
{
// exactly the same code as for server part to initialize and create socket
// ask for the ip the user wants to connect to
cout << "Hi what's the IP that you want to connect to?" <<endl;
cin >> IP;
// connect to socket
conService.sin_addr.s_addr = inet_addr(IP); // connect to the ipnuted IP
conService.sin_family = AF_INET;
conService.sin_port = htons(55555); // should the port also be the argument?
if (connect(sockSocket, (SOCKADDR*)&conService, sizeof(conService)) == SOCKET_ERROR) // check for errors
{
cout << "Failed to connect: " << WSAGetLastError();
WSACleanup();
return true;
}
else
{
cout << "Connected." <<endl;
}
// send messages
for (;;)
{
std::string message;
std::getline(std::cin, message);
unsigned int Length = strlen(message.c_str());
if(Length>512)
Length = 512;
currentDate();
iResult = send(sockSocket, message.c_str(),Length,0);
}
closesocket(sockSocket);
WSACleanup();
}
WSACleanup();
return 0;
}
Edit2: As Lemy suggested in the comment, I need to have a second thread (as the first one is simply what's going on in the main function). From what I understood, I can use CreateThread function. My problem of how to both send and receive messages is solved (I should create another thread), but now I have problem with implementing the solution. As I wrote in the comment below Lemy's answer, I get such error referring to the line where I use CreateThread function (HANDLE hThread = CreateThread(0,0,&ReadingThread,acceptSocket,0,&dwThreadID);):
invalid conversion from 'SOCKET {aka unsigned int}' to 'PVOID {aka void*}' [-fpermissive]| and
invalid conversion from 'DWORD {aka long unsigned int}' to 'PDWORD {aka long unsigned int*}' [-fpermissive]
Any hints for that? Hope this makes my question more specific(if not pls tell me what should I specify more).
You need to have the client and server continuously reading in the background for the lifetime of the connection, and then they can send data in parallel whenever needed. Move your reading logic into a separate thread, eg:
#include <WinSock2.h>
#include <Windows.h>
#include <iostream>
#include <string>
#include <stdio.h>
#include <ctime>
DWORD WINAPI ReadingThread(LPVOID param)
{
SOCKET s = (SOCKET) param;
char Buffer[512];
int iResult;
do
{
iResult = recv(s, Buffer, 512, 0);
if (iResult <= 0) break;
Buffer[iResult] = '\0';
std::cout << "Recv: " << message << std::endl;
}
while (true);
return 0;
}
int main()
{
int userType;
HANDLE hThread;
DWORD dwThreadID;
//initialize winsock and create a socket
WSAData wsaData; // initialize
iResult = WSAStartup(MAKEWORD(2,1), &wsaData);
if (iResult != NO_ERROR) // check for errors
{
std::cout << "Error at WSAStartup()" << std::endl;
return 0;
}
std::cout << "WSAStartup() is OK." << std::endl;
// Ask the user if he is server or client
std::cout << "Hi, which type of user are you? 1 - Server, 2 - Client" << std::endl;
std::cin >> userType;
// depending on the declared user type, execute the appropriate code
if (userType == 1)
{
// create socket
sockSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); // create a socket
if (sockSocket == INVALID_SOCKET) // check for errors
{
std::cout << "Error at socket(): " << WSAGetLastError() << std::endl;
WSACleanup();
return 0;
}
std::cout << "Socket() is OK." << std::endl;
// bind to socket
service.sin_addr.s_addr = INADDR_ANY;
service.sin_family = AF_INET;
service.sin_port = htons(55555);
if (bind(sockSocket, (SOCKADDR*)&service, sizeof(service)) == SOCKET_ERROR) // cheking for errors
{
std::cout << "Error at bind(): " << WSAGetLastError() << std::endl;
closesocket(sockSocket);
WSACleanup();
return 0;
}
std::cout << "Bind() is OK." << std::endl;
// listen
if (listen(sockSocket, 10) == SOCKET_ERROR) // check for errors
{
std::cout << "Error at listen(): " << WSAGetLastError() << std::endl;
closesocket(sockSocket);
WSACleanup();
return 0;
}
std::cout << "Listen() is OK." << std::endl;
//accept connection
servlen = sizeof(service);
std::cout << "Waiting for user to connect..." << std::endl;
acceptSocket = accept(sockSocket, (SOCKADDR*)&service, &servlen);
if (acceptSocket != INVALID_SOCKET)
{
std::cout << "Error at accept(): " << WSAGetLastError() << std::endl;
closesocket(sockSocket);
WSACleanup();
return 0;
}
std::cout << "A client has connected" << std::endl << std::endl;
// receive messages
hThread = CreateThread(NULL, 0, &ReadingThread, (void*)acceptSocket, 0, &dwThreadID);
if (!hThread)
{
std::cout << "Error at CreateThread(): " << GetLastError() << std::endl;
closesocket(acceptSocket);
closesocket(sockSocket);
WSACleanup();
return 0;
}
// send messages
do
{
std::string message;
if (!std::getline(std::cin, message))
break;
if (send(acceptSocket, msg.c_str(), msg.length(), 0) == SOCKET_ERROR)
{
std::cout << "Error at send(): " << WSAGetLastError() << std::endl;
break;
}
}
while (true);
closesocket(acceptSocket);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
closesocket(sockSocket);
WSACleanup();
}
else if (userType == 2)
{
// create socket
sockSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); // create a socket
if (sockSocket == INVALID_SOCKET) // check for errors
{
std::cout << "Error at socket(): " << WSAGetLastError() << std::endl;
WSACleanup();
return 0;
}
std::cout << "Socket() is OK." << std::endl;
// ask for the ip the user wants to connect to
std::string IP;
std::cout << "Hi what's the IP that you want to connect to?" << std::endl;
std::cin >> IP;
// connect to socket
conService.sin_addr.s_addr = inet_addr(IP.c_str()); // connect to the ipnuted IP
conService.sin_family = AF_INET;
conService.sin_port = htons(55555); // should the port also be the argument?
if (connect(sockSocket, (SOCKADDR*)&conService, sizeof(conService)) == SOCKET_ERROR) // check for errors
{
std::cout << "Failed to connect: " << WSAGetLastError() << std::endl;
closesocket(sockSocket);
WSACleanup();
return 0;
}
std::cout << "Connected." << std::endl;
// receive messages
hThread = CreateThread(NULL, 0, &ReadingThread, (void*)sockSocket, 0, &dwThreadID);
if (!hThread)
{
std::cout << "Error at CreateThread(): " << GetLastError() << std::endl;
closesocket(sockSocket);
WSACleanup();
return 0;
}
// send messages
do
{
std::string message;
if (!std::getline(std::cin, message))
break;
if (send(sockSocket, msg.c_str(), msg.length(), 0) == SOCKET_ERROR)
{
std::cout << "Error at send(): " << WSAGetLastError() << std::endl;
break;
}
}
while (true);
closesocket(sockSocket);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
WSACleanup();
}
else
{
std::cout << "Invalid type entered!" << std::endl;
WSACleanup();
return 0;
}
return 0;
}

Winsock C++ Proxy

I'm trying to get this code to work:
#include <stdio.h>
#include <tchar.h>
#include <iostream>
#include <WinSock2.h>
#pragma comment( lib, "ws2_32.lib" )
#include <Windows.h>
using namespace std;
int port = 5012;
SOCKET listen_sock;
SOCKET client_sock;
char FR_recv_buf [1048576] = "";
char recv_buf [102400] = "";
int Receive();
int Listen();
//function to initialize winsock
bool InitializeWinsock()
{
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if(iResult != 0)
{
cout << "WSAStartup failed with error: " << iResult << endl;
return false;
}
else
{
cout << "WSAStartup successfully initialized." << endl;
return true;
}
}
int ForwardResponse()
{
if (send(client_sock, FR_recv_buf, sizeof(FR_recv_buf), 0) == SOCKET_ERROR)
{
cout << "Forward Response: send() failed with error: " << WSAGetLastError() << endl;
closesocket(client_sock);
//WSACleanup();
return 0;
}
else
{
cout << "Forward Response: send() success.\n";
//go back to begginning again?
Receive();
//CreateThread(0,0,(LPTHREAD_START_ROUTINE)Receive, 0, 0 ,0);
}
}
//Function to parse hostname from http request
string ParseHostname(char * buf)
{
size_t pos;
//string to hold hostname substring
string hostname_t;
//copy request to string for easier parsing
string httpheader = buf;
pos = httpheader.find("Host: ");//find "Host: " line
hostname_t = httpheader.substr(pos + 6);//copy to substring, not including "Host: ", just the hostname
pos = hostname_t.find("\r\n");// find end of line
hostname_t.erase(pos);//erase the rest of the string which is unwanted
return hostname_t;
}
//Function to forward HTTP request from browser to webserver
int ForwardRequest()
{
int bytes_received;
SOCKADDR_IN Dest;
SOCKET frecv_sock;
hostent *Host;
//parse hostname from http request
string hostname = ParseHostname(recv_buf);
if((Host=gethostbyname(hostname.c_str()))==NULL)
{
DWORD dwError = WSAGetLastError();
if (dwError != 0)
{
if(dwError == WSAHOST_NOT_FOUND)
{
cout << "Host " << hostname.c_str() << " not found.\n";
WSACleanup();
return FALSE;
}
else if (dwError == WSANO_DATA)
{
cout << "No data record found.\n";;
WSACleanup();
return FALSE;
}
else
{
cout << "Function failed with error: " << dwError << endl;
WSACleanup();
return FALSE;
}
}
}
else
{
cout << "Successfully connected to host: " << hostname.c_str() << endl;
//privmsg(wsockdl.sock,sendbuf,curchan);
}
Dest.sin_family=AF_INET;
Dest.sin_port=htons(80);
memcpy(&Dest.sin_addr,Host->h_addr,Host->h_length);
// Create a SOCKET for connecting to server
if((frecv_sock = socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET)
{
cout << "Forward Request: Error at socket(), error code: " << WSAGetLastError() << endl;
closesocket(frecv_sock);
WSACleanup();
return FALSE;
}
// Connect to server
if(connect( frecv_sock,(SOCKADDR*)&Dest,sizeof(Dest))==SOCKET_ERROR)
{
cout << "Forward Request: connect() failed, error code: " << WSAGetLastError() << endl;
closesocket( frecv_sock);
WSACleanup();
return FALSE;
}
//send intercepted request to server
if (send(frecv_sock, recv_buf, strlen(recv_buf), 0) == SOCKET_ERROR)
{
cout << "Forward Request: send() failed with error: " << WSAGetLastError() << endl;
closesocket(frecv_sock);
WSACleanup();
return 0;
}
else
{
cout << "Forward Request: send() success.\n";
}
//receive request from server
do{
bytes_received = recv(frecv_sock,FR_recv_buf,sizeof(FR_recv_buf),0);
if (bytes_received > 0){
strcat (FR_recv_buf, "\0");
cout << "Forward Request: recv() success. Bytes received: " << bytes_received << endl;
CreateThread(0, 0, (LPTHREAD_START_ROUTINE)ForwardResponse, 0 ,0 ,0);
//ForwardResponse();
}
else if ( bytes_received == 0 ){
cout << "Forward Request: Connection closed\n";
closesocket(frecv_sock);
}
else if ( bytes_received == SOCKET_ERROR){
cout << "Forward Request: recv() failed with error: " << WSAGetLastError() << endl;
closesocket(frecv_sock);
WSACleanup();
return 0;
}
}while (bytes_received > 0);
}
//Function to accept connection and receive data from browser
int Receive()
{
SOCKADDR_IN csin;
int csin_len = sizeof(csin);
int iResult;
//accept client connection
client_sock = accept(listen_sock , (LPSOCKADDR)&csin, &csin_len);//pauses here to wait for connection from client
if (client_sock == INVALID_SOCKET) {
cout << "accept failed with error: "<< WSAGetLastError() << endl;
closesocket(client_sock);
WSACleanup();
return 1;
}
else{
cout << "Client connection from IP: " << inet_ntoa(csin.sin_addr) << ":" << csin.sin_port << endl;
}
CreateThread(0, 0 , (LPTHREAD_START_ROUTINE)Receive, 0 , 0 ,0); //Start another thread to accept.
do {
iResult = recv(client_sock, recv_buf, sizeof(recv_buf), 0);
if (iResult == SOCKET_ERROR) {
closesocket(client_sock);
WSACleanup();
cout << "Receive: recv() failed with error: "<< WSAGetLastError() << endl;
}
else if (iResult > 0){
//null terminate receive buffer
//recv_buf[iResult] = '\0';
strcat(recv_buf, "\0");
cout <<"Receive: Bytes received: " << iResult << endl;
//forward HTTP request from browser to web server
cout << recv_buf << endl;
HANDLE pChildThread = CreateThread(0, 0 , (LPTHREAD_START_ROUTINE)ForwardRequest, 0 , 0 ,0);
WaitForSingleObject(pChildThread,60000); //Wait for connection between proxy and remote server
CloseHandle(pChildThread);
}
else if ( iResult == 0 ){
cout << "Receive: Connection closed\n";
}
}while ( iResult > 0 );
return 0;
}
//Function which listens for incoming connections to the proxy
int Listen()
{
SOCKADDR_IN local;
memset(&local,0,sizeof(local));
local.sin_family = AF_INET;
local.sin_port = htons(port);
local.sin_addr.s_addr = INADDR_ANY;
//create socket for listening to
listen_sock = socket(AF_INET, SOCK_STREAM, 0);
//bind function associates a local address with a socket.
if (bind(listen_sock, (LPSOCKADDR)&local, sizeof(local)) == 0)
{
if (listen(listen_sock, 10) == 0)
{
cout << "Listening on: " << port << endl;
}
else
{
cout << "Error listening on socket.\n";
}
}
else{
cout << "bind() failed with error: "<< WSAGetLastError() << endl;
}
//accept and start receiving data from broswer
CreateThread(0, 0 , (LPTHREAD_START_ROUTINE)Receive, 0 , 0 ,0);
return 0;
}
int CloseServer()
{
closesocket(client_sock);
WSACleanup();
return 1;
}
int _tmain(int argc, _TCHAR* argv[])
{
InitializeWinsock();
Listen();
cin.get();
return 0;
}
But it seems like the connection ends too early, or the recv() or send() functions fail. Nothing is displayed on my browser except that it couldn't connect. Can anyone spot the problem?
One major problem is that you only have one client socket. Each thread you create share the same client socket so if two connections are made before the first one is done, the first socket will be over-written with the second connection. Remember that threads share all memory in the process, including things like global variables.
Edit: Since you are using C++, why don't you encapsulate variables and functions in a class? And instead of allocating memory for buffers statically like you do, create them on the heap with new.
Edit 2
Simple multi-threaded server:
class Connection
{
public:
Connection()
: buffer(0), buffer_size(0)
{ }
void run(SOCKET sock);
privat:
SOCKET input_socket; // Socket we read from
SOCKET output_socket; // Socket we write to
char *buffer; // Buffer we read data into, and write data from
size_t buffer_size; // Total size of buffer (allocated memory)
size_t read_size; // Number of bytes read
void connect();
void recv();
void send();
};
void Connection::run(SOCKET sock)
{
input_socket = sock;
if (buffer == 0)
{
// Allocate buffer
}
// Connect to the real server
connect();
for (;;)
{
try
{
recv();
send();
}
catch (exception &e)
{
std::cerr << "Error: " << e.what() << '\n';
break;
}
}
// Clean up
delete [] buffer;
closesocket(output_socket);
closesocket(input_socket);
}
void Connection::recv()
{
// Read data into the buffer, setting "read_size"
// Like: read_size = recv(input_socket, buffer_size, 0);
// Throw exception on error (includes connection closed)
// NOTE: If error is WSAEWOULDBLOCK, set read_size to 0, don't throw exception
}
void Connection::send()
{
if (read_size > 0)
{
// Send data from the buffer
// Like: send(output_socket, buffer, read_size, 0))
// Throw exception on error
}
}
void Connection::connect()
{
// Connect to the real server
// Set the output_socket member variable
}
DWORD client_thread(LPVOID param)
{
SOCKET socket = (SOCKET) param;
// Make socket nonblocking
int mode = 1;
ioctlsocket(socket, FIONBIO, &mode)
// Main thread stuff
Connection connection;
connection.run(socket);
}
int main()
{
// Create master socket, and other initialization
for (;;)
{
SOCKET client_socket = accept(...);
CreateThread(0, 0 , (LPTHREAD_START_ROUTINE) client_thread,
(LPVOID) client_socket , 0 ,0);
}
// Clean up
}
Another major problem is that you are appending '\0' to the received buffer in the apparent expectation that send() will recognize it and stop sending from there, even though the size parameter to send() is sizeof(FR_recv_buf), which is what it will really respect. Another problem is that data items such as FR_recv_buf are instance variables instead of local variables, so you can't handle multuple concurrent connections.