I am learning about IOCP and have decided to write my own wrapper class based on the following article:
http://www.codeproject.com/Articles/13382/A-simple-application-using-I-O-Completion-Ports-an
My project is a C++ TCP server using IOCP. The client uses send() and recv() to send and receive data which I cannot change (from what I've been told this shouldn't cause any problem, but I am mentioning it just in case). It also creates a socket using socket() (and not WSASocket()).
Everything seems to be working fine (no error with CreateIoCompletionPort, I can add a socket descriptor to the existing completion port without any error. I've checked everything by adding a call to WSAGetLastError() after each of these functions).
(Before anything, please don't mind the inconsistent coding style. I like to make stuff work first and then clean it all up.)
socket_ = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_IP, NULL, 0, WSA_FLAG_OVERLAPPED);
setsockopt(socket_, IPPROTO_IP, SO_DEBUG | TCP_NODELAY, sockopt, 4);
ioctlsocket(socket_, FIONBIO, &ulSockMode_);
sin_.sin_family = AF_INET;
sin_.sin_port = htons((uint16_t)uiPort_));
hAccept_[0] = WSACreateEvent(); //only 1 event, I'm using an array for convenience
if (hAccept_ == WSA_INVALID_EVENT)
{
//this is never executed
}
WSAEventSelect(socket_, hAccept_[0], FD_ACCEPT);
After an incoming connection is detected (I use WSAWaitForMultipleEevents and WSAEnumNetworkEvents which work don't trigger any error), I use the following code to accept the client (and this is where the problems start):
SOCKET sock_client{ INVALID_SOCKET };
int32_t len_si{ sizeof(SOCKADDR_IN) };
//sock_client = accept(socket_, reinterpret_cast<SOCKADDR*>(pSockAddr), &len_si); // this works fine
//sock_client = sock_client = WSAAccept(socket_, reinterpret_cast<SOCKADDR*>(pSockAddr), &len_si, NULL, 0);//works fine too
char buf[2 * (sizeof(SOCKADDR_IN) + 16)];
WSAOVERLAPPED wsaovl;
uint32_t bytes{ 0 };
BOOL b = AcceptEx(socket_, sock_client, (PVOID)buf, 0, sizeof(SOCKADDR_IN) + 16, sizeof(SOCKADDR_IN) + 16, reinterpret_cast<LPDWORD>(&bytes), &wsaovl); //this fails, returns 0
int32_t test = WSAGetLastError(); // this returns 6 (WSA_INVALID_HANDLE)
I have no idea why it works with accept() and WSAAccept(), however it doesn't with AcceptEx().
If I use accept() though, after accepting the client I need to call WSARecv() immediately. I'm not sending anything back to the client just yet but I read that it needs to be called before GetQueuedCompletionStatus() in the worker thread:
WSABUF* buf = new WSABUF;
OVERLAPPED* ovl = new OVERLAPPED;
int32_t flags{ 0 };
int32_t bytes{ 0 };
int32_t bytes_recv = WSARecv(client_socket, buf, 1, &flags, &bytes, ovl, NULL); // this returns -1
int32_t err = WSAGetLastError(); // this returns 6 (WSA_INVALID_HANDLE)
And since this doesn't work, the GetQueuedCompletionStatus() routine in my worker thread keeps on hanging (or at least, I assume this is the reason)
Is there anything wrong with what I'm doing? I've been trying to search around and fix it since yesterday night, I know it's not a lot of time but I really don't see what I'm not doing correctly.
UPDATE:
I have changed the way I initialize my socket for AcceptEx().
SOCKET sock_client = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_IP, NULL, 0, WSA_FLAG_OVERLAPPED);
and
WSAOVERLAPPED wsaovl = {};
AcceptEx() still returns false, however the error returned by WSAGetLastError() is now 997 (WSA_IO_PENDING). I'm not sure what I/O operation is pending exactly and how I would go about fixing it.
I had stumbled upon similar hurdle when I was learning I/O Completion Ports (IOCP)...
I think the problem is that, in the scheme of IOCP socket model, the most complicated part is the beginning phase of 'socket acceptance'. That is why most tutorial skip over it and begin the discussion on how to handle send/recv, instead.
If you want to develop sufficient understanding of IOCP so that you could implement a production software then my advice to you is to study it until you completely grasp it (this answer below is not enough). One document that I would recommend is chapter 5 of 'Network Programming for Microsoft Windows - 2nd edition'. The book may be old but valid for IOCP. Also, the article 'Windows via C/C++: Synchronous and Asynchronous Device I/O' touches some aspects of IOCP, though not enough information to do production software.
I will try to explain as best as I can, however, I must warn you that this may not be enough. Here it goes...
So, the part you are missing is "How to do 'socket acceptance' in an IOCP socket model".
First off, lets examine the typical Winsock (non-IOCP) sequence of calls on server;
// (1) Create listen socket on server.
WSASocket()
// (2) Bind an address to your listen socket.
bind()
// (3) Associate the listen socket with an event object on FD_ACCEPT event.
WSAEventSelect(,, FD_ACCEPT )
// (4) Put socket in listen state - now, Windows listening for new
// connection requests. If new requests comes, the associated
// event object will be set.
listen()
// (5) Wait on the event object associated on listen socket. This
// will get signaled when a new connection request comes.
WaitForSingleObject() {
// (6) A network activity has occurred. Verify that FD_ACCEPT has
// raised the event object. This also resets the event object
// so WaitForSingleObject() does not loop non-stop.
WSAEnumNetworkEvents()
// (7) Understanding this part is important. The WSAAccept() doesn't
// just accept connection, it first creates a new socket and
// then associates it with the newly accepted connection.
WSAAccept()
}
The step (7) is ok for non-IOCP based models. However, when looking it from the performance point of view - socket creation is expensive. And it slows down the connection acceptance process.
In IOCP model, sockets are created in advance for new incoming connection requests. Not only sockets are created in advance they are associated with the listen socket even before the connection request comes. To achieve this Microsoft has provided extension functions. Two such functions that are required for IOCP model are AcceptEx() & GetAcceptExSockaddrs().
Note: When using these extension functions they need to be loaded at runtime in order to avoid performance penalty. This can be achieved using WSAIoctl(). For further read refer to the MSDN documentation on AcceptEx().
Caveat: AcceptEx() can be used to set the new socket to receive some data as part of connection-acceptance process. This feature needs to be disabled as it makes application susceptible to DoS attack i.e., a connection request is issued but no data is sent. The receiving application will wait on that socket indefinitely. To avoid that just pass 0 value for its 'dwReceiveDataLength' parameter.
How to setup connection-acceptance code for IOCP model?
One way to do this is;
// (1) Create IO completion port
CreateIoCompletionPort()
// (2) Have a method that creates worker threads say 'CreateWorkerThreads()'.
// This assign same method (say WorkerThread_Func()) to all worker threads.
// In the WorkerThread_Func() threads are blocked on call to
// GetQueuedCompletionStatus().
CreateWorkerThreads()
// (3) Create listen socket.
WSASocket()
// (4) Associate listen socket to IO Completion Port created earlier.
CreateIoCompletionPort()
// (5) Bind an address to your listen socket.
bind()
// (6) Put socket in listen state - now, Windows listening for new
// connection requests. If a new request comes, GetQueuedCompletionStatus()
// will release a thread.
listen()
// (7) Create sockets in advance and call AcceptEx on each of
// these sockets. If a new connection requests comes
// Windows will pick one of these sockets and associate the
// connection with it.
//
// As an example, below loop will create 1000 sockets.
GUID GuidAcceptEx = WSAID_ACCEPTEX;
DWORD dwBytes;
LPFN_ACCEPTEX lpfnAcceptEx;
// First, load extension method.
int retCode = WSAIoctl(listenSocket,
SIO_GET_EXTENSION_FUNCTION_POINTER,
&GuidAcceptEx,
sizeof(GuidAcceptEx),
&lpfnAcceptEx,
sizeof(lpfnAcceptEx),
&dwBytes,
NULL,
NULL
);
for( /* loop for 1000 times */ ) {
SOCKET preemptiveSocket = WSASocket(, , , , , WSA_FLAG_OVERLAPPED);
lpfnAcceptEx(listenSocket, preemptiveSocket,,,,,,);
}
This essentially prepare your application to accept sockets in IOCP way. When a new connection requests comes one of the worker threads, that are waiting on GetQueuedCompletionStatus(), will be released and handed over the pointer to the data structure. This will have the socket that was created by lpfnAcceptEx().
Is the process complete? Not yet. The socket accepted through AcceptEx() call does not inherit properties of listenSocket. To do that you need to call;
setsockopt( acceptSocket, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
(char*)&listenSocket, sizeof(listenSocket) );
Now, acceptSocket is good to use for WSASend / WSARecv!
Something is missing! I skipped the part about how does a worker thread gets the acceptedSocket from GetQueuedCompletionStatus() ?
The answer is, by passing your specially crafted structure to lpfnAcceptEx(). When the GetQueuedCompletionStatus() returns it will have this data structure containing the socket that you will have passed.
How to make such a structure? By creating a structure having 'WSAOVERLAPPED' as its first member. You can have any members of your own after the first member. For example, my structure looked like;
typedef struct _WSAOVERLAPPEDPLUS
{
WSAOVERLAPPED ProviderOverlapped; // 'WSAOVERLAPPED' has to be the first member.
SOCKET client; // Use this to pass preemptive socket.
SOCKET listenSocket; // Use this to pass the listenSocket.
DWORD dwBytes;
SOCKET_OPERATION operation; // Enum to assist in knowing what socket operation ...
} WSAOVERLAPPEDPLUS, *LPWSAOVERLAPPEDPLUS;
...
typedef enum SOCKET_OPERATION {
UNINITIALIZED_ENUM, // To protect against memory leaks and uninitialized buffers.
OP_ACCEPTEX,
OP_RECEIVE,
OP_SEND
};
...
//
// So the previously mentioned for() loop will become;
//
for( /* loop for 1000 times */ ) {
SOCKET preemptiveSocket = WSASocket(, , , , , WSA_FLAG_OVERLAPPED);
LPWSAOVERLAPPEDPLUS pOl = new WSAOVERLAPPEDPLUS();
// Initialize our "extended" overlapped structure
memset(pOl, 0, sizeof(WSAOVERLAPPEDPLUS));
pOl->operation = OP_ACCEPTEX;
pOl->client = preemptiveSocket;
pOl->listenSocket = listenSocket;
int buflen = (sizeof(SOCKADDR_IN) + 16) * 2;
char* pBuf = new char[buflen];
memset(pBuf, 0, buflen);
m_lpfnAcceptEx(listenSocket,
preemptiveSocket,
pBuf,
0, // Passed 0 to avoid reading data on accept which in turn
// avoids DDoS attack i.e., connection attempt without data will
// cause AcceptEx to wait indefinitely.
sizeof(SOCKADDR_IN) + 16,
sizeof(SOCKADDR_IN) + 16,
&pOl->dwBytes,
&pOl->ProviderOverlapped
);
}
... and in the worker thread when GetQueuedCompletionStatus() returns;
while (TRUE)
{
bOk = ::GetQueuedCompletionStatus(hCompPort, &bytes_transferred, &completion_key, &pOverlapped, INFINITE);
if (bOk) {
// Process a successfully completed I/O request
if (completion_key == 0) {
// Safe way to extract the customized structure from pointer
// is to use 'CONTAINING_RECORD'. Read more on 'CONTAINING_RECORD'.
WSAOVERLAPPEDPLUS *pOl = CONTAINING_RECORD(pOverlapped, WSAOVERLAPPEDPLUS, ProviderOverlapped);
if (pOl->operation == OP_ACCEPTEX) {
// Before doing any WSASend/WSARecv, inherit the
// listen socket properties by calling 'setsockopt()'
// as explained earlier.
// The listenSocket and the preemptive socket are available
// in the 'pOl->listenSocket' & 'pOl->client', respectively.
}
delete pOl;
}
}
else {
// Handle error ...
}
I hope this gave you idea on how AcceptEx() is utilized with IOCP.
Related
I am relatively new to network programming and multithreading in C++. Currently my recv() call returns an unknown error. I'm not quite sure where the error coming from at the moment and would appreciate some help.
I used putty to connect to the server locally
class Threaded_TCPListener{
int Threaded_TCPListener::Init()
{
// Initializing WinSock
WSADATA wsData;
WORD ver = MAKEWORD(2,2);
int winSock = WSAStartup(ver, &wsData);
if(winSock != 0)
return winSock;
// Creating listening socket
this->socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(this->socket == INVALID_SOCKET)
return WSAGetLastError();
// Fill sockaddr with ip addr and port
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(this->port);
inet_pton(AF_INET, this->ipAddress, &hint.sin_addr);
// Bind hint to socket
if(bind(this->socket, (sockaddr*)&hint, sizeof(hint)) == SOCKET_ERROR)
return WSAGetLastError();
// Start listening on socket
if(listen(this->socket, SOMAXCONN) == SOCKET_ERROR)
return WSAGetLastError();
// Accept first client
this->createAcceptThread();
return 0;
}
int Threaded_TCPListener::Run()
{
bool isRunning = true;
// Read from all clients
std::vector<std::thread> threads;
threads.reserve(this->clients.size());
// Recv from client sockets
for (int i=0; i < this->clients.size(); ++i)
{
threads.emplace_back(std::thread(&Threaded_TCPListener::receiveFromSocket, this, socket));
}
// Wait for all threads to finish
for(std::thread& t : threads)
{
t.detach();
}
return 0;
}
void Threaded_TCPListener::onMessageReceived(int clientSocket, const char* msg, int length)
{
Threaded_TCPListener::broadcastToClients(clientSocket, msg, length);
std::thread t(&Threaded_TCPListener::receiveFromSocket, this, clientSocket);
t.detach();
return;
}
void Threaded_TCPListener::sendMessageToClient(int clientSocket, const char * msg, int length)
{
send(clientSocket, msg, length, 0);
return;
}
void Threaded_TCPListener::broadcastToClients(int senderSocket, const char * msg, int length)
{
std::vector<std::thread> threads;
threads.reserve(clients.size());
// Iterate over all clients
for (int sendSock : this->clients)
{
if(sendSock != senderSocket)
threads.emplace_back(std::thread(&Threaded_TCPListener::sendMessageToClient, this,sendSock, msg, length));
}
// Wait for all threads to finish
for(std::thread& t : threads)
t.join();
return;
}
void Threaded_TCPListener::createAcceptThread()
{
// Start accepting clients on a new thread
this->listeningThread = std::thread(&Threaded_TCPListener::acceptClient, this);
this->listeningThread.detach();
return;
}
void Threaded_TCPListener::acceptClient()
{
int client = accept(this->socket, nullptr, nullptr);
// Error
if(client == INVALID_SOCKET)
{
std::printf("Accept Err: %d\n", WSAGetLastError());
}
// Add client to clients queue
else
{
// Add client to queue
this->clients.emplace(client);
// Client Connect Confirmation
onClientConnected(client); // Prints msg on server
// Create another thread to accept more clients
this->createAcceptThread();
}
return;
}
void Threaded_TCPListener::receiveFromSocket(int receivingSocket)
{
// Byte storage
char buff[MAX_BUFF_SIZE];
// Clear buff
memset(buff, 0, sizeof(buff));
// Receive msg
int bytesRecvd = recv(receivingSocket, buff, MAX_BUFF_SIZE, 0);
if(bytesRecvd <= 0)
{
char err_buff[1024];
strerror_s(err_buff, bytesRecvd);
std::cerr << err_buff;
// Close client
this->clients.erase(receivingSocket);
closesocket(receivingSocket);
onClientDisconnected(receivingSocket); // Prints msg on server
}
else
{
onMessageReceived(receivingSocket, buff, bytesRecvd);
}
}
}
I am trying to create a multithreaded TCP 'server' that will handle incoming clients by having an accept thread continuously running (listening for new connections), and a thread waiting with a recv block for each client connected to the server.
Your Init looks fine:
create socket, bind it, listen on it, start accept thread
In your accept thread's acceptClient looks sort of OK:
print some message
add the client socket to clients queue
create a new accept thread
Your Run makes no sense:
create one thread per element in clients to receive from the listening socket
It looks like you are spawning a new thread for every single socket action. That is a pretty wasteful design. As soon as the thread is done it can go back to doing something else.
So creating a new accept thread in acceptClient is a waste, you could just loop back to the beginning to ::accept the next client. Like so:
acceptClient() {
while (alive) {
int client = accept(socket, ...);
createClientHandler(client);
}
}
What seems to be missing is spawning a new client thread to service the client socket. You currently do this in Run, but that's before any of the clients are actually accepted. And you do it for the wrong socket! Instead, you should be spawning the receiveFromSocket threads in acceptClient, and passing it the client socket. So that's a bug.
In your receiveFromSocket you also need not create another thread to receiveFromSocket again -- just loop back to the beginning.
The biggest concern with this thread-per-action design is that you are spawning sender threads on every incoming message. This means you could actually have several sender threads attempting to ::send on the same TCP socket. That's not very safe.
The order of calls made to WSASend is also the order in which the buffers are transmitted to the transport layer. WSASend should not be called on the same stream-oriented socket concurrently from different threads, because some Winsock providers may split a large send request into multiple transmissions, and this may lead to unintended data interleaving from multiple concurrent send requests on the same stream-oriented socket.
https://learn.microsoft.com/en-us/windows/desktop/api/winsock2/nf-winsock2-wsasend
Similarly, instead of spawning threads in broadcastToClients, I suggest you just spawn one persistent sender thread per client socket in acceptClient (together with the receiveFromSocket thread within some createClientHandler).
To communicate with the sender threads you should use thread-safe blocking queues. Each sender thread would look like this:
while (alive) {
msg = queue.next_message();
send(client_socket, msg);
}
Then on message received you just do:
for (client : clients) {
client.queue.put_message(msg);
}
So to summarize, to handle each client you need a structure like this:
struct Client {
int client_socket;
BlockingQueue queue;
// optionally if you want to keep track of your threads
// to be able to safely clean up
std::thread recv_thread, send_thread;
};
Safe cleanup is a whole other story.
Finally, a remark on this comment in your code:
// Wait for all threads to finish
for(std::thread& t : threads)
{
t.detach();
}
That's almost the opposite to what std::thread::detach does:
https://en.cppreference.com/w/cpp/thread/thread/detach
It allows you to destroy the thread object without having to wait for the thread to finish execution.
There is a misconception in the code in how a TCP server has to be implemented:
You seem to assume that you can have a single server socket file descriptor which can handle all communication. This is not the case. You must have a single dedicated socket file descriptor which is just used for listening and accepting incoming connections, and then you have one additional file descriptor for each existing connection.
In your code I see that you invoke receiveFromSocket() always with the listening socket. This is wrong. Also invoking receiveFromSocket() in a loop for all clients is wrong.
What you rather need to do is:
- Have one dedicated thread which call accept() in a loop. There is no performance benefit in calling accept() from multiple threads.
- One accept() returns a new connection you spawn a new thread which calls recv() in a loop. This will then block and wait for new data as you expect in your question.
You also need to drop the habit of calling individual functions from new threads. This is not multithreaded programming. A thread usually contains a loop. Everything else is usually a design flaw.
Also note that multithreaded programming is still rocket science in 2019, especially in C++. If you are not an absolute expert you will not be able to do it. Also note that absolute experts in multithreaded programming will try to avoid multithreaded programming whenever possible. A lot seemingly concurrent tasks which are I/O bound can better be handled by a single threaded event based system.
I'm writing a network game for a university project and while I have messages being sent and received between a client and a server, I'm unsure on how I would go about implementing a writeable fd_set (my lecturer's example code only included a readable fd_set) and what the function is of both fd_sets with select(). Any insight you could give would be great in helping me understand this.
My server code is as such:
bool ServerSocket::Update() {
// Update the connections with the server
fd_set readable;
FD_ZERO(&readable);
// Add server socket, which will be readable if there's a new connection
FD_SET(m_socket, &readable);
// Add connected clients' sockets
if(!AddConnectedClients(&readable)) {
Error("Couldn't add connected clients to fd_set.");
return false;
}
// Set timeout to wait for something to happen (0.5 seconds)
timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 500000;
// Wait for the socket to become readable
int count = select(0, &readable, NULL, NULL, &timeout);
if(count == SOCKET_ERROR) {
Error("Select failed, socket error.");
return false;
}
// Accept new connection to the server socket if readable
if(FD_ISSET(m_socket, &readable)) {
if(!AddNewClient()) {
return false;
}
}
// Check all clients to see if there are messages to be read
if(!CheckClients(&readable)) {
return false;
}
return true;
}
A socket becomes:
readable if there is either data in the socket receive buffer or a pending FIN (recv() is about to return zero)
writable if there is room in the socket receive buffer. Note that this is true nearly all the time, so you should use it only when you've encountered a prior EWOULDBLOCK/EAGAIN on the socket, and stop using it when you don't.
You'd create an fd_set variable called writeable, initialize it the same way (with the same sockets), and pass it as select's third argument:
select(0, &readable, &writeable, NULL, &timeout);
Then after select returns you'd check whether each socket is still in the set writeable. If so, then it's writeable.
Basically, exactly the same way readable works, except that it tells you a different thing about the socket.
select() is terribly outdated and it's interface is arcane. poll (or it's windows counterpart WSAPoll is a modern replacement for it, and should be always preferred.
It would be used in following manner:
WSAPOLLFD pollfd = {m_socket, POLLWRNORM, 0};
int rc = WSAPoll(&pollfd, 1, 100);
if (rc == 1) {
// Socket is ready for writing!
}
I am having trouble using the std::async to have tasks execute in parallel when the task involves a socket.
My program is a simple TCP socket server written in standard C++ for Linux. When a client connects, a dedicated port is opened and separate thread is started, so each client is serviced in their own thread.
The client objects are contained in a map.
I have a function to broadcast a message to all clients. I originally wrote it like below:
// ConnectedClient is an object representing a single client
// ConnectedClient::SendMessageToClient opens a socket, connects, writes, reads response and then closes socket
// broadcastMessage is the std::string to go out to all clients
// iterate through the map of clients
map<string, ConnectedClient*>::iterator nextClient;
for ( nextClient = mConnectedClients.begin(); nextClient != mConnectedClients.end(); ++nextClient )
{
printf("%s\n", nextClient->second->SendMessageToClient(broadcastMessage).c_str());
}
I have tested this and it works with 3 clients at a time. The message gets to all three clients (one at a time), and the response string is printed out three times in this loop. However, it is slow, because the message only goes out to one client at a time.
In order to make it more efficient, I was hoping to take advantage of std::async to call the SendMessageToClient function for every client asynchronously. I rewrote the code above like this:
vector<future<string>> futures;
// iterate through the map of clients
map<string, ConnectedClient*>::iterator nextClient;
for ( nextClient = mConnectedClients.begin(); nextClient != mConnectedClients.end(); ++nextClient )
{
printf("start send\n");
futures.push_back(async(launch::async, &ConnectedClient::SendMessageToClient, nextClient->second, broadcastMessage, wait));
printf("end send\n");
}
vector<future<string>>::iterator nextFuture;
for( nextFuture = futures.begin(); nextFuture != futures.end(); ++nextFuture )
{
printf("start wait\n");
nextFuture->wait();
printf("end wait\n");
printf("%s\n", nextFuture->get().c_str());
}
The code above functions as expected when there is only one client in the map. That you see "start send" quickly followed by "end send", quickly followed by "start wait" and then 3 seconds later (I have a three second sleep on the client response side to test this) you see the trace from the socket read function that the response comes in, and then you see "end wait"
The problem is that when there is more than one client in the map. In the part of the SendMessageToClient function that opens and connects to the socket, it fails in the code identified below:
// connected client object has a pipe open back to the client for sending messages
int clientSocketFileDescriptor;
clientSocketFileDescriptor = socket(AF_INET, SOCK_STREAM, 0);
// set the socket timeouts
// this part using setsockopt is omitted for brevity
// host name
struct hostent *server;
server = gethostbyname(mIpAddressOfClient.c_str());
if (server == 0)
{
close(clientSocketFileDescriptor);
return "";
}
//
struct sockaddr_in clientsListeningServerAddress;
memset(&clientsListeningServerAddress, 0, sizeof(struct sockaddr_in));
clientsListeningServerAddress.sin_family = AF_INET;
bcopy((char*)server->h_addr, (char*)&clientsListeningServerAddress.sin_addr.s_addr, server->h_length);
clientsListeningServerAddress.sin_port = htons(mPortNumberClientIsListeningOn);
// The connect function fails !!!
if ( connect(clientSocketFileDescriptor, (struct sockaddr *)&clientsListeningServerAddress, sizeof(clientsListeningServerAddress)) < 0 )
{
// print out error code
printf("Connected client thread: fail to connect %d \n", errno);
close(clientSocketFileDescriptor);
return response;
}
The output reads: "Connected client thread: fail to connect 4".
I looked this error code up, it is explained thus:
#define EINTR 4 /* Interrupted system call */
I searched around on the internet, all I found were some references to system calls being interrupted by signals.
Does anyone know why this works when I call my send message function one at a time, but it fails when the send message function is called using async? Does anyone have a different suggestion how I should send a message to multiple clients?
First, I would try to deal with the EINTR issue. connect ( ) has been interrupted (this is the meaning of EINTR) and does not try again because you are using and asynch descriptor.
What I usually do in such a circumstance is to retry: I wrap the function (connect in this case) in a while cycle. If connect succeeds I break out of the cycle. If it fails, I check the value of errno. If it is EINTR I try again.
Mind that there are other values of errno that deserve a retry (EWOULDBLOCK is one of them)
I am implementing a Windows-based web server handling multiple specific HTTP requests from clients using WinSock2. I have a class to start and stop my server. It looks something like this:
class CMyServer
{
// Not related to this question methods and variables here
// ...
public:
SOCKET m_serverSocket;
TLM_ERROR Start();
TLM_ERROR Stop();
static DWORD WINAPI ProcessRequest(LPVOID pInstance);
static DWORD WINAPI Run(LPVOID pInstance);
}
where TLM_ERROR is a type definition for my server's errors enumeration.
bool CMyServer::Start() method starts the server creating a socket listening on configured port and creating a separate thread DWORD CMyServer::Run(LPVOID) to accept incoming connections like described here:
// Creating a socket
m_serverSocket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (m_serverSocket == INVALID_SOCKET)
return TLM_ERROR_CANNOT_CREATE_SOCKET;
// Socket address
sockaddr_in serverSocketAddr;
serverSocketAddr.sin_family = AF_INET; // address format is host and port number
serverSocketAddr.sin_addr.S_un.S_addr = inet_addr(m_strHost.c_str()); // specifying host
serverSocketAddr.sin_port = htons(m_nPort); // specifying port number
// Binding the socket
if (::bind(m_serverSocket, (SOCKADDR*)&serverSocketAddr, sizeof(serverSocketAddr)) == SOCKET_ERROR)
{
// Error during binding the socket
::closesocket(m_serverSocket);
m_serverSocket = NULL;
return TLM_ERROR_CANNOT_BIND_SOCKET;
}
// Starting to listen to requests
int nBacklog = 20;
if (::listen(m_serverSocket, nBacklog) == SOCKET_ERROR)
{
// Error listening on socket
::closesocket(m_serverSocket);
m_serverSocket = NULL;
return TLM_ERROR_CANNOT_LISTEN;
}
// Further initialization here...
// ...
// Creating server's main thread
m_hManagerThread = ::CreateThread(NULL, 0, CTiledLayersManager::Run, (LPVOID)this, NULL, NULL);
I use ::accept(...) to wait for incoming client connections in CMyServer::Run(LPVOID), and after new connection has been accepted I create a separate thread CMyServer::ProcessRequest(LPVOID) to receive a data from a client and send a response passing the socket returned by ::accept(...) as part of thread function's argument:
DWORD CMyServer::Run(LPVOID pInstance)
{
CMyServer* pTLM = (CMyServer*)pInstance;
// Initialization here...
// ...
bool bContinueRun = true;
while (bContinueRun)
{
// Waiting for a client to connect
SOCKADDR clientSocketAddr; // structure to store socket's address
int nClientSocketSize = sizeof(clientSocketAddr); // defining structure's length
ZeroMemory(&clientSocketAddr, nClientSocketSize); // cleaning the structure
SOCKET connectionSocket = ::accept(pTLM->m_serverSocket, &clientSocketAddr, &nClientSocketSize); // waiting for client's request
if (connectionSocket != INVALID_SOCKET)
{
if (bContinueRun)
{
// Running a separate thread to handle this request
REQUEST_CONTEXT rc;
rc.pTLM = pTLM;
rc.connectionSocket = connectionSocket;
HANDLE hRequestThread = ::CreateThread(NULL, 0, CTiledLayersManager::ProcessRequest, (LPVOID)&rc, CREATE_SUSPENDED, NULL);
// Storing created thread's handle to be able to close it later
// ...
// Starting suspended thread
::ResumeThread(hRequestThread);
}
}
// Checking whether thread is signaled to stop...
// ...
}
// Waiting for all child threads to over...
// ...
}
Testing this implementation manually gives me the desired results. But when I send multiple requests generated by JMeter I can see that some of them are not handled properly by DWORD CMyServer::ProcessRequest(LPVOID). Looking at log file created by ProcessRequest I determine 10038 WinSock error code (meaning that ::recv call was tried on nonsocket), 10053 error code (Software caused connection abort) or even 10058 error code (Cannot send after socket shutdown). But the 10038th error occurs more often than others mentioned.
It looks like a socket was closed somehow but I close it only after ::recv and ::send have been called in ProcessRequest. I also thought that it can be an issue related to using ::CreateThread instead of ::_beginthreadex but as I can get it could only lead to memory leaks. I don't have any memory leaks detected by the method described here so I have doubts that it is the reason. All the more, ::CreateThread returns a handle that can be used in ::WaitForMultipleObjects to wait for threads to be over, and I need it to stop my server properly.
Could these errors occur due to a client doesn't want to wait for response anymore? I am out of ideas, and I will thank you if you tell me what I am missing or doing/understanding wrong. By the way, both my server and JMeter run on the localhost.
Finally, here is my implementation of ProcessRequest method:
DWORD CMyServer::ProcessRequest(LPVOID pInstance)
{
REQUEST_CONTEXT* pRC = (REQUEST_CONTEXT*)pInstance;
CMyServer* pTLM = pRC->pTLM;
SOCKET connectionSocket = pRC->connectionSocket;
// Retrieving client's request
const DWORD dwBuffLen = 1 << 15;
char buffer[dwBuffLen];
ZeroMemory(buffer, sizeof(buffer));
if (::recv(connectionSocket, buffer, sizeof(buffer), NULL) == SOCKET_ERROR)
{
stringStream ss;
ss << "Unable to receive client's request with the following error code " << ::WSAGetLastError() << ".";
pTLM->Log(ss.str(), TLM_LOG_TYPE_ERROR);
::SetEvent(pTLM->m_hRequestCompleteEvent);
return 0;
}
string str = "HTTP/1.1 200 OK\nContent-Type: text/plain\n\nHello World!";
if (::send(connectionSocket, str.c_str(), str.length(), 0) == SOCKET_ERROR)
{
stringStream ss;
ss << "Unable to send response to client with the following error code " << ::WSAGetLastError() << ".";
pTLM->Log(ss.str(), TLM_LOG_TYPE_ERROR);
::SetEvent(pTLM->m_hRequestCompleteEvent);
return 0;
}
::closesocket(connectionSocket);
connectionSocket = NULL;
pTLM->Log(string("Request has been successfully handled."));
::SetEvent(pTLM->m_hRequestCompleteEvent);
return 0;
}
You pass a pointer to the REQUEST_CONTEXT to every newly created thread. However this is an automatic variable, allocated on the stack. Hence its lifetime is limited to its scope. It ends right after you call ResumeThread.
Practically what happens is that the same memory for REQUEST_CONTEXT is used in every loop iteration. Now imagine you accept 2 connections in a short time internal. It's likely that at the time the first thread starts execution its REQUEST_CONTEXT will already be overwritten. So that you actually have 2 threads serving the same socket.
The easiest fix is to allocate the REQUEST_CONTEXT dynamically. That is, allocate it upon new accept, pass its pointer to the new thread. Then during the thread termination don't forget to delete it.
When creating the thread to handle requests, you give the address to a local variable as argument to the thread. The data of this pointer will not be valid as soon as the local variable is out of scope. Create it dynamically with new and delete it in the thread.
I need the fastest way to see if an ip address is reachable. On each ip address theres a server listening on a specific port so let me know if your method is about to find if a server is listening on a port.
The reason for this is that suppose I have 10 ip addresses with 10 server listening on port 101 on each ip address. I want my client be able to find a Reachable ip address and connect to it as fast as he can(I don't want him to wait 30 seconds to find out if a ip address is reachable and then try the next ip address in the list)
May be it has to be done in treads simultaneously.
While you can quickly determine that an IP is reachable, your problem is determining that an IP is not reachable. The reason why is that you can't always definitively determine that an IP is not reachable. While there are some conditions where you will be given an affirmative notice that the IP is not reachable, usually your code will just not hear an answer and after waiting for some amount of time, your code will assume the IP is not reachable.
The problem in deciding the timeout is network topology. If you have a large topology (such as the Internet), you will need a large timeout to deal with potentially high latencies if you try to connect to an IP that is 'far' away.
From your description, the best idea would be to try to connect to all servers at the same time and use the first one that accepts the connection. You can use threads or you can use non-blocking sockets. In a non-blocking connect, the connect call returns immediately and you then use select to efficiently determine when the connect call has completed (either successfully or with an error).
You could use threads, but it would introduce unnecessary overhead for this task.
Use non-blocking sockets here (and avoid non-blocking sockets wherever you can! really, but they make sense in this case):
// initiate tcp connects...
for( each of your target host+port pairs ) {
int socket = socket( AF_INET, SOCK_STREAM );
...
#ifdef WIN32
unsigned long mode = 1;
ioctlsocket( socket, FIONBIO, &mode );
#else
int value = fcntl( socket, F_GETFL, 0 );
fcntl( socket, F_SETFL, value | O_NONBLOCK );
#endif
...
int code = connect( s, target, ... );
if( code == 0 ) { /* ok, this one did connect, DONE */ }
// now remember the socket in a list ...
}
// now find the first socket that was successfully connected
while( still not found ) {
struct timeval tval;
memset( &tval, 0, sizeof(tval) );
fd_set write_set, error_set;
int largest_socket = 0;
// add sockets to write and error set, and determine largest socket no.
for( each socket that did not fail until now ) {
FD_SET( socket, write_set );
FD_SET( socket, error_set );
if( socket > largest_socket ) largest_socket = socket;
}
// now use select to wait until something happens on the sockets
int code = select( largest_socket+1, NULL, &write_set, &error_set, &tval );
if( code < 0 ) { something went terribly wrong }
else {
for( each socket that did not fail until now ) {
if( FD_ISSET( socket, write_set ) ) { you've found it! DONE }
if( FD_ISSET( socket, error_set ) ) { error, remove this socket from list (for next iteration) }
}
}
}
Check documentation for connect and select for more details!
Typically randomly trying to connect with a short time out is sufficient.
Reachability is not very important, the fact that a route exists from you to the server isn't what matters, whether you can connected to said server is. Typically your own code will run just as fast as any other reachability method you can devise.
If you are having problems with it taking too long then try adjusting the length of your response, or having tighter timeouts.
Simple algorithm:
shuffle IP addresses
foreach IP in addresses
attempt connect
if succeed then
break
Try to open a socket using the connect() function from a BSD socket library. Its as fast as you can get, if the port is not open it wont respond to the SYN packet.
The key issue, as you realize, is tying up a thread which has to wait for a SYN-ACK before it can do anything else. Luckily, you do not need threads to parallelise IO anymore; however programming asynchronous operations can be subtle; therefore, I would recommend the libevent library for dispatching TCP/IP connect operations in parallel... since the kernel is doing the heavy lifting you only need one thread to do it on. You could probably do 100's or thousands of connects a second using libevent -- depending on your network hardware.
Another alternative is Boost::ASIO which is more complicated. But since you are using C++ might suite you better.
Below is code that you can use to create outgoing connections concurrently.
Iterate over your IPs and SpawnOutgoing connections in your loop.
Each connection conn_t* is posted as LParam in a window message - concurrently.
You should monitor the messages and save somewhere only the first connection - ignore (delete) other connections.
#define MSG_NEW_CONNECTION (WM_USER + 1)
struct conn_t {
SOCKET s;
sockaddr_in server;
};
static
UINT OutgoingWorker(LPVOID param)
{
// `param` holds "conn_t*"
assert(param);
if (!param) return 0;
conn_t* c = (conn_t*)param;
if (SOCKET_ERROR == connect(c->s, (SOCKADDR*)&c->server, sizeof c->server)) {
closesocket(c->s);
return 0;
}
PostMessage(mainwnd, MSG_NEW_CONNECTION, 0, (LPARAM)c); // <-- mainwnd handle
return 0;
}
conn_t*
SpawnOutgoing(const char* dest_ip, const USHORT dest_port)
{
if (!dest_ip) return NULL;
SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == s) {
return NULL;
}
conn_t* c = new conn_t;
// Create the socket here but connect it in the worker
memset(&c->server, 0, sizeof sockaddr_in);
c->server.sin_family = AF_INET;
c->server.sin_addr.s_addr = inet_addr(dest_ip);
c->server.sin_port = htons(dest_port);
c->s = s;
CreateThread(0, 0, OutgoingWorker, c);
return c;
}