Beispiel #1
0
int TcpServer::processSend()
{
    char *buffer;
    size_t size, sent;
    if (this->stopping) return 0;


    //TODO: I find it dramatic to iterate over all the connections. Maybe 
    //      I could create one eventFd for each connection to notify that
    //      Data is ready to be sent.
    for (auto it = clientList.begin(); it != clientList.end(); it++)
    {
        TcpClient* client = it->second;
        while ((size = client->getTxData(&buffer)) > 0)
        {
            sent = client->getSocket()->send(buffer, size);    
            if (sent == -1)
            {
                if (errno != EAGAIN)
                {
                    LOG("write error. returned " << errno);
                    abort();
                }
                //if EAGAIN, we stop sending and we will get notified by EPOLL when we are ready again
            }
            else if (sent == 0)
            {
                client->onDisconnected();
                clientList.erase(it);
                delete it->second;
                break;
            }
            else
            {
                // this will move us to the next buffer or further in current if partially sent.
                client->onDataSent(sent);
            }
        }

        // after we are finished sending the tx queue, check if the client is failed and close the connection
        if (client->mFailed)
        {
            client->getSocket()->close();
            client->onDisconnected();
            delete client;
            clientList.erase(it);
        }
    }


}
Beispiel #2
0
void* TcpClient::handleFunc(TcpClient* arg)
{
	TcpClient* pClient = (TcpClient*)arg;

	bool bCon(false);
	for (int i = 0; i < CONN_TIMES; i++)
	{
		bCon = pClient->getSocket()->connectToTcp("192.168.208.128", 9999);
		if (bCon)
			break;

		pClient->getSocket()->close();
		//pClient->getSocket()
	}
   
	if (bCon)
	{  
		G.m_nStatus = STATUS_CONNECTED;
		
		thread t(responseFunc, pClient);
		t.detach();		
		while (!pClient->m_bStop)
		{
			unique_lock<mutex> lock(pClient->m_writeMutex);
			if (pClient->m_writeData.getPos() == 0)
				pClient->m_writeCv.wait(lock);

			int nRet = pClient->m_socket.send(pClient->m_writeData.getBuf(), pClient->m_writeData.getPos());
			
			if (nRet < 0)
			{
				pClient->closeAndReConn();
				break;
			}
			else
			{
				pClient->m_writeData.pop(nRet);
			}
		}
		//pClient->requestLogin(G.getSeq());
	}
	else
	{  
        G.m_nStatus = STATUS_DISCONNECT;
    }     
     
    return NULL;      
}
Beispiel #3
0
int TcpServer::processReceive(int socket)
{
    auto it = clientList.find(socket);
    if (it == clientList.end()) return 0;
    
    TcpClient* client = it->second;

    char tmpBuffer[1024];  //TODO: should get a buffer from a buffer pool
    size_t n = 1;
    while (n > 0)
    {
        if (this->stopping)
        {
            n = 0;
            break;
        }
        n = client->getSocket()->read((char*)&tmpBuffer[0], 1024);

        if (n == 0)
        {
            client->onDisconnected();
            clientList.erase(it);
            delete client;
        }
        else if (n == -1)
        {
            n = 0;
            if (errno == ECONNRESET)
            {
                client->onDisconnected();
                clientList.erase(it);
                delete client;
            }
            else 
            {
                if (errno != EAGAIN)
                {
                    LOG("Read error. Returned " << errno);
                    abort();
                }
            }
            break;
        }
        else
        {
            client->onReceive((char*)&tmpBuffer[0], n);            
        }
    }
    
    return n;
}
Beispiel #4
0
void* TcpClient::responseFunc(TcpClient* arg)
{
	TcpClient* pClient = (TcpClient*)arg;
	DataQueue recvDataQueue;
	int nDataLen(-1);
	while (!pClient->m_bStop)
	{
		char recvBuf[65535];
		int nLen(pClient->getSocket()->recv(recvBuf, sizeof(recvBuf) / sizeof(char), 0));
		if (nLen < 0)
		{

		}
		else
		{
			recvDataQueue.push(recvBuf, nLen);
			int nPos(0);
			int nPackage(recvDataQueue.getPos());

			while (1)
			{
				if (nPackage <= 0)
					break;

				CodedInputStream* coded_input = new CodedInputStream((uint8_t*)(recvDataQueue.getBuf() + nPos), recvDataQueue.getPos() - nPos);
				autoptr<CodedInputStream> inputguard(coded_input);

				int nOldPos = coded_input->CurrentPosition();

				uint32_t datalen;
				if (!coded_input->ReadVarint32(&datalen))
				{
					if (nPos > 0)
					{
						recvDataQueue.pop(nPos);
					}
					break;
				}

				int nNewPos = coded_input->CurrentPosition();
				if (nNewPos + datalen > nPackage)
				{
					//一个包没有收整
					if (nPos > 0)
					{
						recvDataQueue.pop(nPos);
					}

					break;
				}
				else if (nNewPos + datalen == nPackage)
				{
					char* data = new char[datalen];
					autoptr_arr<char> arrdata(data);
					if (coded_input->ReadRaw(data, datalen))
					{
						OnPackage(data, datalen);
					}

					recvDataQueue.setPos(0);
					break;
				}
				else
				{
					char* data = new char[datalen];
					autoptr_arr<char> arrdata(data);

					if (coded_input->ReadRaw(data, datalen))
					{
						OnPackage(data, datalen);
					}

					nPackage -= (datalen+nNewPos-nOldPos);
					nPos += (datalen+nNewPos-nOldPos);
				}
			}
		}
	}

	return NULL;
}
void TcpServer::update()
{
	struct pollfd pfd;
	pfd.fd = m_handle;
	pfd.events = POLLIN;
	pfd.revents = 0;

	int result = poll(&pfd, 1, 0);
	if(result > 0)
	{
		// connection established
		struct sockaddr_in addr;
		socklen_t len = sizeof(struct sockaddr_in);
		int newSock = accept(m_handle, (struct sockaddr *)(&addr), &len);
		if(newSock != -1)
		{
			TcpClient * ptc = new TcpClient(newSock, this);
			ptc->addRef();
			m_connections.insert(std::make_pair(newSock, ptc));
			struct pollfd readFd;
			readFd.fd = ptc->getSocket();
			readFd.events = POLLIN|POLLERR|POLLHUP;
			readFd.revents = 0;
			m_connectionSockets.push_back(readFd);
			ptc->onConnectionOpened();
			if(m_service)
				m_service->onConnectionOpened(ptc);
			ptc->release();
		}
	}

	struct pollfd * clients = &m_connectionSockets[0];
	
	int readResult = poll (clients, m_connectionSockets.size (), 0);
	if (readResult > 0)
	{
		std::vector<struct pollfd>::iterator i;
		std::vector<struct pollfd> cs = m_connectionSockets;
		for (i = cs.begin (); i != cs.end (); ++i)
		{
			if ((*i).revents & POLLERR)
			{
				std::map<int, TcpClient *>::iterator f = m_connections.find ( (*i).fd );
				if (f != m_connections.end ())
				{
					TcpClient * c = (*f).second;
					if (c->m_connection)
						c->m_connection->setDisconnectReason("TcpServer::update POLLERR");
					c->onConnectionClosed();
				}
			}
			// POLLERR is mutually exclusive with POLLIN and POLLHUP.
			// POLLIN and POLLHUP are not consistent cross-platform.  Additionally,
			// a POLLHUP doesn't mean that there's not data available.  The best,
			// cross-platform way to check for disconnection is to see if either
			// POLLHUP or POLLIN are set, and then read from the socket.
			// In cases where there's data, we'll just end up checking it next
			// frame anyway.  In cases where there's no data, it means we've
			// disconnected so we can handle cleanup.
			else if( (*i).revents & (POLLIN|POLLHUP) )
			{	

				if (m_inputBuffer == 0)
				{
					m_inputBuffer = new unsigned char[1500];
					m_inputBufferSize = 1500;
				}
				int bytesReceived = recv ( (*i).fd, m_inputBuffer, m_inputBufferSize, 0);
				std::map<int, TcpClient *>::iterator f = m_connections.find ( (*i).fd );
				if (f != m_connections.end ())
				{
					TcpClient * c = (*f).second;
					std::set<TcpClient *>::iterator pd = m_pendingDestroys.find(c);
					if(pd == m_pendingDestroys.end())
					{
						c->addRef();
						if(bytesReceived > 0)
						{
							c->onReceive(m_inputBuffer, bytesReceived);
						}
						else if (bytesReceived == -1)
						{
							if (c->m_connection)
								c->m_connection->setDisconnectReason("TcpServer::update recv returned %d, errno=%d", bytesReceived, errno);
							c->onConnectionClosed();
						}
						else if (bytesReceived == 0)
						{
							// 0 bytes received on a read is the guaranteed signal for a
							// closed connection.
							if (c->m_connection)
								c->m_connection->setDisconnectReason("TcpServer::update recv returned no bytes, singaling a closed socket (bytes=%d, errno=%d", bytesReceived, errno);
							c->onConnectionClosed();
						}
						c->release();
					}
				}
				if (bytesReceived == m_inputBufferSize)
				{
					delete [] m_inputBuffer;
					m_inputBufferSize = m_inputBufferSize * 2;
					m_inputBuffer = new unsigned char [m_inputBufferSize];
				}
			}
		}
		std::set<TcpClient *>::iterator pdIter;
		for(pdIter = m_pendingDestroys.begin(); pdIter != m_pendingDestroys.end(); ++pdIter)
		{
			removeClient((*pdIter));
		}
		m_pendingDestroys.clear();
	}
}