POCO C++ Getting only one notification when socket is readable? - c++

I now writing game server and here is my onReadable function :
void CSConnection::onReadable(const AutoPtr<ReadableNotification>& pNf)
{
try
{
char * rbuff = new char[128](); //allocate incoming packet memory
int n = _socket.receiveBytes(rbuff, 128);
if(n > 8)
{
WorkerThreadPool::getInstance().tp->start(*new LogicHandler(*this, rbuff));
}
else
{
delete rbuff;
delete this;
}
}
catch(Poco::Exception& exc)
{
app.logger().log(exc);
delete this;
}
}
I tried to move reading packet in thread pool's logic handler, but notification is called multiply.
Is there a way to get only one notification ?
Because reading in thread is slower and it calls 5-9 times onReadable.
Thanks.

Related

Socket Handle Read Is never read In Ns3

I stayed many days to find where the error is and I'm stuck.Can anyone help me please.
MY application is a clustering program in NS3 that was written from one else and free to anyone.
The program is run and no errors and print messages but always the number of neighbors in every Cluster Head CH is zero, this mean that the hellow messages are not reach every node and every node consider itself as cluster head because it dosn't see any neighbor node!. every node (vehicle) has two sockets one for send data m_socket and one for listening m_socketlistening, the code is:
if (!m_socket)
{
// TypeId::LookupByName ("ns3::UdpSocketFactory
TypeId m_tid = TypeId::LookupByName("ns3::UdpSocketFactory");
//m_socket = Socket::CreateSocket(GetNode() , TypeId::LookupByName("ns3::UdpSocketFactory"));
m_socket = Socket::CreateSocket(GetNode(), m_tid);
// i added the down line
// InetSocketAddress remote = InetSocketAddress(Ipv4Address::GetBroadcast(),80);
if (Inet6SocketAddress::IsMatchingType(m_peer))
{
m_socket->Bind6();
}
else if (InetSocketAddress::IsMatchingType(m_peer)
|| PacketSocketAddress::IsMatchingType(m_peer))
{
m_socket->Bind();
}
m_socket->SetAllowBroadcast(true);
m_socket->ShutdownRecv();
m_socket->SetConnectCallback(
MakeCallback(&V2vControlClient::ConnectionSucceeded, this),
MakeCallback(&V2vControlClient::ConnectionFailed, this));
//m_socket->Connect(Ipv4Address::GetBroadcast());
m_socket->Connect(m_peer);
}
now this is a part pf the listening socket creation
if (!m_socketListening)
{
NS_LOG_UNCOND("\n ...creating socket muhsen...");
m_socketListening = Socket::CreateSocket(GetNode(), m_tidListening);
m_socketListening->Bind(m_peerListening);
m_socketListening->Listen();
m_socketListening->ShutdownSend();
if (addressUtils::IsMulticast(m_peerListening))
{
Ptr<UdpSocket> udpSocket = DynamicCast<UdpSocket>(m_socketListening);
if (udpSocket)
{
// equivalent to setsockopt (MCAST_JOIN_GROUP)
udpSocket->MulticastJoinGroup(0, m_peerListening);
}
else
{
NS_FATAL_ERROR("Error: joining multicast on a non-UDP socket");
}
}
}
m_socketListening->SetRecvCallback(MakeCallback(&V2vControlClient::HandleRead, this));
m_socketListening->SetAcceptCallback(
MakeNullCallback<bool, Ptr<Socket>, const Address &>(),
MakeCallback(&V2vControlClient::HandleAccept, this));
m_socketListening->SetCloseCallbacks(
MakeCallback(&V2vControlClient::HandlePeerClose, this),
MakeCallback(&V2vControlClient::HandlePeerError, this));
void V2vControlClient::HandleRead (Ptr<Socket> socket)
{
NS_LOG_UNCOND("\n this message is never executed..");
NS_LOG_FUNCTION (this << socket);
Ptr<Packet> packet;
Address from;
while ((packet = socket->RecvFrom(from)))
{
if (packet->GetSize() == 0)
{ //EOF
break;
}
When i run the application the first statement after the HandleRead Function which is
NS_LOG_UNCOND("\n this message is never executed..");
is never printed when run the program, this means that the handle read is never executed.
Any help is very appreciate!

Writing Data to Poll Invalid Socket Causes Uncatchable Exception

I am working on a game server that uses sockets and implemented a polling function that sends the message "[POLL]" over all player sockets in a lobby every second to notify the player clients that their connection is still alive.
If I disconnect on the client-side the socket is still polled with no errors, however, if I create a new connection with the same client (Gets a new FD and is added to the map as a second player), the whole server crashes without any exceptions/warnings/messages when it attempts to write to the previous socket FD. My call to Write on the socket is wrapped in a try/catch that doesn't catch any exceptions and, when debugging using gdb, I am not given any error messaging.
This is the Socket Write function:
int Socket::Write(ByteArray const& buffer)
{
if (!open)
{
return -1;
}
// Convert buffer to raw char array
char* raw = new char[buffer.v.size()];
for (int i=0; i < buffer.v.size(); i++)
{
raw[i] = buffer.v[i];
}
// Perform the write operation
int returnValue = write(GetFD(), raw, buffer.v.size()); // <- Crashes program
if (returnValue <= 0)
{
open = false;
}
return returnValue;
}
And this is the Poll function (Players are stored in a map of uint -> Socket*):
/*
Polls all connected players to tell them
to keep their connections alive.
*/
void Lobby::Poll()
{
playerMtx.lock();
for (auto it = players.begin(); it != players.end(); it++)
{
try
{
if (it->second != nullptr && it->second->IsOpen())
{
it->second->Write("[POLL]");
}
}
catch (...)
{
std::cout << "Failed to write to " << it->first << std::endl;
}
}
playerMtx.unlock();
}
I would expect to see the "Failed to write to " message but instead the entire server program exits with no messaging. What could be happening here?
I was unable to find a reason for the program crashing in the call to write but I was able to find a workaround.
I perform a poll operation on the file descriptor prior to calling write and I query the POLLNVAL event. If I receive a nonzero value, the FD is now invalid.
// Check if FD is valid
struct pollfd pollFd;
pollFd.fd = GetFD();
pollFd.events = POLLNVAL;
if (poll(&pollFd, 1, 0) > 0)
{
open = false;
return -1;
}

Cant put Accept() (CSocket) in its own thread

I use blocking server-client to do a FTP homework.
But i got stuck when try to put Accept into a thread. (Everytime i run the CServer , it crahses and shut down)
Anyone know the answer or can suggest me sth else. i really appreciate it.
I really want to use blocking and CSocket ,so dont't suggest me non-blocking
I also took a look at p_thread, but i still won't if any chance my code works
void CServerDlg::OnBnClickedListen()
{
// TODO: Add your control notification handler code here
if (listen.Create(PORT, SOCK_STREAM, _T("127.0.0.1")) == 0) {
showMessage("Failed to init socket");
listen.GetLastError();
return;
}
else {
if (listen.Listen(1) == FALSE) {
showMessage("Can't listen to the port");
listen.Close();
return;
}
}
connectThread = thread(&CServerDlg::ThreadMain, this);
}
void CServerDlg::ThreadMain() {
int cnt = -1;
CSocket* client;
while (1)
{
client = new CSocket();
if (listen.Accept(*client)) // it crashes everytime i got here
{
cnt++;
char * id = Converter::StringToChar(Converter::NumberToString(*client));
clients.push_back(client);
ClientId.push_back(id);
showMessage("Found a connection with client " + Converter::CharToString(id));
/*
Thread here
*/
threads.push_back(thread(&CServerDlg::ThreadProc, this, cnt));
}
else break;
}
}

Some progress.Send calls not making it to nodejs land

I've made a Node addon using AsyncProgressWorker thread to handle my socket messages. Here is my code:
class ProgressWorker : public AsyncProgressWorker {
public:
ProgressWorker(
Callback *callback
, Callback *progress)
: AsyncProgressWorker(callback), progress(progress) {}
~ProgressWorker() {}
void Execute (const AsyncProgressWorker::ExecutionProgress& progress) {
char response[4096];
int result;
int connected = 1;
int timeout = 0;
int pending = 0;
while(connected) {
result = sctp_recvmsg(sock, (void *)&response, (size_t)sizeof(response), NULL, 0, 0, 0);
if (result > 0 && result < 4095) {
if (debug) {
printf("Server replied (size %d)\n", result);
}
pending = 0;
progress.Send((const char *)response, size_t(result));
result = 0;
}
else {
// Don't mind my timeout mechanism. :))
if ((result == -1 && errno != EWOULDBLOCK) || pending) {
if (timeout == 0) {
printf("Can't receive from other end. Waiting for 3 seconds. Error code: %d\n", errno);
pending = 1;
}
if (timeout >= 3000) {
connected = 0;
close(sock);
}
else {
timeout += 5;
usleep(5000);
}
}
else {
usleep(5000);
}
}
}
}
void HandleProgressCallback(const char *data, size_t count) {
HandleScope scope;
v8::Local<v8::Value> argv[] = {
CopyBuffer(const_cast<char*>(data), count).ToLocalChecked()
};
progress->Call(1, argv); // This is the callback to nodejs
}
private:
Callback *progress;
};
Now I haven't stress-tested this until tonight then I noticed that some messages won't make it back to node. It will print my "Server replied" debug log but won't log my debug logs I put on the progress callback. Am I missing something here? Thanks in advance.
AsyncProgressWorker is based on a uv_async_t, which allows any thread to wake the main thread. However, as stated in the documentation:
libuv will coalesce calls to uv_async_send(), that is, not every call
to it will yield an execution of the callback. For example: if
uv_async_send() is called 5 times in a row before the callback is
called, the callback will only be called once. If uv_async_send() is
called again after the callback was called, it will be called again.
^^ This is the reason that you may sometimes not receive some events while your application is under stress. Above this line is the answer to the question. Below is my "above and beyond" possible solution to deal with your problem:
It so happens that I am working on adding a new alternative to AsyncProgressWorker that promises to deliver every event, just as AsyncProgressWorker does, but using a queue. This feature was recently merged into NAN. If you want to test it, try out the git repository at https://github.com/nodejs/nan , and then replace your AsyncProgressWorker with AsyncProgressQueueWorker<char> Re-run your tests and all events will be delivered.
The pull request to add this new feature is here: https://github.com/nodejs/nan/pull/692 - merged on Oct 6, 2017.
This new feature was released in NAN version 2.8.0
You can use this new class template by altering your package.json to use nan version 2.8.0 or later:
"dependencies": {
"nan": "^2.8.0"
},

Access violation reading location. Heap corruption. Boost thread

I'm trying to create an multithreaded graphical network application using boost, raknet and irrlicht.
I use one thread that receives messages and another thread to proccess the messages and all the graphical work.
this is the error screen I'm getting
First-chance exception at 0x77183c8d in
NetSystemForVideogamesServerTester.exe: 0xC0000005: Access violation reading location 0x0d99d472
this is the output window information
HEAP[NetSystemForVideogamesServerTester.exe]: HEAP: Free Heap block
da58d10 modified at da58fe0 after it was freed Windows has triggered a
breakpoint in NetSystemForVideogamesServerTester.exe.
This may be due to a corruption of the heap, which indicates a bug in
NetSystemForVideogamesServerTester.exe or any of the DLLs it has
loaded.
This may also be due to the user pressing F12 while
NetSystemForVideogamesServerTester.exe has focus.
The output window may have more diagnostic information.
this is when I launch the thread
void receive()
{
boost::thread(&IConnectionInstance::receiveInThread, this);
}
mutex declaration
boost::mutex mMessagesReceived;
this is the code from the receiving thread
void RakNetConnectionInstance::receiveInThread()
{
Packet* packet;
IMessage* message = NULL;
long time = 0;
while (true)
{
message = NULL;
packet = aPeer->Receive();
while (packet)
{
RakNet::BitStream* dataStream = new RakNet::BitStream(packet->data, packet->length, false);
dataStream->IgnoreBits(sizeof(unsigned char)*8);
switch (packet->data[0])
{
case ID_TIMESTAMP:
{
dataStream->Read(time);
int countMessagesAggregated = 0;
dataStream->Read(countMessagesAggregated);
unsigned char messageType = char();
IBitStream* bitStream = new RakNetBitStream(dataStream);
while(countMessagesAggregated > 0)
{
dataStream->Read(messageType);
switch ((EMESSAGE_TYPE)messageType)
{
case EACTOR_CONTENT_MESSAGE:
message = new CActorContentMessage(aUserDataFactory);
break;
case EWORLD_CONTENT_MESSAGE:
message = new CWorldClientContentMessage(aUserDataFactory);
break;
case EUSER_COMMAND_MESSAGE:
message = new CUserCommandMessage(aEventFactory);
break;
case EPREDICTION_MESSAGE:
message = new CPredictionMessage(aUserDataFactory);
break;
case EPREDICTION_RESPONSE_MESSAGE:
message = new CPredictionResponseMessage(aUserDataFactory);
break;
}
countMessagesAggregated --;
if (messageType >= EUSER_MESSAGE && aCustomReceiver)
{
aCustomReceiver->receiveCustomMessages();
}
if (message)
{
message->readFromBitStream(bitStream);
message->setTimeMS(time);
message->setIPAddress(packet->systemAddress.ToString(false));
message->setPort(packet->systemAddress.port);
mMessagesReceived.lock();
aMessagesReceivedQueue.push(message);
printf("adicionando mensaje a cola en lock\n");
mMessagesReceived.unlock();
message = NULL;
}
}
}
break;
}
if (message)
{
message->setTimeMS(time);
message->setIPAddress(packet->systemAddress.ToString(false));
message->setPort(packet->systemAddress.port);
mMessagesReceived.lock();
aMessagesReceivedQueue.push(message);
mMessagesReceived.unlock();
}
aPeer->DeallocatePacket(packet);
packet = aPeer->Receive();
}
if (RakNet::GetTimeMS() - aBeginTimeSearchServersActives > aWaitTimeServersActives && !aTimeOut)
{
boost::mutex::scoped_lock lock(mTimeOut);
aTimeOut = true;
}
}
}
here I attend the messages from queue in the proccessing thread
void CMessageManager::attendMessages()
{
std::queue<IMessage*> messages = aConnectionInstance->getMessagesReceivedFromQueue();
while(!messages.empty())
{
notifyMessage(messages.back());
aConnectionInstance->popMessageReceivedFromQueue();
messages.pop();
}
}
here I access the message queue
std::queue<IMessage*> RakNetConnectionInstance::getMessagesReceivedFromQueue()
{
boost::mutex::scoped_lock lock(mMessagesReceived);
std::queue<IMessage*> messages;
messages = aMessagesReceivedQueue;
return messages;
}
and finally here I delete the message from queue
void RakNetConnectionInstance::popMessageReceivedFromQueue()
{
boost::mutex::scoped_lock lock(mMessagesReceived);
if (!aMessagesReceivedQueue.empty())
{
aMessagesReceivedQueue.pop();
}
}
I'm new to c++ and multithreading, Please help me, What am I doing wrong?
Thanks in advance.
You don't remove the messages from the original queue, you just copy the pointers to a new queue. So the following happens:
You receive a message. A pointer to it goes on the queue.
You copy the queue, process the message, and delete it.
You receive another message.
You copy the queue. It still contains a pointer to the first message though.
You access the pointer to the first message that you deleted.
This code is broken because it copies the queue leaving the original unmodified:
std::queue<IMessage*> RakNetConnectionInstance::getMessagesReceivedFromQueue()
{
boost::mutex::scoped_lock lock(mMessagesReceived);
std::queue<IMessage*> messages;
messages = aMessagesReceivedQueue;
return messages;
}