Problems with my winsock application - c++

I'm having some problems with my Winsock application.
As it currently stands, when my client first connects to the server, the welcome message is sent fine but thats when it screws up. After that initial message its like the program goes into turbo mode.
Each client has a vector that stores messages that need to be sent, to debug I have it output how many messages are left to send and heres what the latest one says:
Successfully sent message. 1 messages left.
Successfully sent message. 1574803 messages left
................... (Counts down)
Successfully sent message. 1574647 messages left
Client connection closed or broken
EDIT: Managed to place some output code in the right place, for some reason when it starts sending update messages to clients, it starts sending the same message over and over.
Heres some code, am only posting the cpp's, 'Network::Update' is run by a thread in 'Game'
-- Server --
Main.cpp
while(true)
{
m_Game -> Update();
Sleep(500);
}
Network.cpp
#include "Network.h"
Network::Network()
{
}
Network::~Network()
{
closesocket(m_Socket);
}
Network::Network(char* ServerIP, int ServerPort)
{
Initialise(ServerIP, ServerPort);
}
void Network::Initialise(char* ServerIP, int ServerPort)
{
//
// Initialise the winsock library to 2.2
//
WSADATA w;
int error = WSAStartup(0x0202, &w);
if ((error != 0) || (w.wVersion != 0x0202))
{
MessageBox(NULL, L"Winsock error. Shutting down.", L"Notification", MB_OK);
exit(1);
}
//
// Create the TCP socket
//
m_Socket = socket(AF_INET, SOCK_STREAM, 0);
if (m_Socket == SOCKET_ERROR)
{
MessageBox(NULL, L"Failed to create socket.", L"Notification", MB_OK);
exit(1);
}
//
// Fill out the address structure
//
m_Address.sin_family = AF_INET;
m_Address.sin_addr.s_addr = inet_addr(ServerIP);
m_Address.sin_port = htons(ServerPort);
//
// Bind the server socket to that address.
//
if (bind(m_Socket, (const sockaddr *) &m_Address, sizeof(m_Address)) != 0)
{
MessageBox(NULL, L"Failed to bind the socket to the address.", L"Notification", MB_OK);
exit(1);
}
//
// Make the socket listen for connections.
//
if (listen(m_Socket, 1) != 0)
{
MessageBox(NULL, L"Failed to listen on the socket.", L"Notification", MB_OK);
exit(1);
}
m_ID = 1;
}
void Network::Update()
{
//
// Structures for the sockets
//
fd_set readable, writeable;
FD_ZERO(&readable);
FD_ZERO(&writeable);
//
// Let the socket accept connections
//
FD_SET(m_Socket, &readable);
//
// Cycle through clients allowing them to read and write
//
for (std::list<Client *>::iterator it = m_Clients.begin(); it != m_Clients.end(); ++it)
{
Client *client = *it;
if (client->wantRead())
{
FD_SET(client->sock(), &readable);
}
if (client->wantWrite())
{
FD_SET(client->sock(), &writeable);
}
}
//
// Structure defining the connection time out
//
timeval timeout;
timeout.tv_sec = 2;
timeout.tv_usec = 500000;
//
// Check if a socket is readable
//
int count = select(0, &readable, &writeable, NULL, &timeout);
if (count == SOCKET_ERROR)
{
ExitProgram(L"Unable to check if the socket can be read.\nREASON: Select failed");
}
//
// Check if a theres an incoming connection
//
if (FD_ISSET(m_Socket, &readable))
{
//
// Accept the incoming connection
//
sockaddr_in clientAddr;
int addrSize = sizeof(clientAddr);
SOCKET clientSocket = accept(m_Socket, (sockaddr *) &clientAddr, &addrSize);
if (clientSocket > 0)
{
// Create a new Client object, and add it to the collection.
Client *client = new Client(clientSocket);
m_Clients.push_back(client);
// Send the new client a welcome message.
NetworkMessage message;
message.m_Type = MT_Welcome;
client->sendMessage(message);
m_ID++;
}
}
//
// Loop through clients
//
for (std::list<Client *>::iterator it = m_Clients.begin(); it != m_Clients.end(); ) // note no ++it here
{
Client *client = *it;
bool dead = false;
//
// Read data
//
if (FD_ISSET(client->sock(), &readable))
{
dead = client->doRead();
}
//
// Write data
//
if (FD_ISSET(client->sock(), &writeable))
{
dead = client->doWrite();
}
//
// Check if the client is dead (Was unable to write/read packets)
//
if (dead)
{
delete client;
it = m_Clients.erase(it);
}
else
{
++it;
}
}
}
void Network::sendMessage(NetworkMessage message)
{
//Loop through clients and send them the message
for (std::list<Client *>::iterator it = m_Clients.begin(); it != m_Clients.end(); ) // note no ++it here
{
Client *client = *it;
client->sendMessage(message);
}
}
Client.cpp
#include "Client.h"
Client::Client(SOCKET sock)
{
m_Socket = sock;
send_count_ = 0;
}
// Destructor.
Client::~Client()
{
closesocket(m_Socket);
}
// Process an incoming message.
void Client::processMessage(NetworkMessage message)
{
// PROCESSING NEEDS TO GO HERE
}
// Return the client's socket.
SOCKET Client::sock()
{
return m_Socket;
}
// Return whether this connection is in a state where we want to try
// reading from the socket.
bool Client::wantRead()
{
// At present, we always do.
return true;
}
// Return whether this connection is in a state where we want to try-
// writing to the socket.
bool Client::wantWrite()
{
// Only if we've got data to send.
//return send_count_ > 0;
return Messages.size() > 0;
}
// Call this when the socket is ready to read.
// Returns true if the socket should be closed.
bool Client::doRead()
{
return false;
}
// Call this when the socket is ready to write.
// Returns true if the socket should be closed.
bool Client::doWrite()
{
/*int count = send(m_Socket, send_buf_, send_count_, 0);
if (count <= 0)
{
printf("Client connection closed or broken\n");
return true;
}
send_count_ -= count;
// Remove the sent data from the start of the buffer.
memmove(send_buf_, &send_buf_[count], send_count_);
return false;*/
int count = send(m_Socket, (char*)&Messages[0], sizeof(NetworkMessage), 0);
if( count <= 0 )
{
printf("Client connection closed or broken\n");
return true;
}
Messages.pop_back();
printf(" Successfully sent message. %d messages left.\n", Messages.size() );
return false;
}
void Client::sendMessage(NetworkMessage message)
{
/*if (send_count_ + sizeof(NetworkMessage) > sizeof(send_buf_))
{
ExitProgram(L"Unable to send message.\nREASON: send_buf_ full");
}
else
{
memcpy(&send_buf_[send_count_], message, sizeof(NetworkMessage));
send_count_ += sizeof(NetworkMessage);
printf(" Size of send_count_ : %d \n", send_count_);
}*/
Messages.push_back(message);
}
Game.cpp
void Game::Update()
{
tempPlayer -> ChangePosition(1, 1); //Increase X and Y pos by 1
Dispatch();
printf("Update\n");
}
void Game::Dispatch()
{
NetworkMessage temp;
temp.m_Type = MT_Update;
temp.m_ID = tempPlayer->getID();
temp.m_positionX = tempPlayer->getX();
temp.m_positionY = tempPlayer->getY();
m_Network->sendMessage(temp);
}

There are a few problems with your code.
The main problem is that Network::sendMessage() runs an infinite loop. Your it iterator is never incremented (there is a comment saying as much - the comment is doing the wrong thing!), so the loop sends the same NetworkMessage to the same Client over and over without ever stopping. Do this instead:
void Network::sendMessage(NetworkMessage message)
{
//Loop through clients and send them the message
for (std::list<Client *>::iterator it = m_Clients.begin(); it != m_Clients.end(); ++it)
{
...
}
}
Client::doWrite() is using pop_back() when it should be using pop_front() instead. If there are multiple pending messages in the vector, you will lose messages. Rather than using the [] operator to pass a NetworkMessage directly to send(), you should pop_front() the first pending message and then send() it:
bool Client::doWrite()
{
NetworkMessage message = Messages.pop_front();
int count = send(m_Socket, (char*)&message, sizeof(NetworkMessage), 0);
if( count <= 0 )
{
printf("Client connection closed or broken\n");
return true;
}
printf(" Successfully sent message. %d messages left.\n", Messages.size() );
return false;
}
Your dead check in Network::Update() has a small logic hole in it that can prevent you from deleting dead clients correctly if doRead() returns true and then doWrite() return false. Do this instead:
bool dead = false;
//
// Read data
//
if (FD_ISSET(client->sock(), &readable))
{
if (client->doRead())
dead = true;
}
//
// Write data
//
if (FD_ISSET(client->sock(), &writeable))
{
if (client->doWrite())
dead = true;
}

Related

C++ TCP server: FD_ISSET() does not always work in a basic server

This is my implementation of a soon-to-be HTTP server.
void Webserv::resetFdSets()
{
int fildes;
FD_ZERO(&to_read);
FD_ZERO(&to_write);
max_fd = -1;
Server_map::iterator it;
for (it = servers.begin(); it != servers.end(); ++it) //set server sockets to be read
{
fildes = it->second.getFd();
FD_SET(fildes, &to_read);
if (fildes > max_fd)
max_fd = fildes;
}
std::list<int>::iterator iter;
for (iter = accepted.begin(); iter != accepted.end(); ++iter) // set client sockets if any
{
fildes = (*iter);
FD_SET(fildes, &to_read);
FD_SET(fildes, &to_write);
if (fildes > max_fd)
max_fd = fildes;
}
}
accept()
void Webserv::acceptConnections()
{
int client_fd;
sockaddr_in cli_addr;
socklen_t cli_len = sizeof(sockaddr_in);
Server_map::iterator it;
for (it = servers.begin(); it != servers.end(); ++it)
{
ft_bzero(&cli_addr, sizeof(cli_addr));
if (FD_ISSET(it->second.getFd(), &to_read)) // if theres data in server socket
{
client_fd = accept(it->second.getFd(), reinterpret_cast<sockaddr*>(&cli_addr), &cli_len);
if (client_fd > 0) // accept and add client
{
fcntl(client_fd, F_SETFL, O_NONBLOCK);
accepted.push_back(client_fd);
}
else
throw (std::runtime_error("accept() failed"));
}
}
}
recv()
void Webserv::checkReadSockets()
{
char buf[4096];
std::string raw_request;
ssize_t bytes;
static int connections;
std::list<int>::iterator it;
for (it = accepted.begin(); it != accepted.end(); ++it)
{
if (FD_ISSET(*it, &to_read))
{
++connections;
std::cout << "Connection counter : " << connections << std::endl;
while ((bytes = recv(*it, buf, sizeof(buf) - 1, MSG_DONTWAIT)) > 0)
{
buf[bytes] = '\0';
raw_request += buf;
}
std::cout << raw_request << std::endl;
}
}
}
send()
void Webserv::checkWriteSockets()
{
char buf[8096];
char http_success[] = {
"HTTP/1.1 200 OK\r\n"
"Server: This op server\r\n"
"Content-Length: 580\r\n"
"Content-Type: text/html\r\n"
"Connection: Closed\r\n\r\n"
};
std::list<int>::iterator it = accepted.begin();
while (it != accepted.end())
{
int cliSock = (*it);
if (FD_ISSET(cliSock, &to_write))
{
int response_fd = open("hello.html", O_RDONLY);
int bytes = read(response_fd, buf, sizeof(buf));
send(cliSock, http_success, sizeof(http_success) - 1, MSG_DONTWAIT); // header
send(cliSock, buf, bytes, MSG_DONTWAIT); // hello world
close(cliSock);
close(response_fd);
it = accepted.erase(it);
}
else
++it;
}
}
main loop:
void Webserv::operate()
{
int rc;
while (true)
{
resetFdSets(); // add server and client fd for select()
if ((rc = select(max_fd + 1, &to_read, &to_write, NULL, NULL)) > 0) // if any of the ports are active
{
acceptConnections(); // create new client sockets with accept()
checkReadSockets(); // parse and route client requests recv() ...
checkWriteSockets(); // send() response and delete client
}
else if (rc < 0)
{
std::cerr << "select() failed" << std::endl;
exit(1);
}
}
}
The same code highlighted + Webserv class definition on pastebin: https://pastebin.com/9B8uYumF
For now the algorithm is such:
reset fd_sets for reading and writing.
if any of the file descriptors trigger select, we check whether server FD are set, accept connections and store them in a list of ints.
if any of the client FD are FD_ISSET() to read - we read their request and print it.
finally, if any of the client FD are ready to receive - we dump an html page in there and close the connection.
While checking all the client descriptors FD_ISSET() returns false 80% of the time when it shouldn't. Hence I cannot get client requests consistently. Strangely enough, it returns true with fd_set for write sockets much more often. Here's a demo with 2 out of 10 successful reads using the above code: https://imgur.com/a/nzc21LV
I know that the new clients are always accepted because it always enters the if condition in acceptConnections(). In other words, the listen FD are initialized correctly.
edit: Here's how it's initialized:
void Server::init()
{
if ((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
throw (std::runtime_error("socket() failed"));
}
fcntl(listen_fd, F_SETFL, O_NONBLOCK);
int yes = 1;
setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
if (bind(listen_fd, reinterpret_cast<sockaddr*>(&server_addr), sizeof(server_addr)))
{
throw (std::runtime_error("bind() failed"));
}
if (listen(listen_fd, 0))
throw (std::runtime_error("listen() failed"));
}

Find out if the socket was accepted or not

I have basic example of using poll() method:
struct pollfds fds[5];
int nfds = 1;
fds[0].fd = listen_sd;
fds[0].events = POLLIN;
while(1) {
int ret = poll(fds, nfds, 0);
if (ret < 0) {
exit(1);
}
int size = nfds;
for (int i = 0; i < size; i++) {
if (fds[i].revents == 0) {
continue;
}
if (fds[i].revents != POLLIN) {
exit(1);
}
if (fds[i].fd == listen_sd) {
// Something happened on the server
// If there is a client which wasn't accepted yet, it returns its fd
int new = accept(listen_sd, null, null);
// If there is a client which was already accepted,
// it doesn't return anything, just loop in accept() method
} else {
// Something happened on a different socket than the server
}
}
}
All messages from clients will flow through server socket.
It means there is always something happened on the server socket, isn't it?
But how can I do something like this (in true condition):
Try to accept a socket, some function should return: the socket is already
accepted, the socket hasn't been accepted yet.
When the socket is already accepted - receive the data.
When the socket hasn't been accepted yet - accept the socket and
receive the data.
On the server side, a TCP socket listening for connections will enter a readable state when it has a client connection waiting to be accepted. Call accept() to actually accept the connection, and then you can start monitoring for read/write/close states on the new TCP socket returned by accept(). This is a completely separate socket than the one that is listening for connections. Add it to your pollfds array so you can poll both it and the listening socket at the same time.
Try something like this:
#include <vector>
std::vector<pollfds> fds;
{
pollfds listen_pf;
listen_pf.fd = listen_sd;
listen_pf.events = POLLIN;
listen_pf.push_back(listen_pf);
}
while (true) {
int ret = poll(fds.data(), fds.size(), 0);
if (ret < 0) {
exit(1);
}
size_t i = 0, size = fds.size();
while (i < size) {
if (fds[i].revents & POLLIN) {
if (fds[i].fd == listen_sd) {
// accept a pending client connection...
int client_sd = accept(listen_sd, NULL, NULL);
if (client_sd != -1) {
pollfds client_pf;
client_pf.fd = client_sd;
client_pf.events = POLLIN | POLLOUT | POLLRDHUP;
fds.push_back(client_pf);
}
}
else {
// read data from fds[i].fd as needed...
if (read fails) {
fds.erase(fds.begin()+i);
--size;
continue;
}
}
}
if (fds[i].revents & POLLOUT) {
// write pending data to fds[i].fd as needed ...
if (write fails) {
fds.erase(fds.begin()+i);
--size;
continue;
}
}
if (fds[i].revents & (POLLERR | POLLHUP | POLLNVAL)) {
if (fds[i].fd == listen_fd) {
exit(1);
}
else {
fds.erase(fds.begin()+i);
--size;
continue;
}
}
++i;
}
}
On the client side, a TCP socket connecting to a server will enter a writable state when connect() is successful and the connection has been fully established with the server and is ready for I/O.

File descriptor returned from socket is larger than FD_SETSIZE

I have a problem where the returned file descriptor would gradually increase to be a number larger than FD_SETSIZE.
My tcp server is continually shutdown which requires my client to close the socket and reconnect. The client will then attempt to reconnect to the server by calling socket to obtain a new file descriptor before calling connect.
However it appears that everytime I call socket the file descriptor returned is incremented and after a certain amount of time it becomes larger than FD_SETSIZE, which is a problem where I use select to monitor the socket.
Is it ok to reuse the first file descriptor returned from socket for the connect call even though the the socket was closed? Or is there other workarounds?
Reconnect code (looping until connected):
int s = getaddrinfo(hostname, port, &hints, &result);
if (s != 0) { ... HANDLE ERROR ...}
...
struct addrinfo *rp;
int sfd;
for (rp = result; rp != NULL; rp -> ai_protocol)
{
sfd = socket( rp->ai_family, rp->ai_sockettype, rp->ai_addrlen);
if (sfd >= 0)
{
int res = connect(sfd, rp->ai_addr, rp->ai_addrlen);
if (res != -1)
{
_sockFd = sfd;
_connected = true;
break;
}
else
{
close (sfd);
break;
}
}
}
if (result != NULL)
{
free(result);
}
Read Message code:
if (_connected)
{
...
retval = select(n, &rec, NULL, NULL, &timeout);
if (retval == -1)
{
...
_connected = false;
close(_sockFd);
}
else if (retval)
{
if (FD_ISSET(_sockFD, &rec) == 0)
{
....
return;
}
int count = read(...)
if (count)
{
....
return;
}
else
{
....
_connected = false;
close(_sockFd);
}
}
}
You're not closing the socket if the connect fails. So it remains open, occupying an FD, so next time you call socket() you get a new FD. You're also not breaking out of your loop when connect() succeeds, which is another leak. You're also not checking the result of read() for -1.

Server & client socket connection issue re. send(), accept() and multi-threading

I'm designing a server program in C++ to receive multiple client connections and pass them into threads, however I've reached an impasse.
The socket connections all work fine, as does the multi-threading - almost. Please see my code below (it compiles and runs fine).
I've tried to pare it down to the essentials for you to make it easy to follow and take up the least of your time. I've commented the code to help you see where the problem is, then I describe the problem in detail at the bottom. If you can help me then I would be very grateful!
#include <vector>
#include <boost/thread.hpp>
#include "unix_serverSocket.h"
#include "server.h"
extern const string socketAddress;
void do_stuff(ServerSocket *client)
{
string in;
string out;
try
{
/* Gets input until the client closes the connection, then throws an exception, breaking out of the loop */
while (true)
{
*client >> in; /* Receives data from client socket connection */
/* Assume the input is processed fine and returns the result into 'out' */
sleep(3); /* I've put sleep() here to test it's multithreading properly - it isn't */
*client << out; /* Returns result to client - send() is called here */
/* If I put sleep() here instead it multithreads fine, so the server is waiting for send() before it accepts a new client */
}
}
catch (SocketException &)
{
delete client;
return;
}
}
int main()
{
try
{
ServerSocket server(socketAddress);
while (true)
{
ServerSocket *client = new ServerSocket();
/* See below */
server.accept(*client);
boost::thread newThread(do_stuff, client);
}
}
catch (SocketException &e)
{
cout << "Error: " << e.description() << endl;
}
return 0;
}
After a client socket connection has been passed to a thread, main() gets back to
the line:
server.accept(*client);
but then waits for the previous connection to send its result back to the
client via send() before it will accept a new connection - i.e. the server is waiting
for something to happen in the thread before it will accept a new client! I don't
want it to do this - I want it to send the client connection to a thread then accept
more client connections straight away and pass them into more threads!
In case you're wondering why I created a pointer to the socket here...
ServerSocket *client = new ServerSocket();
... if I don't create a pointer then the recv() function called by the thread fails to receive data from the client, which seems to be due to the thread shallow copying the client socket connection and the garbage collector not understanding threads and thinking the client connection is no longer going to be used after it has been passed to the thread and so destroying it before recv() is called in the thread. Hence using a pointer created on the heap, which worked. Anyway, when I reworked the code using fork() instead of threads (which meant I didn't need to create the socket on the heap), I still had the same problem with the server not being able to accept new clients.
I guess I need to change the server settings somehow so that it doesn't wait for a client to send() before accepting a new one, however despite much Googling I'm still at a loss!
Here's the relevant socket connection code in case it helps (the server and clients are all on the same box and thus connecting via local UNIX sockets):
class Socket
{
private:
int sockfd;
struct sockaddr_un local;
public:
Socket();
virtual ~Socket();
bool create();
bool bind(const string &);
bool listen() const;
bool accept(Socket &) const;
bool send(const string &) const;
int recv(string &) const;
void close();
bool is_valid() const
{
return sockfd != -1;
}
};
bool Socket::create()
{
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (!is_valid())
{
return false;
}
int reuseAddress = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*) &reuseAddress, sizeof(reuseAddress)) == -1)
{
return false;
}
return true;
}
bool Socket::bind(const string &socketAddress)
{
if (!is_valid())
{
return false;
}
local.sun_family = AF_UNIX;
strcpy(local.sun_path, socketAddress.c_str());
unlink(local.sun_path);
int len = strlen(local.sun_path) + sizeof(local.sun_family);
int bind_return = ::bind(sockfd, (struct sockaddr *) &local, len);
if (bind_return == -1)
{
return false;
}
return true;
}
bool Socket::listen() const
{
if (!is_valid())
{
return false;
}
int listen_return = ::listen(sockfd, MAXCLIENTCONNECTIONS);
if (listen_return == -1)
{
return false;
}
return true;
}
bool Socket::accept(Socket &socket) const
{
int addr_length = sizeof(local);
socket.sockfd = ::accept(sockfd, (sockaddr *) &local, (socklen_t *) &addr_length);
if (socket.sockfd <= 0)
{
return false;
}
else
{
return true;
}
}
int Socket::recv(string &str) const
{
char buf[MAXRECV + 1];
str = "";
memset(buf, 0, MAXRECV + 1);
int status = ::recv(sockfd, buf, MAXRECV, 0);
if (status == -1)
{
cout << "status == -1 errno == " << errno << " in Socket::recv" << endl;
return 0;
}
else if (status == 0)
{
return 0;
}
else
{
str = buf;
return status;
}
}
bool Socket::send(const string &str) const
{
int status = ::send(sockfd, str.c_str(), str.size(), MSG_NOSIGNAL);
if (status == -1)
{
return false;
}
else
{
return true;
}
}
class ServerSocket : private Socket
{
public:
ServerSocket(const string &);
ServerSocket() {};
virtual ~ServerSocket();
void accept(ServerSocket &);
const ServerSocket & operator << (const string &) const;
const ServerSocket & operator >> (string &) const;
};
ServerSocket::ServerSocket(const string &socketAddress)
{
if (!Socket::create())
{
throw SocketException("Could not create server socket");
}
if (!Socket::bind(socketAddress))
{
throw SocketException("Could not bind to port");
}
if (!Socket::listen())
{
throw SocketException("Could not listen to socket");
}
}
void ServerSocket::accept(ServerSocket &socket)
{
if (!Socket::accept(socket))
{
throw SocketException("Could not accept socket");
}
}
const ServerSocket & ServerSocket::operator << (const string &str) const
{
if (!Socket::send(str))
{
throw SocketException("Could not write to socket");
}
return *this;
}
const ServerSocket & ServerSocket::operator >> (string &str) const
{
if (!Socket::recv(str))
{
throw SocketException("Could not read from socket");
}
return *this;
}
I've figured it out! The reason the clients weren't multithreading was that the program creating the client connections was doing so within a mutex - hence it wouldn't create a new connection until the old one had received a reply from the server, and thus the server appeared to be only single-threading! So in short my server program above was fine and it was a problem at the client end - sorry for wasting your time - I didn't even consider the possibility until I completely reworked the program structure by putting the threading at the client end instead, which then revealed the issue.
Thanks for all your help!
Your sockets are blocking! This means that they will wait for the operation to finish before returning.
This is how you make a socket non-blocking:
bool nonblock(int sock)
{
int flags;
flags = fcntl(sock, F_GETFL, 0);
flags |= O_NONBLOCK;
return (fcntl(sock, F_SETFL, flags) == 0);
}
Now the functions accept, read and write will all return an error if the socket would block, setting the errno variable to EWOULDBLOCK or possibly EAGAIN.
If you want to wait for a socket to be ready for reading or writing, you can use the function select. For listening sockets (the one you do accept on) it will be ready to read when a new connection can be accepted.

multi-threaded chess using winsock

I've been working on a small network based chess application. I managed to create a server that can handle multiple connections, however I don't know how to send data from one client to another.
Here is the partial Server implementation
//function to handle our Socket on its own thread.
//param- SOCKET* that is connected to a client
DWORD WINAPI HandleSocket(void* param)
{
string test;
SOCKET s = (SOCKET)param;
User temp;
temp._socket = (SOCKET)param;
temp._inGame = false;
userlist.add(&temp);
std::cout<<"connection"<<endl;
int bytesread = 0;
int byteswrite=0;
while(true)
{
//receive
bytesread = recv(s, reinterpret_cast<char*>(test.c_str()), BUF_LEN, 0);
//error check
if(bytesread == SOCKET_ERROR)
{
std::cout << WSAGetLastError();
//shutdown and close on error
shutdown(s, SD_BOTH);
closesocket(s);
return 0;
}
//check for socket being closed by the client
if(bytesread == 0)
{
//shutdown our socket, it closed
shutdown(s, SD_BOTH);
closesocket(s);
return 0;
}
byteswrite = send(s, "test" , 255 , 0);
if(byteswrite == SOCKET_ERROR)
{
std::cout << WSAGetLastError();
//shutdown and close on error
shutdown(s, SD_BOTH);
closesocket(s);
return 0;
}
test.clear();
}
}
Maybe you should start a thread for a new game when both players of the game are connected to the server. In that case you can deliver both sockets to the thread by the following way:
DWORD WINAPI HandleGame(void* param)
{
GameState* game = (GameState*)param;
SOCKET s1 = game->getSocketOfPlayer(1);
SOCKET s2 = game->getSocketOfPlayer(2);
...
// TODO: Forward game messages between clients (players).
...
delete game;
return 0;
}
Alternative solutions: Implement the server program in sigle thread.
In both cases you propably need select() function for waiting messages from several players simultaneously.