КАТЕГОРИИ: Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748) |
Посылаем и получаем сообщение
Функции класса CAsyncSocket Class Чтобы иметь возможность перехватывать и отвечать на события сокета, нам нужно создать свой собственный класс на основе класса CAsyncSocket. В этом классе будет содержаться его собственная версия функций для обработки событий, а также средства отражения событий на уровне класса диалогового окна, здесь будет использоваться указатель на диалоговое окно родительского класса нашего класса сокета. Этот указатель будем использовать для осуществления вызова функций каждого события сокета, предварительно осуществим проверку наличия ошибок. Чтобы создать этот класс, выберем в меню Insert | New Class. В диалоговом меню создания нового класса New Class оставим тип класса таким, какой предлагается по умолчанию (MFC), введем имя класса, например, CmySocket, и укажем в качестве базового класс CAsyncSocket в списке доступных базовых классов. Нажимаем кнопку ОК, новый класс вставлен. После того как новый класс сокета создан, вставим переменную в класс, который будет использоваться в качестве указателя на родительское диалоговое окно. Указываем тип переменной CDialog*, имя переменной m_pWnd, доступ private. В классе необходимо определить метод, а значит, вставим новую функцию в этот класс. Тип функции void, объявим функцию в виде SetParent(CDialog* pWnd), доступ public. Редактируем созданную функцию. void CMySocket::SetParent(CDialog *pWnd) { //устанавливаем указатель m_pWnd = pWnd; } В классе сокета создаем функции обработки событий. Для создания функции, соответствующей событию OnAccept, вставим новую функцию в класс сокета, тип функции void, опишем функцию в виде OnAccept(int nErrorCode), доступ protected. Редактируем код. void CMySocket::OnAccept(int nErrorCode) { //Есть ошибки? if (nError == 0) //Нет, вызываем функцию OnAccept() ((CSockDlg*)m_pWnd)->OnAccept(); } Вставляем подобные функции для событий OnConnect, OnClose, OnReceive и OnSend. После того как функции вставлены,нужно вставить заголовочный файл в диалоговое окно нашего приложения в класс сокета. //MySocket.cpp // … #include "MySocket.h" После того как требуемые функции событий созданы в классе сокета, вставим переменную, связанную с нашим классом сокета, в класс диалогового окна. Для сервера нам потребуется две переменные, одна будет связана с прослушиванием запросов на соединение, а другая - связана с другим приложением. Поскольку у нас существует два объекта сокета, то в диалоговый класс (CSockDlg) вводим две переменные. Обе переменные имеют тип класс сокета (CMySocket) и доступ private. Имя одной переменной m_sListenSocket, эта переменная связана с прослушиванием запроса на соединение, вторая переменная называется, m_sConnectSocket и используется для пересылки сообщения в том и в другом направлении. После того как переменные сокета созданы, необходимо написать код, инициализирующий эти переменные. По умолчанию зададим тип приложения такой, как "клиент", номер порта 4000. Помимо этих параметров установим указатель в объектах сокетов, чтобы они указывали на диалоговый класс. Это можно сделать, если вставить код в функцию OnInitDialog. Замечание. Имя, соответствующее loopback – это специальное имя, используемое в протоколе TCP/IP, которое обозначает компьютер, на котором мы работаем. Это внутреннее имя компьютера, превращаемое в адрес 127.0.0.1. Это имя и адрес компьютера, широко используемое в тех случаях, когда требуется осуществить соединение с другим приложением, установленным на том же самом компьютере, на котором мы и работаем. BOOL CSockDlg::OnInitDialog() { CDialog::OnInitDialog(); //… SetIcon(m_hIcon, FALSE); //Инициализируем переменные управления m_iType = 0; m_strName = "loopback"; m_iPort = 4000; //обновляем элементы управления UpDateData(FALSE); //Устанавливаем указатель m_sConnectSocket.SetParent(this); m_sListenSocket.SetParent(this); retutn TRUE; //} Связываемся с приложением Когда пользователь нажимает кнопку, то все функции основного окна становятся недоступными. В этот момент пользователь не может менять параметры программы. Сейчас обращаемся к функции Create в соответствующей переменной сокета в зависимости от того, используется наше приложение в виде сервера или в виде клиента. Затем мы обращаемся либо к функции Connect, либо к функции Listen, этим мы инициализируем соединение с нашей стороны. Чтобы вставить описанные функции в приложение, откроем мастер классов Class Wizard и вставим функцию для сообщения о событии BN_CLICKED в кнопке Connect(ID IDC_BCONNECT). Редактируем код функции. void CSockDlg::OnBconnect() { //Синхронизируем переменные, используя значения элементов управления UpdateData(TRUE); //Включаем прочие элементы управления GetDlgItem(IDC_BCONNECT)->EnableWindow(FALSE); GetDlgItem(IDC_ESERVNAME)->EnableWindow(FALSE); GetDlgItem(IDC_ESERVPORT)->EnableWindow(FALSE); GetDlgItem(IDC_STATICNAME)->EnableWindow(FALSE); GetDlgItem(IDC_STATICPORT)->EnableWindow(FALSE); GetDlgItem(IDC_RCLIENT)->EnableWindow(FALSE); GetDlgItem(IDC_RSERVER)->EnableWindow(FALSE); GetDlgItem(IDC_STATICTYPE)->EnableWindow(FALSE); //Работаем в качестве клиента или сервера? if (m_iType == 0) { //клиент, создаем сокет по умолчанию m_sConnectSocket.Creatr(); //открываем соединение с сервером m_sConnectSocket.Connect(m_strName, m_iPort); } else { //сервер, создаем возможность прослушивания на указанном порте m_sListenSocket.Create(m_iPort); //прослушиваем запросы на соединение m_sListenSockrt.Listen(); } } Затем, чтобы завершить приложение, вставляем функцию обработки событий сокета в диалоговый класс: OnAccept и OnConnect. Эти функции вызываются в нашем классе сокета. Эти функции не требуют указания каких-либо параметров. Функция OnAccept вызывается в том случае, когда со слушающим сокетом пытается соединиться другое приложение. После того как соединение принято, мы можем включить окно для ввода текста сообщений, которые будет передавать другому приложению. Чтобы вставить такую функцию в приложение, добавляем новую функцию в диалоговый класс CSockDlg. Указываем тип функции void, описываем функцию как OnAccept, доступ public. Редактируем код функции. void CSockDlg::OnAccept() { //принимаем запрос на соединение m_sListenSocket.Accept(m_sConnectSocket); //включаем элементы управления вводимого текста GetDlgItem(IDC_EMSG)->EnableWindow(TRUE); GetDlgItem(IDC_BSEND)->EnableWindow(TRUE); GetDlgItem(IDC_STATICMSG)->EnableWindow(TRUE); } На клиентской стороне ничего делать не надо, за исключением включения элементов управления, ответственных за ввод и посылку сообщений. Мы также включаем кнопку Close, с ее помощью соединение закрывается со стороны клиента (но не сервера). Чтобы добавить в приложение описанные функции, в диалоговый класс CSockDlg вставляем новую функцию, тип новой функции void, описываем функцию в виде OnConnsct, доступ к функции public. void CSockDlg::OnConnect() { //включаем элементы управления текстом сообщений GetDlgItem(IDC_EMSG)->EnableWindow(TRUE); GetDlgItem(IDC_BSEND)->EnableWindow(TRUE); GetDlgItem(IDC_STATICMSG)->EnableWindow(TRUE); GetDlgItem(IDC_BCLOSE)->EnableWindow(TRUE); } В диалоговый класс CSockDlg вставим три функции, тип всех функций void, а доступ - public. Первая функция - OnSend, вторая - OnReceive, третья - OnClose. Можно скомпилировать приложение. Запустим две копии приложения. Зададим, чтобы одна из копий работала в режиме сервера, щелкнем кнопку Listen, чтобы перевести его в состояние ожидания запроса на соединение. Все элементы управления при этом будут находиться в отключенном состоянии. Второй экземпляр программы запустим в режиме клиента и нажмем кнопку Connect. Здесь также элементы управления установлены в выключенное состояние. После того как соединение будет установлено, элементы управления, ответственные за отсылку сообщений, перейдут в рабочее состояние.
Необходимо добавить в приложение функции, которые позволили бы осуществлять прием и посылку сообщений. После того как между приложениями установлено соединение, пользователь может ввести текстовое сообщение в окно для редактирования, расположенное в центре диалогового окна, затем, нажав кнопку SEND, посылается сообщение другому приложению. Чтобы вставить требуемые функции, выполняемые после нажатия кнопки SEND, вначале необходимо позаботиться о том, чтобы была произведена проверка того, содержится ли в окне какое-либо сообщение, затем определить его длину, потом послать сообщение, а затем добавить сообщение в окно списка. Используем «Мастер классов» для вставки функции, которая будет выполняться после наступления события нажатия кнопки IDC_BSEND. Редактируем функцию. void CSockDlg::OnBsend() { int iLen; int iSent; //Обновляем элементы управления в соответствии с переменными UpdateData(TRUE); //Есть сообщение для посылки? if (m_strMessage!="") { //Получаем длину сообщения iLen = m_strMessage.GetLength(); //Посылаем сообщение iSent= m_sConnectSocket.Send(LPCTSTR(m_strMessage), iLen}; //Смогли послать? if (iSent == SOCKET_ERROR) { } else { // Добавляем сообщение в список m_ctlSent.AddString(m_strMessage); // Обновляем переменные согласно элементам управления UpdateData(FALSE); }}} При срабатывании функция OnReceive, что происходит в момент, когда приходит сообщение, мы извлекаем это сообщение из сокета, используя функцию Receive. После того как сообщение извлечено, мы преобразуем его в тип String и добавляем его в список полученных сообщений. Эти функции можно создать, если отредактировать существующую функцию OnReceive в диалоговом классе. void CSockDlg::OnReceive() { char *pBuf = new char[1025]; int iBufSize = 1024; int iRcvd; CString strRecvd; //Получаем сообщение iRcvd = m_sConnectSocket.Receive(pBuf, iBufSize); //Получили что-либо? if (iRcvd == SOCKET_ERROR) { } else { //Отрезаем конец сообщения pBuf[iRcvd] = NULL; //Копируем сообщение в CString strRecvd = pBuf; //добавляем сообщение в список полученных сообщений m_ctlRecvd.AddString(strRecvd); // обновляем переменные в соответствии с элементами управления UpdateData(FALSE); } } Сейчас можно скомпилировать и запустить две копии приложения, соединив их друг с другом. После того как соединение будет установлено, можно ввести сообщение в одном приложении и послать его другому приложению. Завершение соединения Чтобы закрыть соединение, пользователь клиента может щелкнуть кнопкой Close, соединение будет прекращено. В серверном приложении будет получено событие сокета OnClose. После этого в обоих приложениях должны произойти одинаковые процессы: соединяющийся сокет должен быть закрыт, элементы управления, ответственные за отсылку сообщений, должны быть выключены. На клиентском приложении, кроме того, необходимо включить элементы управления, ответственные за установку соединения. На серверном приложении процесс прослушивания в ожидании запроса на установление связи восстановится. Чтобы создать необходимые для осуществления описанных действий функции, отредактируем код функции OnClose, изменив код. void CSockDlg::OnClose() { // закрываем сокет m_sConnectSocket.Close(); // выключаем элементы управления, ответственные за посылку сообщений GetDlgItem(IDC_EMSG)->EnableWindow(FALSE); GetDlgItem(IDC_BSEND)->EnableWindow(FALSE); GetDlgItem(IDC_STATICMSG)->EnableWindow(FALSE); GetDlgItem(IDC_BCLOSE)->EnableWindow(FALSE); // мы работаем как клиент? if (m_iType == 0) { // да, тогда влючаем элементы управления соединением GetDlgItem(IDC_BCONNECT)->EnableWindow(TRUE); GetDlgItem(IDC_ESERVNAME)->EnableWindow(TRUE); GetDlgItem(IDC_ESERVPORT)->EnableWindow(TRUE); GetDlgItem(IDC_STATICNAME)->EnableWindow(TRUE); GetDlgItem(IDC_STATICPORT)->EnableWindow(TRUE); GetDlgItem(IDC_RCLIENT)->EnableWindow(TRUE); GetDlgItem(IDC_RSERVER)->EnableWindow(TRUE); GetDlgItem(IDC_STATICTYPE)->EnableWindow(TRUE); } } Наконец, для кнопки Close необходимо организовать обращение к функции OnClose. Для этого используем мастер классов и с его помощью вставим функцию, соответствующую событию нажатия кнопки Close (IDC_BCLOSE). Редактируем код функции. void CSockDlg::OnBclose() { // TODO: Add your control notification handler code here // вызываем функцию OnClose OnClose(); } Сейчас после компиляции и запуска двух копий приложения мы сможем осуществить соединение между клиентской и серверной версией приложения и пересылать между ними сообщения в обоих направлениях, а потом разорвать соединение из клиентского приложения, нажав на кнопку Close (рис.4.2) Рис 4.2.Результат работы приложения Мы сможем восстановить соединение клиента с сервером, нажав на кнопку Connect еще раз. Если запустить третью копию приложения, изменим в ней номер порта, установим эту копию как сервер, включим режим ожидания запроса на соединение, можно переключать клиентское приложение, поочередно подключаясь то к одному, то к другому, изменяя при этом номер порта. Задание к лабораторной работе Разработать приложение, позволяющее осуществлять взаимодействие клиента и сервера по совместному решению задач обработки информации. Приложение должно располагать: 1) минимальным» пользовательским интерфейсом, определяющим возможности приложения; 2) возможностью передачи и модифицирования получаемых (передаваемых) данных; 3) средствами диагностики и обработки исключительных ситуаций, а также средствами поддержки деятельности пользователя.
Варианты индивидуального задания 1. Разработать интерфейс для обмена сообщениями между пользователями различных узлов сети. 2. Разработать программу организации простых расчетов на сервере для клиентских задач. 3. Организовать взаимодействие, реализующее рассылку сообщений от одного клиента, группе клиентов. 4. Организовать пересылку журнала репликаций БД между клиентами Remote-установки через сокеты.
Литература
1. Грегори К. Использование Visual C++ 6.: Пер. с англ. - М.; СПб.; Киев.: Изд. дом «Вильямс», 2000. - 864 с. 2. Комличенко В.Н., Живицкая Е.Н., Соколов С.А. и др. Лабораторный практикум по курсу «Визуальные средства разработки приложений» для студентов специальности 40 01 02-02 "Информационные системы и технологии в экономике". -Мн.: БГУИР, 2002.- 89 с. 3. Тихомиров Ю. Самоучитель MFC. – СПб.: БХВ-Петербург, 2002. - 640 с.
Св. план 2003, поз. 111
Учебное издание
Комличенко Виталий Николаевич, Едемская Оксана Павловна, Кириенко Наталья Алексеевна и др.
ВИЗУАЛЬНЫЕ СРЕДСТВА РАЗРАБОТКИ ПРИЛОЖЕНИЙ
Учебно-методическое пособие по курсу «Объектно-ориентированное проектирование и программирование» для студентов специальности 40 01 02-02 «Информационные системы и технологи в экономике» дневной формы обучения
Редактор Т.А.Лейко Корректор Е.Н. Батурчик Подписано в печать Формат 60х84 1/16. Бумага офсетная. Печать ризографическая. Гарнитура Times. Усл. печ. л. Уч.-изд. л. 4,0. Тираж 150 экз. Заказ 290. Издатель и полиграфическое исполнение: Учреждение образования «Белорусский государственный университет информатики и радиоэлектроники» Лицензия ЛП № 156 от 30.12.2002. Лицензия ЛП № 509 от 03.08.2001. 220027, Минск, ул. П. Бровки, 6
Дата добавления: 2014-11-29; Просмотров: 673; Нарушение авторских прав?; Мы поможем в написании вашей работы! Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет |