Методичні вказівки до виконання лабораторних робіт з дисципліни “Комп’ютерні мережі”, страница 4

Розмістимо на діалоговому вікні одну кнопку з ідентифікатором IDC_LISTEN і заголовком Listen і один Edit з ідентифікатором IDC_DATA. При натисканні на кнопку Listen сервер почне слухати мережу. Після того, як клієнт приєднається до нашого сервера і відправить деякі дані, вони з'являться в нашому Edіt. Для простоти після з'єднання тільки клієнт зможе відправляти дані. Якщо ви захочете відправляти дані також і із сервера, то вам доведеться додати в серверну частину нашої програми код, аналогічний кодові клієнтської частини, яку ми розглянемо в розділі 3.2.

Після розміщення всіх елементів наша програма буде виглядати приблизно так:

Далі пунктом Add Variable контекстного меню елемента Edit припишемо цьому елементу змінну m_sData типу CEdit.

Приступимо безпосередньо до написання коду. Пунктом контекстного меню Add | Class на вкладці Class View створимо новий MFC клас CMySocket як нащадок класу CSocket.

Додамо в клас CMySocket (файл MySocket.h) змінну типу покажчик на CServDlg:

public:

    CServDlg* m_pDlg; .

У цій змінній буде зберігатися покажчик на наше діалогове вікно. Оскільки ми тут використовуємо клас CServDlg, то необхідно додати рядок

class CServDlg;

безпосередньо перед оголошенням класу CMySocket.

Далі ми повинні додати метод для завдання значення змінній m_pDlg. Назвемо його SetParentDlg:

void SetParentDlg(CServDlg *pDlg);

Реалізація методу (файл MySocket.cpp) буде така

void CMySocket::SetParentDlg(CServDlg *pDlg)

{

    m_pDlg=pDlg;

}

Тепер нам потрібно в нашому класі написати дві віртуальні функції – OnAccept і OnReceive з заголовками:

virtual void  OnAccept (int  nErrorCode) ;

virtual void  OnReceive (int  nErrorCode) ;  .

 Перша буде викликатися, коли наш сокет, який прослуховує мережу, одержить запит на з'єднання від клієнтської сторони. Друга – при одержанні даних від клієнта. Фунції додамо за допомогою пункту Add | Add function контекстного меню класу CMySocket на вкладці Class View.

В одержані  заготовки для функцій додамо такий код:

void CMySocket::OnAccept (int nErrorCode)

{

    AfxMessageBox("Есть соединение");

    m_pDlg->OnAccept();

    CSocket::OnAccept(nErrorCode);

}

void CMySocket::OnReceive(int nErrorCode)

{

    AfxMessageBox("Данные получены");

    m_pDlg->OnReceive();

    CSocket::OnReceive(nErrorCode);

}

У цих двох фрагментах ми після показу МеssаgeBох  викликаємо однойменні функції OnAccept() і OnReceive() нашого діалогового вікна. Виклик виконаємо за допомогою змінної m_pDlg, в якій і зберігається покажчик на головне вікно. Ці функції діалогового вікна у нас поки що не написані. Чому код з обробки краще писати у класі діалогового вікна, а не в класі сокета? Тому що дані, як правило, пересилаються саме діалоговому вікну для відображення і подальшої обробки, а не нашому сокету. Але обробку можна робити й у класі сокета. Оскільки ми в цьому фрагменті використовуємо змінну m_pDlg, то перед реалізацією методів у файлі MySocket.cpp пишемо рядок

#include "ServDlg.h" .

Тепер займемося класом діалогового вікна. Для початку в файлі  ServDlg.h  задамо дві змінні типу CMySocket:

#include "MySocket.h"

. . .

class CServerDlg : public CDialog

{

      . . .

public:

    CMySocket m_pListenSocket;

    CMySocket m_pConnectSocket;

    . . .

Як бачимо, сокетів у нас два. Перший (m_pListenSocket) прослуховує мережу. Коли серверна частина нашого додатка починає працювати, саме він приймає на заданому порту запит від клієнта. Як тільки від клієнта надійде запит, m_pListenSocket переведе з'єднання на сокет m_pConnectSocket, який буде займатися передачею даних, а сам буде продовжувати слухати далі.

У методі OnInitDialog за допомогою SetParentDlg задамо значення для змінної m_pDlg в сокетах:

BOOL CServDlg::OnInitDialog()

{

    CDialog::OnInitDialog();

     SetIcon(m_hIcon, TRUE);                // Set big icon

     SetIcon(m_hIcon, FALSE);               // Set small icon

             // TODO: Add extra initialization here        

     m_pListenSocket.SetParentDlg(this);

     m_pConnectSocket.SetParentDlg(this);

      m_pListenSocket.Create(2000);   // 2000 порт

      return TRUE;

 }

У результаті змінна m_pDlg буде показувати на поточне діалогове вікно.

Далі додаємо методи OnAccept і OnReceive. Реалізація методів має вигляд

void CServDlg::OnAccept ()

{

     m_pListenSocket.Accept(m_pConnectSocket);

}

void CServDlg::OnReceive ()

{

     char *pBuf=new char[1025];