Стаття Побудова клієнт-серверної програми на основі класу CAsyncSocket (MFC)
- Клієнт(позначення далі -1CL). Об'єкт, який підключається до сервера.
- Сервер(позначення далі -SRV). Об'єкт, що здійснює очікування запиту на підключення від Клієнта (1CL) і підключає його до одного з елементів серверного масиву ПАР для Клієнтів.
- Серверний клієнт(позначення далі -sCL). Цей об'єкт є елементом серверного масиву клієнтів. У цьому масиві містяться "точки" (або "клієнтські пари") для підключення Клієнтів (1CL).

//повідомлення WM_SOCKET_NOTIFY, lParam==FD_READ //1CL або sCL отримав нові дані від пари - потрібно їх прийняти virtual void OnReceive ( int nErrorCode ) ;
//повідомлення WM_SOCKET_NOTIFY, lParam==FD_WRITE //1CL або sCL відправляє дані через Send virtual void OnSend ( int nErrorCode ) ;
//повідомлення WM_SOCKET_NOTIFY, lParam==FD_OOB //1CL або sCL відправляє дані out-of-band (дані з високим пріоритетом) отримав virtual void OnOutOfBandData ( int nErrorCode ) ;
//повідомлення WM_SOCKET_NOTIFY, lParam==FD_ACCEPT //SRV отримав («підслухав») запит на з'єднання від 1CL virtual void OnAccept ( int nErrorCode ) ;
//повідомлення WM_SOCKET_NOTIFY, lParam==FD_CONNECT //1CL отримав повідомлення про те, що сервер підключив його до sCL методом Accept virtual void OnConnect ( int nErrorCode ) ;
//повідомлення WM_SOCKET_NOTIFY, lParam==FD_CLOSE //1CL або sCL отримав повідомлення про те, що його (сокет) закрили virtual void OnClose ( int nErrorCode ) ;
namespace ALX1153 < //константи та допоміжні структури та класи namespace ASocketH < //клас даних користувача клієнта, // використовується за умовчанням class VoidUSERDATA < > ; . . > ;
//батько для сервера та клієнта class ASocketParent : public CAsyncSocket < . . > ;
//клас для 1CL class ASocketClient : public ASocketParent < . . > ;
//клас для SRV template class USERDATA = ASocketH :: VoidUSERDATA > class ASocketServer : public ASocketParent < //клас для sCL class CsCL : public ASocketClient < friend class ASocketServer;
USERDATA m_UserData; // дані користувача ASocketServer * m_pParentServer ; //Покажчик на сервер
public : //добути вказівник на дані користувача USERDATA * Us_GetUserData ( ) const < return (USERDATA *) & m_UserData; > . . > ;
private : //клас-контейнер покажчика на CsCL для розміщення в std::map struct CsCL_container < private : CsCL * m_p; . . CsCL_container ( ASocketServer * pParentServer ) < m_p = new CsCL (pParentServer); >
private : //ServerClientsMap - масив для зберігання серверних клієнтів typedef std :: map int ,CsCL_container > td_ClientsMap; td_ClientsMap m_ServerClientsMap ; . . > ; > ;
- Конструктор за замовчуванням;
- Оператор =;
- Конструктор копіювання.

//Визначення того, що сокет підключений bool Us_IsClient__Connected ( ) ;
//відключення від сервера та закриття сокету void Us_StopWorking ( ) const ;
//перевірка, чи включено отримання події прийому даних bool Us_GetIsEventOn_OnReceive ( ) ;
//зупинити одержання подій прийому/передачі/підключення void Us_PauseEvents ( ) ;
//відновити отримання подій прийому/передачі/підключення voidUs_StartEvents();
//Повертає константу ASocketH::e_net_MaxOnceSendLen static int Us_GetMaxOneSendLen ( ) ;
//перевірка того, що сокет був некоректно відключений //(зв'язок розірвався з незрозумілих причин) bool Us_IsClient__BadDisconnectedAfterLastConnect ( ) const ;
//перевірити об'єкт SOCKET (хендл сокету) на валідність bool Us_IsWorking_checkJustHandle ( ) const ;
// звичайні функції відсилання та прийому int Us_Send (const void * lpBuf, int nBufLen, int nFlags = 0) const; int Us_Receive (void * lpBuf, const int nBufLen, int nFlags = 0);
//викликається з Send при кожній невдалій спробі надіслати дані //(вірніше, коли (CAsyncSocket::Send()==SOCKET_ERROR і //this->GetLastError()==WSAEWOULDBLOCK) //dwdTicksPassed - мс, приблизно скільки пройшло з початку спроби відправити virtual bool VF_FeedBackFromSend_RetTrueIfNeedCancel (DWORD dwdTicksPassed) = 0;
//викликається після закриття клієнта virtual void VF_OnAfterClose ( ) = 0 ;
//викликається після підключення клієнта сервером (коли сервер викликає Accept) virtual void VF_OnConnected ( ) = 0 ;
//викликається, коли є дані прийому (але ще прийняті - //это треба зробити у цьому обробнику) virtual void VF_OnReceive ( ) = 0 ;

//перевірити відповідність індексу та покажчика на серверний клієнт у масиві клієнтів bool Us_CheckClientPointerEqualsTheIndex (DWORD Index_zb, const CsCL * cli_test);
//перевірка сокету на валідність хендла bool Us_IsWorking_checkJustHandle () const;
//перевірка сокету на підключеність bool Us_IsClient__Connected (const CsCL * cli); bool Us_IsClient__Connected (DWORD Index_zb);
//Визначення факту«нештатного» розриву зв'язку bool Us_IsClient__BadDisconnectedAfterLastConnect (DWORD Index_zb);
//отримати покажчик на серверний клієнт за індексом const CsCL * Us_GetClientByIndex (DWORD Index_zb);
//задати максимальну кількість клієнтів void Us_SetClientCount (DWORD ClientsMax_in);
//дістати поточну максимальну кількість клієнтів DWORD Us_GetClientsCount ( ) ;
//запуск сервера bool Us_StartWorkingServer ( WORD wServerPort, int nClientsCountLimit, bool bPauseEventsBeforeWorking ) ;
//зупинка сервера void Us_StopWorking ();
//викликається, коли клієнт відключився virtual void VF_OnAfterClose ( const CsCL * sCL ) = 0 ;
//викликається, коли клієнт підключився virtual void VF_Accepted ( const CsCL * sCL ) = 0 ;
//викликається, сервер запущено virtual void VF_SRV_OnAfterServerCreated ( ) = 0 ;
//викликається з Send при кожній невдалій спробі надіслати дані //(вірніше, коли (CAsyncSocket::Send()==SOCKET_ERROR і //this->GetLastError()==WSAEWOULDBLOCK) //dwdTicksPassed - мс, приблизно скільки пройшло з початку спроби відправити virtual bool VF_FeedBackFromSend_RetTrueIfNeedCancel ( const CsCL * sCL, DWORD dwdTicksPassed ) = 0;
//викликається, коли є дані прийому (але ще прийняті - //это треба зробити у цьому обробнику) virtual void VF_OnReceive ( const CsCL * sCL ) = 0 ;
//добути покажчик на дані користувача USERDATA * Us_GetUserData ( ) const ;
//перевірка сокету на валідність хендла bool Us_IsWorking_checkJustHandle ( ) const
#pragma once #include "ASocket1153.h"
class CMyClient : public ALX1153 :: ASocketClient < virtualvoid VF_OnReceive ( ) < //вручну читаємо напряму із сокета //Us_Receive(. );//опціонально. >
віртуальна порожнеча VF_OnAfterClose ( ) < > віртуальна порожнеча VF_OnConnected ( ) < > віртуальний bool VF_FeedBackFromSend_RetTrueIfNeedCancel ( DWORD dwdTicksPassed ) < якщо (dwdTicksPassed > e_sendTOdefault) < TRACE ( " \r \n \r \n VF_FeedBackFromSend_RetTrueIfNeedCancel припинив надсилання \r \n \r \n " ) ; повернути істину; >
Сон (1); повернути false ; >
віртуальний bool VF_FeedBackFromSend_RetTrueIfNeedCancel ( const CsCL * sCL,DWORD dwdTicksPassed ) < якщо (dwdTicksPassed > e_sendTOdefault) < TRACE ( " \r \n \r \n VF_FeedBackFromSend_RetTrueIfNeedCancel припинив надсилання \r \n \r \n " ) ; повернути істину; >
Сон (1); повернути false ; >
//извещение для сервера virtual void VF_SRV_OnAfterServerCreated ( )
//примінюється, коли чергові повідомлення не обробляються, а поймати //событие підключення клієнта до сервера необхідно. Вихід із функцій //виходить за входом потрібного повідомлення WM_SOCKET_NOTIFY(FD_CONNECT) або //по істеченню таймаута (false). Функція повертає значення Us_IsClient__Connected() //якщо зворотний виклик є і повертає true, то запит переривається і повертає false bool Us_WaitOneConnectEvent ( DWORD dwdTO = 5000 , DWORD dwdTimeStep = 50 , bool ( * WaitCancelCallBack ) ( int percent, void * pData ) = 0 , void * pData = 0 ) ;
//примінюється, коли чергові повідомлення не обробляються, а поймати //побути прихід даних до сервера необхідно. Вихід із функцій //виходить за входом повідомлення WM_SOCKET_NOTIFY(FD_READ) або //по істеченню таймаута. Функція нічого не повертає //якщо callback є і повертає true, то опитування переривається //підходить цілісного повідомлення, але з розбитого на частини. bool Us_WaitOneReceiveEvent ( DWORD dwdTO = 10000, DWORD dwdTimeStep = 50, bool (* WaitCancelCallBack) (int percent, void * pData) = 0, void * pData 9>);
//застосовується, щоб очистити чергу від «непотрібних» повідомлень // WM_SOCKET_NOTIFY(FD_WRITE) void Us_WaitAndRemoveSendEvents();
static bool WaitingReceive (int percent, void * pData) < TRACE ("Чекання даних. Таймаут: %d%% \r \n",%); return false; > > ;
TRACE ("Підключаємося до сервера \r \n"); if (! Client. Us_StartWorkingClient ("localhost", 1234, false)) return false;
TRACE ("Чекаємо асепт \r \n"); if (! Client. Us_WaitOneConnectEvent (5000, 100, s_show :: WaitingConnect, this)) return false; if ( ! Client. Us_IsClient__Connected ( ) ) return false ; TRACE ("Підключилися \r \n");
//Видаляємо з черги повідомлення відправки //Якщо цього зробити, це повідомлення завадить //"побачити" повідомлення отримання даних Client. Us_WaitAndRemoveSendEvents();
TRACE ("Чекаємо відповідь \r \n"); //скидаємо прапор прийняття відповіді //(Прапор встановиться в Client.VF_OnReceive(), якщо дані-відповідь вірні) Client. m_bAnswerGot = false; if (! Client. Us_WaitOneReceiveEvent (5000, 100, s_show :: WaitingReceive, this)) return false;
//Сервер надіслав дані. // Перевіряємо, чи піднявся прапор if ( ! Client. m_bAnswerGot ) return false ;
TRACE ("аторизація отримана! \r \n"); return true; >