Advertisement

Server code driving me crazy

Started by March 05, 2003 08:08 PM
1 comment, last by SyntheticHate 21 years, 11 months ago
I'm currently creating a non-blocking server class that using winsock2, but I'm having some problems. I've read an article and used code from a mud as a reference. Maybe I don't know enough about it yet, but I just can't seem to figure out what's wrong. The code isn't commented much at all, but I hope someone can figure it out. Here it is. NonBlockingServer.h

#include "GlobalDefs.h"
#include "GameWorld.h"
#include <winsock2.h>

class CClient
{
public:
	CClient();

	CCharacter *m_pChar;

	sockaddr_in m_sinClient;
	int m_nSinSize;
	SOCKET m_sockClient;

	char *m_byteRecvData;
	char *m_byteSendData[10];
	int m_nSendDataSize[10];

	CClient *m_pNextClient;
	CClient *m_pPrevClient;

	void Send(char *byteData);
	void Send(char *byteData, int nDataSize);
};

class CNonBlockingServer
{
public:
	CNonBlockingServer(unsigned int nPort = 4000, unsigned int nMaxClients = 1);
	~CNonBlockingServer();
	
//private:
	WSADATA m_wsData;			//winsock init data
	sockaddr_in m_sinServer;	//server socket info	
	int m_nSinSize;				//size of server socket info
	SOCKET m_sockServer;		//handle to socket

	unsigned int m_nMaxClients;
	fd_set m_fdRecv,
		   m_fdSend,
		   m_fdError;  //sets of sockets to gather info from

public:
	CClient *m_cClients;
	unsigned int m_nNumClients;
	int m_nNumSocksRdy;

	void PollSockets();
	void ReceiveData();
	void SendData();
	void GetData(CClient *pClient, char *szReturn)  //must be changed for non-text data
	{
		strcpy(szReturn, pClient->m_byteRecvData);  
		*pClient->m_byteRecvData = '\0';
	}
	void DisconnectClient(CClient *pClient);
};
 
NonBlockingServer.cpp

#include "StdAfx.h"
#include "NonBlockingServer.h"

CClient::CClient()
{
	m_byteRecvData = new char[g_nMaxBufLen];
	for(int i = 0; i < 10; i++) m_byteSendData = new char[g_nMaxBufLen];
	*m_byteRecvData = '\0';
}

void CClient::Send(char *byteData)
{
	for(int i = 0; i < 10; i++)
	{
		if(!m_nSendDataSize)
		{
			strcpy(m_byteSendData, byteData);
			m_nSendDataSize = strlen(m_byteSendData);
		}
	}
}

void CClient::Send(char *byteData, int nDataSize)
{
	for(int i = 0; i < 10; i++)
	{
		if(!m_nSendDataSize && nDataSize <= g_nMaxBufLen)
		{
			memcpy(m_byteSendData, byteData, nDataSize);
			m_nSendDataSize = nDataSize;
		}
	}
}

CNonBlockingServer::CNonBlockingServer(unsigned int nPort, unsigned int nMaxClients)
: m_nMaxClients(nMaxClients)
{
	WSAStartup(0x0202, &m_wsData);

	m_sinServer.sin_family      = AF_INET;         
    m_sinServer.sin_port      	= htons(nPort); 
    m_sinServer.sin_addr.s_addr	= htonl(INADDR_ANY);      
	m_nSinSize					= sizeof(sockaddr_in);

	m_sockServer = socket(AF_INET, SOCK_STREAM, 0);  

	bind(m_sockServer, (sockaddr *)&m_sinServer, sizeof(sockaddr));
	listen(m_sockServer, m_nMaxClients);

	m_nNumClients = 0;
}

CNonBlockingServer::~CNonBlockingServer()
{
	CClient *pClient = m_cClients->m_pPrevClient;

	while(pClient != m_cClients)
	{
		closesocket(pClient->m_sockClient);
		pClient = pClient->m_pPrevClient;
		delete pClient->m_pNextClient;
		pClient->m_pNextClient = NULL;
	}

	if(m_cClients)
	{
		closesocket(m_cClients->m_sockClient);
		delete m_cClients;
	}
}

void CNonBlockingServer:<img src="tongue.gif" width=15 height=15 align=middle>ollSockets()
{
	CClient *pClient = m_cClients;
	const timeval tvTimeout = { 0, 0 };
	int nMaxDesc = m_sockServer;

	FD_ZERO(&m_fdRecv);
	FD_ZERO(&m_fdSend);
	FD_ZERO(&m_fdError);
	FD_SET(m_sockServer, &m_fdRecv);

	for(unsigned int i = 0; i < m_nNumClients; i++)
	{
		nMaxDesc = (nMaxDesc > pClient->m_sockClient) ? nMaxDesc : pClient->m_sockClient;
		FD_SET(pClient->m_sockClient, &m_fdRecv);
		FD_SET(pClient->m_sockClient, &m_fdSend);
		FD_SET(pClient->m_sockClient, &m_fdError);
		pClient = pClient->m_pNextClient;
	}

	pClient = m_cClients;
	m_nNumSocksRdy = select(nMaxDesc, &m_fdRecv, &m_fdSend, &m_fdError, &tvTimeout);

	if(m_nNumSocksRdy == SOCKET_ERROR)
	{
		int nError = WSAGetLastError();
		char szError[5];
		sprintf(szError, "%d\n", nError);
		printf(szError);
		return;
	}

	if(FD_ISSET(m_sockServer, &m_fdRecv))
	{
		CClient *pNewClient = new CClient;

		if(m_nNumClients == 0)
			m_cClients = pNewClient;
		else if(m_nNumClients == 1)
		{
			pNewClient->m_pPrevClient = m_cClients;
			pNewClient->m_pNextClient = m_cClients;
			m_cClients->m_pNextClient = pNewClient;
			m_cClients->m_pPrevClient = pNewClient;
		}
		else
		{
			pNewClient->m_pPrevClient = m_cClients->m_pPrevClient;
			pNewClient->m_pNextClient = m_cClients;
			m_cClients->m_pPrevClient->m_pNextClient = pNewClient;
			m_cClients->m_pPrevClient = pNewClient;
		}

		pNewClient->m_sockClient = accept(m_sockServer, (sockaddr *)&pNewClient->m_sinClient, &pNewClient->m_nSinSize);
		m_nNumClients++;
		m_nNumSocksRdy–;

		pNewClient->m_pChar = new CCharacter;  //special logon code
		pNewClient->m_pChar->m_nLogonSeq = 1;  //for the mud
	}

	for(i = 0; i < m_nNumSocksRdy<img src="wink.gif" width=15 height=15 align=middle>
	{
		if(FD_ISSET(pClient->m_sockClient, &m_fdError))
		{
			DisconnectClient(pClient);
			m_nNumSocksRdy–;
		}

		pClient = pClient->m_pNextClient;
	}
}

void CNonBlockingServer::ReceiveData()
{
	if(!m_nNumClients) return;

	CClient *pClient = m_cClients;

	for(unsigned int i = 0; i < m_nNumClients; i++)
	{
		if(FD_ISSET(pClient->m_sockClient, &m_fdRecv))
		{
			recv(pClient->m_sockClient, pClient->m_byteRecvData, g_nMaxBufLen, 0);
			m_nNumSocksRdy–;
		}

		pClient = pClient->m_pNextClient;

		if(!m_nNumSocksRdy && pClient == m_cClients || m_nNumClients == 1) return;
	}
}

void CNonBlockingServer::SendData()
{
	if(!m_nNumClients) return;

	CClient *pClient = m_cClients;

	for(unsigned int i = 0; i < m_nNumClients; i++)
	{
		if(FD_ISSET(pClient->m_sockClient, &m_fdSend))
		{
			if(pClient->m_nSendDataSize > 0)
			{
				send(pClient->m_sockClient, pClient->m_byteSendData[0], pClient->m_nSendDataSize[0], 0);
					
				for(int i = 0; i < 10; i++)
				{
					pClient->m_byteSendData = pClient->m_byteSendData[i+1];
					pClient->m_nSendDataSize = pClient->m_nSendDataSize[i+1];
				}
					
				m_nNumSocksRdy–;
			}

			pClient = pClient->m_pNextClient;

			if(!m_nNumSocksRdy && pClient == m_cClients || m_nNumClients == 1) return;
		}
	}
}

void CNonBlockingServer::DisconnectClient(CClient *pClient)
{
	delete pClient->m_pChar;

	closesocket(pClient->m_sockClient);
	m_nNumClients–;

	delete[] pClient->m_byteRecvData;
	for(int i = 0; i < 10; i++) delete[] pClient->m_byteSendData;

	pClient->m_pNextClient->m_pPrevClient = pClient->m_pPrevClient;
	pClient->m_pPrevClient->m_pNextClient = pClient->m_pNextClient;
	delete pClient;
}
 </pre> 

<SPAN CLASS=editedby>[edited by - SyntheticHate &#111;n March 5, 2003 9:09:59 PM]</SPAN>  </i>   
Sorry, I couldn't figure out how to use the code tags to make it look better.

I also forgot to mention what it's doing wrong..
Well after a connection is accept()ed, I get the error WSAENOTSOCK from WSAGetLastError(). Hope that helps.

[edited by - SyntheticHate on March 5, 2003 9:26:07 PM]
Advertisement
sounds like your listen socket isn''t valid. the following is the function i use to setup my server. i think the INADDR_ANY is causing your problems, this function retrieves the ip from the machine its running on

virtual int StartListening()
{
char szName[256];
int nRet = gethostname(szName, sizeof(szName));
if (nRet == SOCKET_ERROR)
return 0;

HOSTENT* pHost = gethostbyname(szName);
if (pHost == NULL)
return 0;

m_socketListen = socket(AF_INET, SOCK_STREAM, 0);
if (m_socketListen == INVALID_SOCKET)
return 0;

SOCKADDR_IN saServ;
saServ.sin_port = htons(YOUR_PORT_HERE);
saServ.sin_family = AF_INET;
saServ.sin_addr = *((LPIN_ADDR)*pHost->h_addr_list);
nRet = bind(m_socketListen, (LPSOCKADDR)&saServ, sizeof(SOCKADDR_IN));
if (nRet == SOCKET_ERROR)
return 0;

int nNameLen = sizeof(SOCKADDR_IN);
nRet = getsockname(m_socketListen, (LPSOCKADDR)&saServ, &nNameLen);
if (nRet == SOCKET_ERROR)
return 0;

nRet = listen(m_socketListen, SOMAXCONN);
if (nRet == SOCKET_ERROR)
return 0;
return 1;
}

This topic is closed to new replies.

Advertisement