I have used C++ & Winsock2 to create both server and client applications. It currently handles multiple client connections by creating separate threads.
Two clients connect to the server. After both have connected, I need to send a message ONLY to the first client which connected, then wait until a response has been received, send a separate message to the second client.
The trouble is, I don't know how I can target the first client which connected.
The code I have at the moment accepts two connections but the message is sent to client 2.
Can someone please give me so ideas on how I can use Send() to a specific client? Thanks
Code which accepts the connections and starts the new threads
SOCKET TempSock = SOCKET_ERROR; // create a socket called Tempsock and assign it the value of SOCKET_ERROR
while (TempSock == SOCKET_ERROR && numCC !=2) // Until a client has connected, wait for client connections
{
cout << "Waiting for clients to connect...\n\n";
while ((ClientSocket = accept(Socket, NULL, NULL)))
{
// Create a new thread for the accepted client (also pass the accepted client socket).
unsigned threadID;
HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, &ClientSession, (void*)ClientSocket, 0, &threadID);
}
}
ClientSession()
unsigned __stdcall ClientSession(void *data)
{
SOCKET ClientSocket = (SOCKET)data;
numCC ++; // increment the number of connected clients
cout << "Clients Connected: " << numCC << endl << endl; // output number of clients currently connected to the server
if (numCC <2)
{
cout << "Waiting for additional clients to connect...\n\n";
}
if (numCC ==2)
{
SendRender(); // ONLY TO CLIENT 1???????????
// wait for client render to complete and receive Done message back
memset(bufferReply, 0, 999); // set the memory of the buffer
int inDataLength = recv(ClientSocket,bufferReply,1000,0); // receive data from the server and store in the buffer
response = bufferReply; // assign contents of buffer to string var 'message'
cout << response << ". " << "Client 1 Render Cycle complete.\n\n";
SendRender(); // ONLY TO CLIENT 2????????????
}
return 0;
}
Sendrender() function (sends render command to the client)
int SendRender()
{
// Create message to send to client which will initialise rendering
char *szMessage = "Render";
// Send the Render message to the first client
iSendResult = send(ClientSocket, szMessage, strlen(szMessage), 0); // HOW TO SEND ONLY TO CLIENT 1???
if (iSendResult == SOCKET_ERROR)
{
// Display error if unable to send message
cout << "Failed to send message to Client " << numCC << ": ", WSAGetLastError();
closesocket(Socket);
WSACleanup();
return 1;
}
// notify user that Render command has been sent
cout << "Render command sent to Client " << numCC << endl << endl;
return 0;
}
You can provide both a wait function and a control function to the thread by adding a WaitForSingleObject (or WaitForMultipleObjects) call. Those API calls suspend the thread until some other thread sets an event handle. The API return value tells you which event handle was set, which you can use to determine which action to take.
Use a different event handle for each thread. To pass it in to a thread you will need a struct that contains both the event handle and the socket handle you are passing now. Passing a pointer to this struct into the thread is a way to, in effect, pass two parameters.
Your main thread will need to use CreateEvent to initialize the thread handles. Then after both sockets are connected it would set one event (SetEvent), triggering the first thread.
Related
I'm working on a vision-application, which have two modes:
1) parameter setting
2) automatic
The problem is in 2), when my app waits for a signal via TCP/IP. The program is freezing while accept()-methode is called. I want to provide the possibility on a GUI to change the mode. So if the mode is changing, it's provided by another signal (message_queue). So I want to interrupt the accept state.
Is there a simple possibility to interrupt the accept?
std::cout << "TCPIP " << std::endl;
client = accept(slisten, (struct sockaddr*)&clientinfo, &clientinfolen);
if (client != SOCKET_ERROR)
cout << "client accepted: " << inet_ntoa(clientinfo.sin_addr) << ":"
<< ntohs(clientinfo.sin_port) << endl;
//receive the message from client
//recv returns the number of bytes received!!
//buf contains the data received
int rec = recv(client, buf, sizeof(buf), 0);
cout << "Message: " << rec << " bytes and the message " << buf << endl;
I read about select() but I have no clue how to use it. Could anybody give me a hint how to implement for example select() in my code?
Thanks.
Best regards,
T
The solution is to call accept() only when there is an incoming connection request. You do that by polling on the listen socket, where you can also add other file descriptors, use a timeout etc.
You did not mention your platform. On Linux, see epoll(), UNIX see poll()/select(), Windows I don't know.
A general way would be to use a local TCP connection by which the UI thread could interrupt the select call. The general architecture would use:
a dedicated thread waiting with select on both slisten and the local TCP connection
a TCP connection (Unix domain socket on a Unix or Unix-like system, or 127.0.0.1 on Windows) between the UI thread and the waiting one
various synchronizations/messages between both threads as required
Just declare that select should read slisten and the local socket. It will return as soon as one is ready, and you will be able to know which one is ready.
As you haven't specified your platform, and networking, especially async, is platform-specific, I suppose you need a cross-platform solution. Boost.Asio fits perfectly here: http://www.boost.org/doc/libs/1_39_0/doc/html/boost_asio/reference/basic_socket_acceptor/async_accept/overload1.html
Example from the link:
void accept_handler(const boost::system::error_code& error)
{
if (!error)
{
// Accept succeeded.
}
}
...
boost::asio::ip::tcp::acceptor acceptor(io_service);
...
boost::asio::ip::tcp::socket socket(io_service);
acceptor.async_accept(socket, accept_handler);
If Boost is a problem, Asio can be a header-only lib and used w/o Boost: http://think-async.com/Asio/AsioAndBoostAsio.
One way would be to run select in a loop with a timeout.
Put slisten into nonblocking mode (this isn't strictly necessary but sometimes accept blocks even when select says otherwise) and then:
fd_set read_fds;
FD_ZERO(&read_fds);
FD_SET(slisten, &read_fds);
struct timeval timeout;
timeout.tv_sec = 1; // 1s timeout
timeout.tv_usec = 0;
int select_status;
while (true) {
select_status = select(slisten+1, &read_fds, NULL, NULL, &timeout);
if (select_status == -1) {
// ERROR: do something
} else if (select_status > 0) {
break; // we have data, we can accept now
}
// otherwise (i.e. select_status==0) timeout, continue
}
client = accept(slisten, ...);
This will allow you to catch signals once per second. More info here:
http://man7.org/linux/man-pages/man2/select.2.html
and Windows version (pretty much the same):
https://msdn.microsoft.com/pl-pl/library/windows/desktop/ms740141(v=vs.85).aspx
I have a winsock-server, accepting packets from a local IP, which currently works without using IOCP. I want it to be non-blocking though, working through IOCP. Yes I know about the alternatives (select, WSAAsync etc.), but this won't do it for developing an MMO server.
So here's the question - how do I do this using std::thread and IOCP?
I already know that GetQueuedCompletionStatus() dequeues packets, while PostQueuedCompletionStatus() queues those to the IOCP.
Is this the proper way to do it async though?
How can I threat all clients equally on about 10 threads? I thought about receiving UDP packets and processing those while IOCP has something in queue, but packets will be processed by max 10 at a time and I also have an infinite loop in each thread.
The target is creating a game server, capable of holding thousands of clients at the same time.
About the code: netListener() is a class, holding packets received from the listening network interface in a vector. All it does in Receive() is
WSARecvFrom(sockfd, &buffer, 1, &bytesRecv, &flags, (SOCKADDR*)&senderAddr, &size, &overl, 0);
std::cout << "\n\nReceived " << bytesRecv << " bytes.\n" << "Packet [" << std::string(buffer.buf, bytesRecv)<< "]\n";*
The code works, buffer shows what I've sent to myself, but I'm not sure whether having only ONE receive() will suffice.
About blocking - yes, I realized that putting listener.Receive() into a separate thread doesn't block the main thread. But imagine this - lots of clients try to send packets, can one receive process them all? Not to mention I was planning to queue an IOCP packet on each receive, but still not sure how to do this properly.
And another question - is it possible to establish a direct connection between a client and another client? If you host a server on a local machine behind NAT and you want it to be accessible from the internet, for example.
Threads:
void Host::threadFunc(int i) {
threadMutex.lock();
for (;;) {
if (m_Init) {
if (GetQueuedCompletionStatus(iocp, &bytesReceived, &completionKey, (LPOVERLAPPED*)&overl, WSA_INFINITE)) {
std::cout << "1 completion packet dequeued, bytes: " << bytesReceived << std::endl;
}
}
}
threadMutex.unlock(); }
void Host::createThreads() {
//Create threads
for (unsigned int i = 0; i < SystemInfo.dwNumberOfProcessors; ++i) {
threads.push_back(std::thread(&Host::threadFunc, this, i));
if (threads[i].joinable()) threads[i].detach();
}
std::cout << "Threads created: " << threads.size() << std::endl; }
Host
Host::Host() {
using namespace std;
InitWSA();
createThreads();
m_Init = true;
SecureZeroMemory((PVOID)&overl, sizeof(WSAOVERLAPPED));
overl.hEvent = WSACreateEvent();
iocp = CreateIoCompletionPort((HANDLE)sockfd, iocp, 0, threads.size());
listener = netListener(sockfd, overl, 12); //12 bytes buffer size
for (int i = 0; i < 4; ++i) { //IOCP queue test
if (PostQueuedCompletionStatus(iocp, 150, completionKey, &overl)) {
std::cout << "1 completion packet queued\n";
}
}
std::cin.get();
listener.Receive(); //Packet receive test - adds a completion packet n bytes long if client sent one
std::cin.get();}
I am trying to send a file to a server using socket programming. My server and client are able to connect to each other successfully however I am expecting the while loop below to go through the entire file and add it to the server. The issue I am having is that it only send the first chunk and not the rest.
On the client side I have the following:
memset(szbuffer, 0, sizeof(szbuffer)); //Initialize the buffer to zero
int file_block_size;
while ((file_block_size = fread(szbuffer, sizeof(char), 256, file)) > 0){
if (send(s, szbuffer, file_block_size, 0) < 0){
throw "Error: failed to send file";
exit(1);
} //Loop while there is still contents in the file
memset(szbuffer, 0, sizeof(szbuffer)); //Reset the buffer to zero
}
On the server side I have the following:
while (1)
{
FD_SET(s, &readfds); //always check the listener
if (!(outfds = select(infds, &readfds, NULL, NULL, tp))) {}
else if (outfds == SOCKET_ERROR) throw "failure in Select";
else if (FD_ISSET(s, &readfds)) cout << "got a connection request" << endl;
//Found a connection request, try to accept.
if ((s1 = accept(s, &ca.generic, &calen)) == INVALID_SOCKET)
throw "Couldn't accept connection\n";
//Connection request accepted.
cout << "accepted connection from " << inet_ntoa(ca.ca_in.sin_addr) << ":"
<< hex << htons(ca.ca_in.sin_port) << endl;
//Fill in szbuffer from accepted request.
while (szbuffer > 0){
if ((ibytesrecv = recv(s1, szbuffer, 256, 0)) == SOCKET_ERROR)
throw "Receive error in server program\n";
//Print reciept of successful message.
cout << "This is the message from client: " << szbuffer << endl;
File.open("test.txt", ofstream::out | ofstream::app);
File << szbuffer;
File.close();
//Send to Client the received message (echo it back).
ibufferlen = strlen(szbuffer);
if ((ibytessent = send(s1, szbuffer, ibufferlen, 0)) == SOCKET_ERROR)
throw "error in send in server program\n";
else cout << "Echo message:" << szbuffer << endl;
}
}//wait loop
} //try loop
The code above is the setup for the connection between the client and server which works great. It is in a constant while loop waiting to receive new requests. The issue is with my buffer. Once I send the first buffer over, the next one doesn't seem to go through. Does anyone know what I can do to set the server to receive more than just one buffer? I've tried a while loop but did not get any luck.
Your code that sends the file from the server appears to send consecutive sections of the file correctly.
Your code that appears to have the intention of receiving the file from the client performs the following steps:
1) Wait for and accept a socket.
2) Read up to 256 bytes from the socket.
3) Write those bytes back to the socket.
At this point the code appears to go back to waiting for another connection, and keeping the original connection open, and, at least based on the code you posted, obviously leaking the file descriptor.
So, the issues seems to be that the client and the server disagreeing on what should happen. The client tries to send the entire file, and doesn't read from the socket. The server reads the first 256 bytes from the socket, and writes it back to the client.
Of course, its entirely possible that portions of the code not shown implement some of the missing pieces, but there's definitely a disconnect here between what the sending side is doing, and what the receiving side is doing.
buffer will only send once to the server
No, your server is only reading once from the client. You have to loop, just like the sending loop does.
I'm trying to get FD_CLOSE event (c++) by WSAWaitForMulipleObjects. in the WSASelectEvent I've set only the FD_CLOSE. however, the wait return, and the network enumaration also return 0, but NetworkEvents return 0 from the enumaration so I can't see FD_CLOSE in it.
Any help?
thanks.
void EventThread(void* obj)
{
WSANETWORKEVENTS NetworkEvents;
WSAEVENT EventArray[WSA_MAXIMUM_WAIT_EVENTS];
DWORD EventTotal = 0;
EventArray[EventTotal] = WSACreateEvent();
EventTotal++;
int res;
int index;
if(WSAEventSelect(_socket, EventArray[EventTotal - 1], FD_CLOSE)==SOCKET_ERROR)
Logger::GetInstance() << "WSAEventSelect failed with error " << WSAGetLastError() << endl;
bool bResult;
while(true)
{
if((index = WSAWaitForMultipleEvents(EventTotal, EventArray, FALSE, WSA_INFINITE, FALSE))==WSA_WAIT_FAILED)
{
Logger::GetInstance() << "WSAWaitForMultipleEvents failed with error " << WSAGetLastError() << endl;
}
if ((index != WSA_WAIT_FAILED) && (index != WSA_WAIT_TIMEOUT)) {
res = WSAEnumNetworkEvents(_socket, EventArray[index - WSA_WAIT_EVENT_0], &NetworkEvents) ;
if(NetworkEvents.lNetworkEvents & FD_CLOSE)
{
if(NetworkEvents.iErrorCode[FD_CLOSE_BIT] !=0)
{
Logger::GetInstance() << "FD_CLOSE failed with error " << NetworkEvents.iErrorCode[FD_CLOSE_BIT] << endl;
}
else
{
Logger::GetInstance() << "FD_CLOSE is OK!!! " << NetworkEvents.iErrorCode[FD_CLOSE_BIT] << endl;
}
}
}
}
}
The WinSock documentation says the following:
The FD_CLOSE message is posted when a close indication is received
for the virtual circuit corresponding to the socket. In TCP terms,
this means that the FD_CLOSE is posted when the connection goes into
the TIME_WAIT or CLOSE_WAIT states. This results from the remote
end performing a shutdown() on the send side or a closesocket().
FD_CLOSE should only be posted after all data is read from a socket,
but an application should check for remaining data upon receipt of
FD_CLOSE to avoid any possibility of losing data.
Be aware that the application will only receive an FD_CLOSE message
to indicate closure of a virtual circuit, and only when all the
received data has been read if this is a graceful close. It will not
receive an FD_READ message to indicate this condition.
...
Here is a summary of events and conditions for each asynchronous
notification message.
...
FD_CLOSE: Only valid on connection-oriented sockets (for example,
SOCK_STREAM)
When WSAAsyncSelect() called, if socket connection has been closed.
After remote system initiated graceful close, when no data currently available to receive (Be aware that, if data has been
received and is waiting to be read when the remote system initiates a
graceful close, the FD_CLOSE is not delivered until all pending data
has been read).
After local system initiates graceful close with shutdown() and remote system has responded with "End of Data" notification (for
example, TCP FIN), when no data currently available to receive.
When remote system terminates connection (for example, sent TCP RST), and lParam will contain WSAECONNRESET error value.
Note FD_CLOSE is not posted after closesocket() is called.
Pulling out the network cable does not satisfy any of those conditions. This is actually by design, as networks are designed to handle unexpected outages so they can maintain existing connections as best as they can during short outages. Wait a few minutes until the OS times out and see what happens. Also, when you put the cable back in, the OS will validate pre-existing connections and then may or may not reset them at that time.
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.