This section of the archives stores flipcode's complete Developer Toolbox collection, featuring a variety of mini-articles and source code contributions from our readers.

 

  Multi-user Network Class
  Submitted by



Here is an unpolished and unfinished TCP/IP & UDP Networking Manager. This is the initial base code for an article I was (well, am) willing to write about multi-user networking. It is a non-blocking, window-based multi-user client-server code with user-defined callbacks. It is easy to use, one extension is available as a simple http download class. Basically I'm publishing it to hear some criticisms. Added to my bad coding style is the absolutely unfinished UDP Manager.

Description from readme.txt:

"This is a technical, OOP C++ programming sample code. You will need some previous C++ programming knowledge to fully understand it. This networking class provides non-blocking, easy to use TCP/IP and UDP client-server objects for networked applications. This is the same code that I use on my networked applications. There is an HTTP class that can do multiple file downloads as well. This code may be updated from time to time. You are free to use this code on anything you desire, as long as you do not state that you wrote the class for yourself. A mention is appreciated if you use this code solution on your own projects."

Regards,
Vander Nunes
http://www.virtware.net

Currently browsing [vnnetclass.zip] (17,401 bytes) - [net.h] - (2,057 bytes)

//====----------------------- --- --   -      -
// MULTIUSER NETWORK MANAGEMENT
// TCP/IP and UDP support.
// ©2000-2002, Vander Nunes
//======----------------------------- --- --   -      -

// ------------------------------------------------------------------------------------------
// applications using net classes should include netserver.h and/or netclient.h
// ------------------------------------------------------------------------------------------

#ifndef _NET_H_

#define _NET_H_ #include <windows.h>

// include wsock32.lib in the link #pragma comment (lib, "wsock32.lib")

// type of socket enum enSockType { stUDP, stTCP };

// a network packet typedef struct _NETPACKET { void *pBuffer; int iLength; } NETPACKET;

// ---------------------------------------------------------------------------------------------- // Net Events - most will be repassed to the user's callback // ---------------------------------------------------------------------------------------------- // internal use #define NET_SELECT WM_USER+10

// internal use by resolver #define NET_RESOLVE WM_USER+11

// new incoming connection #define NET_NEWCONNECTION WM_USER+20

// new outcoming connection #define NET_CONNECTED WM_USER+21

// new data waiting #define NET_NEWDATA WM_USER+22

// client disconnection #define NET_DISCONNECTION WM_USER+23

// refused incoming connection #define NET_REFCONNECTION WM_USER+24

// ----------------------------------------------------------------------------------------------

// ------------------------------------------------------------------------------------------ // this is a private function used by CNetServer and CNetClient classes. // ------------------------------------------------------------------------------------------ HWND NetMakeWindow(const char *szTitle, DWORD dwRefCount, int iWidth, int iHeight, DWORD dwFlags, WNDPROC hWndProc);

#endif

Currently browsing [vnnetclass.zip] (17,401 bytes) - [http.h] - (4,207 bytes)

//====----------------------- --- --   -      -
// MULTIUSER NETWORK MANAGEMENT
// TCP/IP and UDP support.
// ©2000-2002, Vander Nunes
//======----------------------------- --- --   -      -

#ifndef _HTTP_H_

#define _HTTP_H_ #include <windows.h> #include <stdio.h>

// size of socket buffer #define BUFFER_SIZE 1024

class CNetClient;

// download stages enumeration enum enHttpDownStage { dsIdle, dsConn, dsReq, dsRecv, dsFail };

// http get file request // #define HTTP_GETREQUEST "GET %s%s%s HTTP/1.1\nUser-Agent: VirtwareA1\nHost: %s\nConnection: close\r\n\r\n" #define HTTP_GETREQUEST "GET %s%s%s HTTP/1.1\nHost: %s\nConnection: close\n\n"

// request OK, file found #define HTTP_GETOK "200 OK"

// request OK, file found but in another place // (must parse response and build the request again) // ### not used yet #define HTTP_GETOKREDIR "302 Found"

// end of the http header #define HTTP_HEADEREND "\r\n\r\n"

// user's callback #define USR_HTTPCALLBACK(userProc) void (*userProc)(CHttp *pHttp, void *pUserData, enHttpDownStage Stage, DWORD dwBytesDownloaded)

// ---------------------------------------------------------------------------------------------- // // CHttp download class // // ---------------------------------------------------------------------------------------------- class CHttp { friend void HttpClientCallback(CNetClient *pClient, void *pData, int iMsg); friend LRESULT CALLBACK HttpWndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam);

private:

// download stage enHttpDownStage m_Stage;

// hidden window to handle timer timeout HWND m_hWnd;

// flag if a download is in progress BOOL m_bWorking;

// socket CNetClient *m_pClient;

// host, file and target char m_szHost[MAX_PATH]; char m_szFile[MAX_PATH]; char m_szTarget[MAX_PATH];

// proxy info BOOL m_bUseProxy; char m_szProxyAddr[33]; int m_iProxyPort;

// file FILE *m_hFile; DWORD m_dwBytesDownloaded;

// user callback USR_HTTPCALLBACK(m_userProc); void *m_pUserData;

// internal callback void Callback(CNetClient *pClient, int iMsg);

// internal search for string int CHttp::strpos(char *szStr, char *szString);

void CloseDownload(); void Fail();

public:

CHttp(USR_HTTPCALLBACK(userProc), void *pUserData); virtual ~CHttp();

// ------------------------------------------------------------------------------------------ // download a file from a url // ------------------------------------------------------------------------------------------ BOOL Download(char *szHost, char *szFile, char *szTarget, int iPort=80, char *szProxyAddr=NULL, int iProxyPort=0);

// ------------------------------------------------------------------------------------------ // stop a download // ------------------------------------------------------------------------------------------ void Stop();

// ------------------------------------------------------------------------------------------ // return the actual download stage // ------------------------------------------------------------------------------------------ enHttpDownStage Stage() { return m_Stage; }

// ------------------------------------------------------------------------------------------ // tell if a download is in progress // ------------------------------------------------------------------------------------------ BOOL Working() { return m_bWorking; } };

#endif

Currently browsing [vnnetclass.zip] (17,401 bytes) - [net.cpp] - (2,493 bytes)

//====----------------------- --- --   -      -
// MULTIUSER NETWORK MANAGEMENT
// TCP/IP and UDP support.
// ©2000-2002, Vander Nunes
//======----------------------------- --- --   -      -


#include "net.h" #include <stdio.h>

// ------------------------------------------------------------------------ // A Basic, still smart window creation function. // ------------------------------------------------------------------------ HWND NetMakeWindow(const char *szTitle, DWORD dwRefCount, int iWidth, int iHeight, DWORD dwFlags, WNDPROC hWndProc) {

if (dwRefCount == 1) { // our window class WNDCLASS wndWc;

// --------------------------------------------------------- // fill window class members // --------------------------------------------------------- wndWc.style = CS_OWNDC; wndWc.lpfnWndProc = (WNDPROC)hWndProc; wndWc.cbClsExtra = 0; wndWc.cbWndExtra = 0; wndWc.hInstance = GetModuleHandle(NULL); wndWc.hIcon = NULL; wndWc.hCursor = LoadCursor(0, IDC_ARROW); wndWc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndWc.lpszMenuName = NULL; wndWc.lpszClassName = szTitle;

// register class //if (!RegisterClass(&wndWc)) return false; // ### was creating problems with // CNetClient and CNetServer, // like, the user deleted the first instance of NetClient, // then newed[] it again... the reference count was 1 again then, // but the class continued registered. To solve this, // those classes must delete the window class when RefCount reachs zero. // For now, this quick hack will do =) RegisterClass(&wndWc); } // --------------------------------------------------------- // get actual screen resolution int iSw = (WORD)GetSystemMetrics(SM_CXSCREEN); // width int iSh = (WORD)GetSystemMetrics(SM_CYSCREEN); // height // make a rectangle on the center of the screen RECT rc = { (iSw - iWidth)/2, (iSh - iHeight)/2, iWidth, iHeight };

// create the window. the spaces on the window title // are just to make sure this will be visible when the region // is active. just run the app and you'll understand. =) HWND hWnd = CreateWindow(szTitle, szTitle, WS_OVERLAPPEDWINDOW, rc.left,rc.top, iWidth,iHeight, NULL, NULL, GetModuleHandle(NULL), NULL);

// return result return hWnd; }

Currently browsing [vnnetclass.zip] (17,401 bytes) - [http.cpp] - (11,141 bytes)

//====----------------------- --- --   -      -
// MULTIUSER NETWORK MANAGEMENT
// TCP/IP and UDP support.
// ©2000-2002, Vander Nunes
//======----------------------------- --- --   -      -


#include "http.h" #include "netclient.h"



// ------------------------------------------------------------------------------------------------ // // Http Window Procedure // // ------------------------------------------------------------------------------------------------ LRESULT CALLBACK HttpWndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam) {

// get the pointer to the netserver class CHttp *pHttp = (CHttp*)GetProp(hWnd, "http"); if (!pHttp) return DefWindowProc(hWnd,uMessage,wParam,lParam);

// handle the message switch (uMessage) {

case WM_TIMER: { // connection timed out. if (pHttp->m_Stage == dsConn || pHttp->m_Stage == dsReq) pHttp->Fail();

break; }

}

// return default window procedure result return DefWindowProc(hWnd,uMessage,wParam,lParam); }



// ---------------------------------------------------------------------------- // // Private callback for the socket client - just pass to the class callback // // ---------------------------------------------------------------------------- void HttpClientCallback(CNetClient *pClient, void *pData, int iMsg) { CHttp *pHttp = (CHttp*)pData; pHttp->Callback(pClient, iMsg); }



// ------------------------------------------------------------------------------------------------ // // Constructor // // User instantiating the class can provide a callback to receive http events, // and store a pointer to any data wanted. This data will be repassed to the callback. // // ------------------------------------------------------------------------------------------------ CHttp::CHttp(USR_HTTPCALLBACK(userProc), void *pUserData) { m_hFile = NULL; m_pClient = NULL; m_Stage = dsIdle; m_dwBytesDownloaded = 0; m_userProc = userProc; m_pUserData = pUserData; m_bWorking = FALSE;

m_bUseProxy = FALSE; m_szProxyAddr[0] = 0; m_iProxyPort = 0;

m_hWnd = NetMakeWindow("http",1,64,64,WS_OVERLAPPEDWINDOW,HttpWndProc); if (!m_hWnd) throw (1);

SetProp(m_hWnd,"http",this); }



// ------------------------------------------------------------------------------------------------ // // Destructor - closes any pending download before instance destruction. // // ------------------------------------------------------------------------------------------------ CHttp::~CHttp() { CloseDownload(); if (m_hWnd) DestroyWindow(m_hWnd); }



// ------------------------------------------------------------------------------------------------ // // Start a download. // If you need multiple downloads, use multiple instances of the class. // // ex: pHttp->Download("www.virtware.net", "/downs/techdemo.exe", "c:\\downs\\techdemo.exe"); // // ------------------------------------------------------------------------------------------------ BOOL CHttp::Download(char *szHost, char *szFile, char *szTarget, int iPort, char *szProxyAddr, int iProxyPort) { // refuses to start a new download if a download is happening. if (m_bWorking) return FALSE;

// safe check names if (strlen(szHost)>=MAX_PATH || strlen(szFile)>=MAX_PATH || strlen(szTarget)>=MAX_PATH) return FALSE;

if (szProxyAddr) { if (strlen(szProxyAddr) > sizeof(m_szProxyAddr)) return FALSE; }

// check if there is proxy information if (szProxyAddr && iProxyPort) { strcpy(m_szProxyAddr, szProxyAddr); m_iProxyPort = iProxyPort; m_bUseProxy = TRUE; } else m_bUseProxy = FALSE;

try { m_pClient = new CNetClient(stTCP, HttpClientCallback, this, BUFFER_SIZE);

if (!m_bUseProxy) m_pClient->Connect(szHost, iPort); else m_pClient->Connect(szProxyAddr, iProxyPort); } catch (...) { // failed to initialize CNetClient // (maybe because already downloading something?) return FALSE; }

m_Stage = dsConn; strcpy(m_szHost, szHost); strcpy(m_szFile, szFile); strcpy(m_szTarget, szTarget); m_dwBytesDownloaded = 0;

m_bWorking = TRUE;

// callback user function if (m_userProc) m_userProc(this, m_pUserData, m_Stage, m_dwBytesDownloaded);

// set a timer // to timeout the connection+request stages. SetTimer(m_hWnd, 1, 60000, NULL);

return TRUE; }



// ------------------------------------------------------------------------------------------------ // // Private http callback - handles socket connection and data receiving // // ------------------------------------------------------------------------------------------------ void CHttp::Callback(CNetClient *pClient, int iMsg) { char szTmp[512];

switch (iMsg) {

case NET_CONNECTED: { // send GET request to server if (!m_bUseProxy) sprintf(szTmp, HTTP_GETREQUEST, "", "", m_szFile, m_szHost); else sprintf(szTmp, HTTP_GETREQUEST, "http://", m_szHost, m_szFile, m_szHost);

pClient->Send((void*)szTmp,strlen(szTmp)+1);

// change stage m_Stage = dsReq;

// callback user function if (m_userProc) m_userProc(this, m_pUserData, m_Stage, m_dwBytesDownloaded);

break; }

case NET_NEWDATA: {

NETPACKET *pPacket = pClient->Read();

switch (m_Stage) {

// ---------------------------------------------------------------------------------------- // Requesting // ---------------------------------------------------------------------------------------- case dsReq: {

// kill the time out timer KillTimer(m_hWnd, 1);

// expecting server response to GET request if ( strpos(HTTP_GETOK, (char*)pPacket->pBuffer) >= 0 ) { // open the target file m_hFile = fopen(m_szTarget, "wb+"); if (!m_hFile) { // failed to open target file Fail(); return; }

// find the end of the answer header // (the start of the file can be glued at the end of the header) int iFirst = strpos(HTTP_HEADEREND, (char*)pPacket->pBuffer);

// if found the end, see if there is something to write already if (iFirst >= 0) { // skip the header end (will point at the first byte of the file or end of the block) iFirst += strlen(HTTP_HEADEREND);

// check to see if there is data remaining to write yet if (pPacket->iLength > iFirst) { // there is file data already, write it m_dwBytesDownloaded = pPacket->iLength-iFirst; BYTE *p = (BYTE*)pPacket->pBuffer; fwrite(&p[iFirst], 1, m_dwBytesDownloaded, m_hFile); } }

// change stage m_Stage = dsRecv;

// callback user function if (m_userProc) m_userProc(this, m_pUserData, m_Stage, m_dwBytesDownloaded); } else { if (pPacket->iLength < BUFFER_SIZE) { // failed Fail(); } }

break; } // ----------------------------------------------------------------------------------------

// ---------------------------------------------------------------------------------------- // Downloading // ---------------------------------------------------------------------------------------- case dsRecv: {

do {

if (pPacket->iLength > 0) { // write to file fwrite(pPacket->pBuffer, 1, pPacket->iLength, m_hFile);

// update bytes downloaded m_dwBytesDownloaded += pPacket->iLength;

// callback user function if (m_userProc) m_userProc(this, m_pUserData, m_Stage, m_dwBytesDownloaded); }

// get new packet pPacket = pClient->Read();

} while (pPacket->iLength > 0);

// check if there was an error code if (pPacket->iLength == SOCKET_ERROR) { int nRc = WSAGetLastError();

// check why we received an error code if (nRc != WSAEWOULDBLOCK) { // finished - ### guess if this happens here, we failed to download? // Fail(); Stop(); } }

break;

} // ---------------------------------------------------------------------------------------- }

break; }

case NET_DISCONNECTION: { // finished Stop();

break; }

} }



// ------------------------------------------------------------------------------------------------ // // Just close any pending download - doesn't change stage nor call user. // // ------------------------------------------------------------------------------------------------ void CHttp::CloseDownload() { if (m_hFile) { fclose(m_hFile); m_hFile = NULL; }

if (m_pClient) { delete m_pClient; m_pClient = NULL; }

m_bWorking = FALSE; }



// ------------------------------------------------------------------------------------------------ // // Stop a download (with success) // // ------------------------------------------------------------------------------------------------ void CHttp::Stop() { CloseDownload();

m_Stage = dsIdle;

// callback user function if (m_userProc) m_userProc(this, m_pUserData, m_Stage, m_dwBytesDownloaded); }



// ------------------------------------------------------------------------------------------------ // // Stop a download (with fail) // // ------------------------------------------------------------------------------------------------ void CHttp::Fail() { CloseDownload();

m_Stage = dsFail;

// callback user function if (m_userProc) m_userProc(this, m_pUserData, m_Stage, m_dwBytesDownloaded); }



// ------------------------------------------------------------------------------------------------ // // Private helper method - tell where inside szString is located szStr // // ------------------------------------------------------------------------------------------------ int CHttp::strpos(char *szStr, char *szString) { DWORD p = 0;

for (DWORD i=0; i<strlen(szString); i++) { if (szString[i] == szStr[p]) { p++; if (p >= strlen(szStr)) return i-(p-1); } else p = 0; }

return -1; }

Currently browsing [vnnetclass.zip] (17,401 bytes) - [netclient.cpp] - (12,291 bytes)

//====----------------------- --- --   -      -
// MULTIUSER NETWORK MANAGEMENT
// TCP/IP and UDP support.
// ©2000-2002, Vander Nunes
//======----------------------------- --- --   -      -


#include <windows.h> #include "netclient.h"

DWORD CNetClient::m_dwRefCount = 0;

// ------------------------------------------------------------------------------------------------ // // Client Window Procedure // // ------------------------------------------------------------------------------------------------ LRESULT CALLBACK NetClientWndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam) {

// get the pointer to the netserver class CNetClient *pClient = (CNetClient*)GetProp(hWnd, "netclient"); if (!pClient) return DefWindowProc(hWnd,uMessage,wParam,lParam);

// handle the message switch (uMessage) {

case NET_SELECT: { pClient->Select(wParam, lParam); break; }

case NET_RESOLVE: { if ((HANDLE)wParam == pClient->m_hResolver) { // this is our hostbyname result. int nRc = HIWORD(lParam);

switch (nRc) { case 0: { // successful struct hostent *phe = (struct hostent *)pClient->m_szHostData; pClient->ContinueConnect(phe); break; }

case WSAHOST_NOT_FOUND: { // authoritative: host not found break; }

case WSATRY_AGAIN: { // non-authoritative host not found, // or server-fail. break; }

default: { // there are more possible errors, // but we'll treat then as default. break; }

}

} break; }

}

// return default window procedure result return DefWindowProc(hWnd,uMessage,wParam,lParam); }



// ------------------------------------------------------------------------------------------------ // // Construction // // ------------------------------------------------------------------------------------------------ CNetClient::CNetClient(enSockType SockType, USR_CLNTCALLBACK(userProc), void *pUserData, int iBufferSize) { m_bInitialized = FALSE; m_dwRefCount++;

// try to initialize buffers if ( !Init(SockType, userProc, pUserData, iBufferSize) ) throw (0);

// try to create hidden window if ( !(m_hWnd = NetMakeWindow("netclient",m_dwRefCount,64,32,WS_OVERLAPPEDWINDOW,NetClientWndProc)) ) throw (1);

// put our address in the window properties if ( !SetProp(m_hWnd, "netclient", (HANDLE)this) ) throw (2);

m_bInitialized = TRUE; }



// ------------------------------------------------------------------------------------------------ // // Initialization // // ------------------------------------------------------------------------------------------------ BOOL CNetClient::Init(enSockType SockType, USR_CLNTCALLBACK(userProc), void *pUserData, int iBufferSize) { if (m_dwRefCount == 1) { // start winsock WSADATA wsaData; WORD wVersionRequested = MAKEWORD(1,1); WSAStartup(wVersionRequested, &wsaData); }

// clear socket m_Sock = INVALID_SOCKET;

// store connection information m_SockType = SockType; m_userProc = userProc; m_pUserData = pUserData;

// initialize buffer m_iRecvBufferSize = iBufferSize; m_pRecvBuffer = new char[m_iRecvBufferSize]; if (!m_pRecvBuffer) return FALSE;

// point the packet buffer to the receive buffer m_Packet.pBuffer = (void*)m_pRecvBuffer;

return TRUE; }



// ------------------------------------------------------------------------------------------------ // // Close winsock service // // ------------------------------------------------------------------------------------------------ CNetClient::~CNetClient() { m_dwRefCount--;

// disconnect Disconnect();

// remove properties from our window RemoveProp(m_hWnd, "netclient");

// destroy the window DestroyWindow(m_hWnd);

if (!m_dwRefCount) { // close sockets service WSACleanup(); }

// free resources if (m_pRecvBuffer) delete m_pRecvBuffer; }



// ------------------------------------------------------------------------------------------------ // // Connect to a host // // ------------------------------------------------------------------------------------------------ BOOL CNetClient::Connect(char *szHost, int iPort) { // refuses to connect if not initialized if (!m_bInitialized) return FALSE;

// disconnect from any previous host Disconnect();

// store port m_iPort = iPort;

// initialize address memset((LPSTR)&m_MyAddr, 0, sizeof(m_MyAddr)); m_MyAddr.sin_family = PF_INET; m_MyAddr.sin_port = htons(m_iPort);

// resolve host memset(m_szHostData,0,sizeof(m_szHostData)); m_hResolver = WSAAsyncGetHostByName(m_hWnd, NET_RESOLVE, szHost, m_szHostData, MAXGETHOSTSTRUCT); if (!m_hResolver) return FALSE;

return TRUE; }



// ------------------------------------------------------------------------------------------------ // // Continue the connect process to a host // // ------------------------------------------------------------------------------------------------ BOOL CNetClient::ContinueConnect(struct hostent *phe) { int nRc;

// check if resolved correctly if (phe == NULL) return FALSE;

// finish filling socket info if (phe->h_addr_list[0] != NULL) memcpy(&m_MyAddr.sin_addr, *(phe->h_addr_list), sizeof(*(phe->h_addr_list))); else return FALSE;

// -------------------------------------------------------------------------- // start connection // -------------------------------------------------------------------------- // user wants to connect through UDP. if(m_Sock == INVALID_SOCKET) {

if (m_SockType == stUDP) { // UDP m_Sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); } else // TCP m_Sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

if(m_Sock != SOCKET_ERROR) { // set non-blocking bits unsigned long argp = 1; //ioctlsocket(m_Sock, FIONBIO, &argp); } else { // error while initializing UDP m_Sock = INVALID_SOCKET; return FALSE; }

}

// request an asynchronous connection nRc = WSAAsyncSelect(m_Sock, m_hWnd, // our window procedure will be the recipient NET_SELECT, // message to send FD_CONNECT | // tell when a connection is done FD_READ | // tell when new data's here FD_WRITE | // tell when there's buffer space FD_CLOSE); // tell if the other side closes // try connecting to host nRc = connect(m_Sock, (const struct sockaddr *)&m_MyAddr, sizeof(m_MyAddr));

if (nRc == SOCKET_ERROR) {

nRc = WSAGetLastError(); switch (nRc) { default: { // really failed m_Sock = INVALID_SOCKET; return FALSE; }

case WSAEWOULDBLOCK: { // ok, connect is queued... // just ignore it. break; }

}

}

return TRUE; }



// ------------------------------------------------------------------------------------------------ // // Disconnect // // ------------------------------------------------------------------------------------------------ void CNetClient::Disconnect() { // turn off UDP if it's running. if(m_Sock != INVALID_SOCKET) { closesocket(m_Sock); m_Sock = INVALID_SOCKET; } }



// ------------------------------------------------------------------------------------------------ // // Process connection events, that can be either TCP or UDP. // // ------------------------------------------------------------------------------------------------ BOOL CNetClient::Select(int wParam, int lParam) { int nRc, i; unsigned long data = 0; unsigned long four_byte; int namelen = sizeof(m_HostAddr), ilen = sizeof(unsigned long);

// get the involved socket SOCKET sock = (SOCKET)wParam;

switch(WSAGETSELECTEVENT(lParam)) {

case FD_CONNECT: { // // only TCP connections pass here // if (m_userProc) m_userProc(this, m_pUserData, NET_CONNECTED); break; }

case FD_READ: { // // check if really there is need for reading // nRc = ioctlsocket(sock, FIONREAD, (u_long *)&data); if(nRc == SOCKET_ERROR) return FALSE; if(data <= 0 ) return FALSE;

// TCP doesn't fill in the from address on // recvfrom(). Find out if this is UDP or // tcp, and use an appropriate mechanism to // find out who the other end is. i = sizeof(int); getsockopt(sock, SOL_SOCKET, SO_TYPE, (char *)&nRc, (LPINT)&i);

if(nRc == SOCK_DGRAM) { // // UDP datagram // nRc = recvfrom(sock, (LPSTR)&four_byte, (int)ilen, MSG_PEEK, (struct sockaddr *)&m_HostAddr, (LPINT)&namelen); if(nRc == SOCKET_ERROR) { nRc = WSAGetLastError(); if(nRc != WSAEMSGSIZE) return FALSE; } } else { // // TCP packet // nRc = getpeername(sock, (struct sockaddr *)&m_HostAddr, (LPINT)&namelen); } if(nRc == SOCKET_ERROR) return FALSE; data = m_HostAddr.sin_addr.s_addr;

// tell client there is data waiting if (m_userProc) m_userProc(this, m_pUserData, NET_NEWDATA);

break; }

case FD_CLOSE: { // // Only TCP pass here. // // the other side closed the connection. close the socket, // to clean up internal resources. // // receive the disconnection message nRc = recvfrom(sock, (LPSTR)&four_byte, (int)ilen, MSG_PEEK, (struct sockaddr *)&m_HostAddr, (LPINT)&namelen);

// if there is a last bit of data, let user read it. if (nRc > 0) if (m_userProc) m_userProc(this, m_pUserData, NET_NEWDATA);

Disconnect(); if (m_userProc) m_userProc(this, m_pUserData, NET_DISCONNECTION);

break; }

} // end: switch(WSAGETSELECTEVENT(lParam)) return TRUE; }



// ------------------------------------------------------------------------------------------------ // // Send a message to the host. // // ------------------------------------------------------------------------------------------------ void CNetClient::Send(void *Msg, int MsgLen) { if (m_SockType == stTCP) { // // use TCP/IP send() // send(m_Sock, (const char *)Msg, MsgLen, 0); } else { // // use UDP sendto() // sendto(m_Sock, (const char *)Msg, MsgLen, 0, (struct sockaddr *)&m_HostAddr, sizeof(m_HostAddr)); } }



// ------------------------------------------------------------------------------------------------ // // There is data waiting to be read. // Receive that. // Both TCP/IP and UDP pass here, after been 'selected'. // // ------------------------------------------------------------------------------------------------ NETPACKET* CNetClient::Read() { int nRc, nTc=0; int ilen = sizeof(struct sockaddr_in); char *p = (char*)m_pRecvBuffer;

do {

if (m_SockType == stUDP) { nRc = recvfrom( m_Sock, p, m_iRecvBufferSize-nTc, 0, (struct sockaddr *)&m_HostAddr, (LPINT)&ilen ); } else { nRc = recv(m_Sock, p, m_iRecvBufferSize-nTc, 0); }

if (nRc > 0) { nTc += nRc; p += nRc; }

} while (nRc > 0);

if (nTc > 0) m_Packet.iLength = nTc; else m_Packet.iLength = nRc;

return &m_Packet; }

Currently browsing [vnnetclass.zip] (17,401 bytes) - [netclient.h] - (4,666 bytes)

//====----------------------- --- --   -      -
// MULTIUSER NETWORK MANAGEMENT
// TCP/IP and UDP support.
// ©2000-2002, Vander Nunes
//======----------------------------- --- --   -      -

#ifndef _NETCLIENT_H_
#define _NETCLIENT_H_

#include <time.h> #include "net.h"

// ---------------------------------------------------------------------------------------------- // user's callback #define USR_CLNTCALLBACK(userProc) void (*userProc)(CNetClient *pClient, void *pUserData, int iMsg)

// ---------------------------------------------------------------------------------------------- // NetClient class // ---------------------------------------------------------------------------------------------- class CNetClient { // internal window procedure friend LRESULT CALLBACK NetClientWndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam);

private:

// reference count static DWORD m_dwRefCount;

// netclient hidden window HWND m_hWnd;

// connection information SOCKET m_Sock; enSockType m_SockType; int m_iPort;

// receive buffer char* m_pRecvBuffer; int m_iRecvBufferSize;

// a network packet NETPACKET m_Packet;

// client ip address struct sockaddr_in m_MyAddr; // host ip address struct sockaddr_in m_HostAddr;

// flag if the class is correctly initialized BOOL m_bInitialized;

// user callback procedure USR_CLNTCALLBACK(m_userProc); void* m_pUserData;

// used by the non-blocking gethostbyname() HANDLE m_hResolver; char m_szHostData[MAXGETHOSTSTRUCT];

// ------------------------------------------------------------------------------------------ // private methods // ------------------------------------------------------------------------------------------ BOOL Init(enSockType SockType, USR_CLNTCALLBACK(userProc), void *pUserData, int iBufferSize); BOOL Select(int wParam, int lParam);

// after resolving the host, this will // be called to continue connection process BOOL CNetClient::ContinueConnect(struct hostent *phe);

public:

// ------------------------------------------------------------------------------------------ // constructor - user must provide a callback function address to receive network events. // a NULL callback address is accepted but in this case the user can't receive warnings // about connection, disconnection, new packets, etc. // optionally can be passed a pointer to any desired user data. this pointer will be passed // back in any call to the user's callback. // ------------------------------------------------------------------------------------------ CNetClient(enSockType SockType, USR_CLNTCALLBACK(userProc), void *pUserData, int iBufferSize=1024);

// ------------------------------------------------------------------------------------------ // destructor - closes connection, clean resources. // ------------------------------------------------------------------------------------------ virtual ~CNetClient();

// ------------------------------------------------------------------------------------------ // connect to a hostname through specified port. // ------------------------------------------------------------------------------------------ BOOL Connect(char *szHost, int iPort);

// ------------------------------------------------------------------------------------------ // disconnects from actual host. // ------------------------------------------------------------------------------------------ void Disconnect();

// ------------------------------------------------------------------------------------------ // read and return a pointer to a network packet. // ------------------------------------------------------------------------------------------ NETPACKET* Read();

// ------------------------------------------------------------------------------------------ // send data to the actual host. // ------------------------------------------------------------------------------------------ void Send(void *Msg, int MsgLen); };

#endif

Currently browsing [vnnetclass.zip] (17,401 bytes) - [netserver.cpp] - (19,931 bytes)

//====----------------------- --- --   -      -
// MULTIUSER NETWORK MANAGEMENT
// TCP/IP and UDP support.
// ©2000-2002, Vander Nunes
//======----------------------------- --- --   -      -


#include <windows.h> #include "netserver.h"

DWORD CNetServer::m_dwRefCount = 0;

// ------------------------------------------------------------------------------------------------ // // Server Window Procedure // // ------------------------------------------------------------------------------------------------ LRESULT CALLBACK NetWndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam) { // get the pointer to the netserver class CNetServer *pServer = (CNetServer*)GetProp(hWnd, "netserver");

// handle the message switch (uMessage) { case NET_SELECT: { pServer->Select(wParam, lParam); break; } }

// return default window procedure result return DefWindowProc(hWnd,uMessage,wParam,lParam); }



// ------------------------------------------------------------------------------------------------ // // Construction // // ------------------------------------------------------------------------------------------------ CNetServer::CNetServer(enSockType SockType, USR_SRVRCALLBACK(userProc), void *pUserData, int iListenPort, int iMaxClients, int iBufferSize, int iTimeout) { m_bInitialized = FALSE; m_dwRefCount++;

// try to initialize buffers if ( !Init(iMaxClients, iBufferSize) ) throw (0);

// try to create hidden window if ( !(m_hWnd = NetMakeWindow("netserver",m_dwRefCount,64,32,WS_OVERLAPPEDWINDOW,NetWndProc)) ) throw (1);

// put our address in the window properties if ( !SetProp(m_hWnd, "netserver", (HANDLE)this) ) throw (2);

m_bInitialized = TRUE;

// try to start listening for connections if ( !Listen(SockType, userProc, pUserData, iListenPort, iTimeout) ) throw (3); }



// ------------------------------------------------------------------------------------------------ // // Initialization // // ------------------------------------------------------------------------------------------------ BOOL CNetServer::Init(int iMaxClients, int iBufferSize) { if (m_dwRefCount == 1) { WSADATA wsaData; WORD wVersionRequested = MAKEWORD(1,1); WSAStartup(wVersionRequested, &wsaData); }

// clear listening sockets m_UDPInSock = INVALID_SOCKET; m_TCPInSock = INVALID_SOCKET;

// initialize clients array m_iMaxClients = iMaxClients; m_iNumClients = 0; m_pClients = new CONN_INFO[m_iMaxClients]; if (!m_pClients) return FALSE;

// initialize buffers m_iRecvBufferSize = iBufferSize; m_pRecvBuffer = new char[m_iRecvBufferSize]; if (!m_pRecvBuffer) return FALSE;

// point netpacket buffer to the receive buffer m_Packet.pBuffer = m_pRecvBuffer;

return TRUE; }



// ------------------------------------------------------------------------------------------------ // // Close winsock service // // ------------------------------------------------------------------------------------------------ CNetServer::~CNetServer() { m_dwRefCount--;

// stop listening StopListening();

// remove properties from our window RemoveProp(m_hWnd, "netserver");

// destroy the window DestroyWindow(m_hWnd);

if (!m_dwRefCount) { // close sockets service WSACleanup(); }

// free resources if (m_pClients) delete m_pClients; if (m_pRecvBuffer) delete m_pRecvBuffer; }



// ------------------------------------------------------------------------------------------------ // // Start listening for client connections // // ------------------------------------------------------------------------------------------------ BOOL CNetServer::Listen(enSockType SockType, USR_SRVRCALLBACK(userProc), void *pUserData, int iListenPort, int iTimeout) { int nRc; int c;

// refuses to listen if not initialized if (!m_bInitialized) return FALSE;

// stop any listening mode StopListening();

// store listening information m_SockType = SockType; m_userProc = userProc; m_pUserData = pUserData; m_iListenPort = iListenPort; m_iTimeout = iTimeout;

// clear any remaining client for(c=0; c<m_iMaxClients; c++) m_pClients[c].used = 0;

// get server address memset((LPSTR)&m_MyAddr, 0, sizeof(m_MyAddr)); m_MyAddr.sin_family = PF_INET; m_MyAddr.sin_port = htons(m_iListenPort);

// -------------------------------------------------------------------------- // listen for UDP connections // -------------------------------------------------------------------------- if(m_SockType == stUDP) {

// user wants to listen for UDP. if(m_UDPInSock == INVALID_SOCKET) {

// its not already running, so start it m_UDPInSock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);

if(m_UDPInSock != SOCKET_ERROR) { nRc = bind(m_UDPInSock, (struct sockaddr *)&m_MyAddr, sizeof(m_MyAddr));

// // Use WSAAsyncSelect() to notify ourselves of network // events. Since this is UDP, we'll never see FD_CONNECT, // FD_ACCEPT, or FD_CLOSE, but we can still register for // them. // nRc = WSAAsyncSelect(m_UDPInSock, m_hWnd, // our window procedure will be the recipient NET_SELECT, // message to send FD_READ | // tell when new data's here FD_WRITE | // tell when there's buffer space FD_CONNECT | // tell when the below connect is done FD_ACCEPT | FD_CLOSE); // tell if the other side closes } else { // error while initializing UDP m_UDPInSock = INVALID_SOCKET; return FALSE; }

}

}

// -------------------------------------------------------------------------- // listen for TCP connections // -------------------------------------------------------------------------- if(m_SockType == stTCP) {

// user wants to listen for TCP. if(m_TCPInSock == INVALID_SOCKET) {

// it's not already running, so start it m_TCPInSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

if(m_TCPInSock != SOCKET_ERROR) { nRc = bind(m_TCPInSock, (struct sockaddr *)&m_MyAddr, sizeof(m_MyAddr));

nRc = listen(m_TCPInSock, 2);

// // Use WSAAsyncSelect() to notify ourselves of network // events. This is TCP, so we could see all of the // notifications. However, since we are listening, // we'll never see FD_CONNECT on this socket. // them. // nRc = WSAAsyncSelect(m_TCPInSock, m_hWnd, // our window procedure will be the recipient NET_SELECT, FD_READ | FD_WRITE | FD_CONNECT | FD_ACCEPT | FD_CLOSE);

} else { // error while initializing TCP m_TCPInSock = INVALID_SOCKET; return FALSE; }

}

}

return TRUE; }



// ------------------------------------------------------------------------------------------------ // // Stop listening // // ------------------------------------------------------------------------------------------------ void CNetServer::StopListening() { // turn off UDP if it's running. if(m_UDPInSock != INVALID_SOCKET) { closesocket(m_UDPInSock); m_UDPInSock = INVALID_SOCKET; }

// turn off TCP if it's running. if(m_TCPInSock != INVALID_SOCKET) { closesocket(m_TCPInSock); m_TCPInSock = INVALID_SOCKET; } }



// ------------------------------------------------------------------------------------------------ // // Process incoming connections, that can be either TCP or UDP. // If TCP, accepts connection and increments NumClients. // If UDP, simply receive the message and close the socket. // // ------------------------------------------------------------------------------------------------ BOOL CNetServer::Select(int wParam, int lParam) { int nRc, i; unsigned long data = 0; unsigned long four_byte; struct sockaddr_in rem_addr; int namelen = sizeof(rem_addr), ilen = sizeof(unsigned long); int clientidx;

// get the involved socket SOCKET sock = (SOCKET)wParam;

switch(WSAGETSELECTEVENT(lParam)) {

case FD_CONNECT: { // // only TCP connections pass here // break; }

case FD_ACCEPT: { // // (only TCP connections pass here) // a new TCP connection has come in. Accept it, set // up the socket info // // accept the incoming connection sock = accept(sock, NULL, NULL);

// we must get the address of the peer nRc = getpeername(sock, (struct sockaddr *)&rem_addr, (LPINT) &namelen);

// if don't, refuse connection if(nRc == SOCKET_ERROR) { closesocket(sock); // tell user about the refused connection if (m_userProc) m_userProc(this, m_pUserData, NET_REFCONNECTION, -1); return FALSE; }

//? //data = rem_addr.sin_addr.s_addr; // // if this is a new connection, we won't have a local handle // yet. Just pass it on to the new connection routine // if ((clientidx = FindClientIdx(sock)) == -1) { // the method will tell user about the new connection NewConnection(sock); } else { // we don't need to do anything, just // allow the socket to get it's FD_READ // which will be next } break; }

case FD_READ: { // // check if really there is need for reading // nRc = ioctlsocket(sock, FIONREAD, (u_long *)&data); if(nRc == SOCKET_ERROR) return FALSE; if(data <= 0 ) return FALSE;

// TCP doesn't fill in the from address on // recvfrom(). Find out if this is UDP or // tcp, and use an appropriate mechanism to // find out who the other end is. i = sizeof(int); getsockopt(sock, SOL_SOCKET, SO_TYPE, (char *)&nRc, (LPINT)&i);

if(nRc == SOCK_DGRAM) { // // UDP datagram // nRc = recvfrom(sock, (LPSTR)&four_byte, (int)ilen, MSG_PEEK, (struct sockaddr *)&rem_addr, (LPINT)&namelen); if(nRc == SOCKET_ERROR) { nRc = WSAGetLastError(); if(nRc != WSAEMSGSIZE) return FALSE; } } else { // // TCP packet // nRc = getpeername(sock, (struct sockaddr *)&rem_addr, (LPINT)&namelen); } if(nRc == SOCKET_ERROR) return FALSE; data = rem_addr.sin_addr.s_addr;

// // if it's a new connection, we won't have a local handle // yet. Just pass it on to the new connection routine // if ((clientidx = FindClientIdx(sock)) == -1) { // it's a new connection. // connect and tell user about the new connection NewConnection(sock); } else { // it isn't a new connection. // tell client there is data waiting if (m_userProc) m_userProc(this, m_pUserData, NET_NEWDATA, clientidx); }

break; }

case FD_CLOSE: { // // Only TCP pass here. // // the other side closed the connection. close the socket, // to clean up internal resources. // // receive the disconnection message recvfrom(sock, (LPSTR)&four_byte, (int)ilen, MSG_PEEK, (struct sockaddr *)&rem_addr, (LPINT)&namelen);

// find the client connection info clientidx = FindClientIdx(sock); if (clientidx != -1) { // free client slot. m_pClients[clientidx].used = 0; m_pClients[clientidx].sock = INVALID_SOCKET; }

// close socket and update client counting closesocket(sock); m_iNumClients--;

// tell user about the disconnection if (m_userProc) m_userProc(this, m_pUserData, NET_DISCONNECTION, clientidx);

break; }

} // end: switch(WSAGETSELECTEVENT(lParam)) return TRUE; }



// ------------------------------------------------------------------------------------------------ // // There is data waiting to be read. // Receive that. // Both TCP/IP and UDP pass here, after been 'selected'. // // ------------------------------------------------------------------------------------------------ NETPACKET* CNetServer::ReadMessageFromClient(int iClientIdx) { int nRc; struct sockaddr rem_addr; int ilen = sizeof(struct sockaddr_in); CONN_INFO *pClient;

// safe checking if (iClientIdx < 0 || iClientIdx >= m_iMaxClients) return NULL;

// get the client pClient = &m_pClients[iClientIdx];

// more safe checking if (!pClient->used) return NULL;

nRc = recvfrom( pClient->sock, m_pRecvBuffer, m_iRecvBufferSize, 0, (struct sockaddr *)&rem_addr, (LPINT)&ilen );

m_Packet.iLength = nRc;

return &m_Packet;

//### NOTE FOR UDP MESSAGES: // i think the best thing to do at this stage is: // if the first bytes of the message are not a ClientIdx number, // allocate a new Client entry for him and // answer to the client with his ClientIdx number. // the client them should send all his forthcoming messages // with the first bytes containing his ClientIdx id. // if his message contains the ClientIdx, we know that client // and can process his message. }



// ------------------------------------------------------------------------------------------------ // // Register an incoming call as a new connection. // ### Currently it's being called only from TCP calls by selector, // but should be called for both. // to register UDP calls, i need to implement some timing control to // figure out when the client is not communicating anymore. // // ------------------------------------------------------------------------------------------------ BOOL CNetServer::NewConnection(SOCKET ServerSocket) { int clientidx; int nRc; CONN_INFO *conn_info; int sz = sizeof(int); int type; unsigned long llen; int ilen;

// refuse only if server is full. if (m_iNumClients == m_iMaxClients) { closesocket(ServerSocket); // tell user about the refused connection if (m_userProc) m_userProc(this, m_pUserData, NET_REFCONNECTION, -1); return FALSE; }

// seek for an empty slot to accomodate this client. for(clientidx=0; clientidx<m_iMaxClients; clientidx++) if (!m_pClients[clientidx].used) break;

// should never i==m_iMaxClients! if (clientidx==m_iMaxClients) return FALSE;

// use this slot. conn_info = &m_pClients[clientidx];

// must determine if we are dealing with a TCP (stream) // or UDP (dgram) incoming connection. We could have just // passed it in as a flag, but this works as well. nRc = getsockopt(ServerSocket, SOL_SOCKET, SO_TYPE,(LPSTR)(LPINT)&type, (LPINT) &sz);

if(nRc == SOCKET_ERROR) { nRc = WSAGetLastError(); return FALSE; }

// // initialize the connection structure // conn_info->sock = INVALID_SOCKET;

if(type == SOCK_STREAM) {

// // it's a TCP socket. fill the conn_info structure. // conn_info->protocol = IPPROTO_TCP; ilen = sizeof(struct sockaddr_in); nRc = getpeername(ServerSocket, (struct sockaddr *)&(conn_info->rem_addr),(LPINT)&ilen); if(nRc == SOCKET_ERROR) return FALSE;

// mark this slot as used. m_iNumClients ++; conn_info->used = 1; } else if (type == SOCK_DGRAM) {

// // it's a UDP socket. We'll need to do a recvfrom() to // get the name of the other side, but leave the data there. // that will cause another FD_READ to be sent, and then // the message will be displayed in the normal manner // conn_info->protocol = IPPROTO_UDP;

// first, get the size of the incoming message nRc = ioctlsocket(ServerSocket, FIONREAD, (u_long *)&llen); if(nRc == SOCKET_ERROR) return FALSE;

ilen = sizeof(struct sockaddr_in);

// // using MSG_PEEK causes the data to be read and left // in the queue, so another FD_READ will be issued. // by that time, everything is set up, so the right // thing will happen. // nRc = recvfrom(ServerSocket, m_pRecvBuffer, (int)ilen, MSG_PEEK, (struct sockaddr *)&(conn_info->rem_addr), (LPINT)&ilen);

if(nRc == SOCKET_ERROR) { nRc = WSAGetLastError(); return FALSE; }

// RecvBuf contains the initial data sent from client, // using UDP datagram. }

// // Associate the conn_info with it // conn_info->sock = ServerSocket; conn_info->lasttick = GetTickCount();

// tell user about the new connection if (m_userProc) m_userProc(this, m_pUserData, NET_NEWCONNECTION, clientidx);

return TRUE; }



// ------------------------------------------------------------------------------------------------ // // Seek for a client, given it's socket. // // ------------------------------------------------------------------------------------------------ int CNetServer::FindClientIdx(SOCKET Socket) { int c;

// search by socket for (c=0; c<m_iMaxClients; c++) if (Socket == m_pClients[c].sock) return c;

return -1; }



// ------------------------------------------------------------------------------------------------ // // Send a message to a client. // // ------------------------------------------------------------------------------------------------ void CNetServer::SendMessageToClient(int ClientIdx, void *Msg, int MsgLen) { CONN_INFO *Client = &m_pClients[ClientIdx];

if (Client->protocol == IPPROTO_TCP) { // // use TCP/IP send() // send(Client->sock, (const char *)Msg, MsgLen, 0); } else { // // use UDP sendto() // sendto(Client->sock, (const char *)Msg, MsgLen, 0, (struct sockaddr *)&Client->rem_addr, sizeof(Client->rem_addr)); } }



// ------------------------------------------------------------------------------------------------ // // Broadcast a message to all clients // // ------------------------------------------------------------------------------------------------ void CNetServer::BroadcastMessage(void *Msg, int MsgLen) { int c;

for (c=0; c<m_iMaxClients; c++) { if (m_pClients[c].used) SendMessageToClient(c,Msg,MsgLen); } }



// ------------------------------------------------------------------------------------------------ // // Return a pointer to a client connection info // // ------------------------------------------------------------------------------------------------ CONN_INFO* CNetServer::Client(int iClientIdx) { if (iClientIdx < 0 || iClientIdx >= m_iMaxClients) return NULL; return (&m_pClients[iClientIdx]); }

Currently browsing [vnnetclass.zip] (17,401 bytes) - [netserver.h] - (3,507 bytes)

//====----------------------- --- --   -      -
// MULTIUSER NETWORK MANAGEMENT
// TCP/IP and UDP support.
// ©2000-2002, Vander Nunes
//======----------------------------- --- --   -      -


#ifndef _NETSERVER_H_ #define _NETSERVER_H_

#include <time.h> #include "net.h"

// ---------------------------------------------------------------------------------------------- // user's callback #define USR_SRVRCALLBACK(userProc) void (*userProc)(CNetServer *pServer, void *pUserData, int iMsg, int iClientIdx)

// connection information typedef struct _conn { struct sockaddr_in rem_addr; // net address of other end SOCKET sock; // socket(s) allocated for net traffic, waiting for a response. int protocol; // protocol to use when calling client long lasttick; // last tick when we heard something from this client char used; // 0 = empty slot } CONN_INFO;

// ---------------------------------------------------------------------------------------------- // NetServer class // ---------------------------------------------------------------------------------------------- class CNetServer { // internal window procedure friend LRESULT CALLBACK NetWndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam);

private:

// reference count static DWORD m_dwRefCount;

// netserver hidden window HWND m_hWnd;

enSockType m_SockType; int m_iListenPort; int m_iMaxClients; CONN_INFO* m_pClients; int m_iNumClients;

char* m_pRecvBuffer; int m_iRecvBufferSize; NETPACKET m_Packet;

SOCKET m_UDPInSock; SOCKET m_TCPInSock; BOOL m_bInitialized;

// default timeout to auto-disconnect clients. // this is useful to handle UDP connections too. // ### because my time constraints, I didn't finish Timeout handling yet. int m_iTimeout;

// server ip address struct sockaddr_in m_MyAddr;

// user callback procedure USR_SRVRCALLBACK(m_userProc); void *m_pUserData;

// ------------------------------------------------------------------------------------------ // initialize winsock // ------------------------------------------------------------------------------------------ BOOL Init(int iMaxClients, int iBufferSize); BOOL Select(int wParam, int lParam); BOOL NewConnection(SOCKET ServerSocket); int FindClientIdx(SOCKET Socket);

public:

CNetServer(enSockType SockType, USR_SRVRCALLBACK(userProc), void *pUserData, int iListenPort=1970, int iMaxClients=32, int iBufferSize=1024, int iTimeout=60000); virtual ~CNetServer();

BOOL Listen(enSockType SockType, USR_SRVRCALLBACK(userProc), void *pUserData, int iListenPort, int iTimeout=60000); void StopListening();

NETPACKET* ReadMessageFromClient(int iClientIdx); void SendMessageToClient(int ClientIdx, void *Msg, int MsgLen); void BroadcastMessage(void *Msg, int MsgLen);

CONN_INFO* Client(int iClientIdx);

};

#endif

The zip file viewer built into the Developer Toolbox made use of the zlib library, as well as the zlibdll source additions.

 

Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.