Смекни!
smekni.com

Разработка программы для обмена тестовыми сообщениями (стр. 2 из 3)

// сокета и связывание его с одним из IP адресом доступном на компьютере.

if(m_mainSocket.Create() == TRUE)

{

CString strAddress;

m_wndIPAddress.GetWindowText(strAddress);

CString strPort;

m_wndPort.GetWindowText(strPort);

if(m_mainSocket.Connect(strAddress, atoi(strPort)) == FALSE)

{

// В ассинхронном режиме код этой ошибки

// считается как ожидание события подключения,

// т.е. практически успешный возврат.

if(GetLastError() == WSAEWOULDBLOCK)

{

DisabledControl(false);

}

else

{

// Если какая-либо ошибка возникла,

// приводим приложение в первоначальное состояние,

// готовым к следующей попытке создания соединения.

StopChat();

}

}

}

}

/////////////////////////////////////////////////////////// БЛОК 2////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////БЛОК 1.1////////////////////////////////////////////////////////////////

// Нажали кнопку "Выйти из чата".

void CChatCppDlg::OnBnClickedButtonStopchat()

{

StopChat();

}

// Запрещает доступ к управлениям при работе

// приложения в режиме сервера или клиента.

// Цель запрета - избежать исключения от

// случайного нажатия "неправильных" кнопок.

void CChatCppDlg::DisabledControl(bool server)

{

// Запреты.

m_wndIPAddress.EnableWindow(FALSE);

m_wndPort.EnableWindow(FALSE);

m_ButtonSend.EnableWindow(FALSE);

if(server == true)

{

m_ButtonStopChat.SetWindowText(g_strStopChat);

m_ButtonStartClient.EnableWindow(FALSE);

}

else

{

m_ButtonStopChat.SetWindowText(g_strExitFromChat);

m_ButtonStartServer.EnableWindow(FALSE);

}

// Разрешения.

// Разрешить возможность выхода из чата.

m_ButtonStopChat.EnableWindow(TRUE);

}

// Разрешить доступ к управлениям после закрытия сокетов.

// Цель запрета - избежать исключения от

// случайного нажатия "неправильных" кнопок.

void CChatCppDlg::EnabledControl(void)

{

// Разрешения.

m_wndIPAddress.EnableWindow(TRUE);

m_wndPort.EnableWindow(TRUE);

m_ButtonStartClient.EnableWindow(TRUE);

m_ButtonStartServer.EnableWindow(TRUE);

// Запреты.

m_ButtonStopChat.EnableWindow(FALSE);

m_ButtonSend.EnableWindow(FALSE);

}

/////////////////////////////////////////////////////////БЛОК 1.1////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////БЛОК 1.2////////////////////////////////////////////////////////////////

// Принимаем запросы на подключения

void CChatCppDlg::OnAccept(void)

{

CSock* pSock = new CSock;

pSock->m_pParent = this;

// Если все в порядке добавим рабочий сокет в список

// подключенных рабочих сокетов.

if(m_mainSocket.Accept(*pSock) == TRUE)

{

m_vecSockets.push_back(pSock);

m_ButtonSend.EnableWindow(TRUE);

SendCountPeople();

}

else

delete pSock;

SetWindowText("Сеть работает!");

}

/////////////////////////////////////////////////////////БЛОК 1.2////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////БЛОК 1.3////////////////////////////////////////////////////////////////

// Выход из чата,

// если это сработало на стороне сервера,

// то это полная остановка чата.

// Для более надежной работы чата, во всех

// приложениях должны быть запущеня дублирующие серверы...

voidCChatCppDlg::StopChat(void)

{

// Отсылаем сигнал об отключении от чата.

SendDisconnect();

m_mainSocket.Close();

for(int i = 0; i < (int)m_vecSockets.size(); i++)

{

m_vecSockets[i]->Close();

delete m_vecSockets[i];

}

// Очистим вектор от ненужных элементов.

m_vecSockets.clear();

m_ButtonStartServer.SetCheck(BST_UNCHECKED);

m_ButtonStartClient.SetCheck(BST_UNCHECKED);

// Разрешим доступ к управлению для

// повторных попыток.

EnabledControl();

// В чате нет никого.

m_wndCountPeople.SetWindowText("В чате 0 чел.");

SetWindowText("Нет сети!");

}

/////////////////////////////////////////////////////////БЛОК 1.3////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////БЛОК 2.1////////////////////////////////////////////////////////////////

// Отправка подготовленного сообщения.

void CChatCppDlg::OnBnClickedButtonSend()

{

CString strChat;

m_wndSend.GetWindowText(strChat);

SendChat(strChat);

}

/////////////////////////////////////////////////////////БЛОК 2.1////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////БЛОК 1.4////////////////////////////////////////////////////////////////

// Извлечение сообщений из сети чата.

void CChatCppDlg::OnReceive(void)

{

SENDBUFFER sb;

if(m_ButtonStartServer.GetCheck() == BST_CHECKED)

{

// Сервер несет большую нагрузку при получении сообщений.

for(int index = 0; index < (int)m_vecSockets.size(); index++)

{

m_vecSockets[index]->Receive(&sb, sizeof(SENDBUFFER));

// Если кто-то отключился, удаляем этого клиента

// из списка доступных клиентов.

if(sb.typemessage == m_TypeMessage::tmDisconnect)

{

m_vecSockets[index]->Close();

delete m_vecSockets[index];

m_vecSockets.erase(m_vecSockets.begin() + index);

SendCountPeople();

// Отсылка принятого севером сообщения в сеть другим клиентам,

// как зеркало, клиент может работать с другими клиентами в

// сети только через сервер.

SendBuffer(sb, false);

break;

}

// Рассылаем сообщения клиента по сети чата.

if(sb.typemessage == m_TypeMessage::tmChat)

{

SendBuffer(sb, false);

break;

}

}

}

else if(m_ButtonStartClient.GetCheck() == BST_CHECKED)

{

m_mainSocket.Receive(&sb, sizeof(SENDBUFFER));

}

// Обработка принятого сообщения на основе

// его типа.

switch(sb.typemessage)

{

case m_TypeMessage::tmCountPeople:

{

m_wndCountPeople.SetWindowText("В чате " +

IntToStr(sb.countpeople) + " чел.");

}

break;

case m_TypeMessage::tmChat:

{

CString strChat;

m_wndChat.GetWindowText(strChat);

strChat += " " + CString(sb.name) + ": " + CString(sb.buffer) + "&bsol;r&bsol;n";

m_wndChat.SetWindowText(strChat);

int number_line = m_wndChat.GetLineCount();

m_wndChat.LineScroll(number_line);

}

break;

case m_TypeMessage::tmDisconnect:

{

CString strChat;

m_wndChat.GetWindowText(strChat);

// Если принято сообщение об остановки чата(отключении сервера),

// изменим содержимое сообщения.

if(sb.stopchat == true)

{

StopChat();

strChat += " " + CString(sb.name) + ": Чат остановлен!" + "&bsol;r&bsol;n";

}

else

{

strChat += " " + CString(sb.name) + " - покинул(а) чат!" + "&bsol;r&bsol;n";

}

m_wndChat.SetWindowText(strChat);

int number_line = m_wndChat.GetLineCount();

m_wndChat.LineScroll(number_line);

}

break;

default:

AfxMessageBox("Неизвестное сообщение!");

break;

}

}

/////////////////////////////////////////////////////////БЛОК 1.4////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////БЛОК 1.5////////////////////////////////////////////////////////////////

// При закрытии приложения отправим в чат

// информацию об отключении чатующего.

voidCChatCppDlg::OnClose()

{

StopChat();

CDialog::OnClose();

}

// Послать строку-сообщение в чат.

void CChatCppDlg::SendChat(CString strMessage)

{

SENDBUFFER sb;

int len = strMessage.GetLength();

memcpy(sb.buffer, strMessage.GetBuffer(), sizeof(TCHAR)*len);

m_wndName.GetWindowText(strMessage);

len = strMessage.GetLength();

memcpy(sb.name, strMessage.GetBuffer(), sizeof(TCHAR)*len);

sb.typemessage = m_TypeMessage::tmChat;

SendBuffer(sb, true);

}

// Послать буфер подготовленного сообщения в сеть.

void CChatCppDlg::SendBuffer(SENDBUFFER sb, bool toserver)

{

// Если слкет не создан, нечего делать в этой функции.

if(m_mainSocket.m_hSocket == INVALID_SOCKET) return;

if(m_ButtonStartServer.GetCheck() == BST_CHECKED)

{

for(int i = 0; i < (int)m_vecSockets.size(); i++)

{

int send = m_vecSockets[i]->Send(&sb, sizeof(SENDBUFFER));

if(send == sizeof(SENDBUFFER))

{

m_wndSend.SetWindowText("");

}

}

// Если непосредственно отправку осуществляет сервер,

// отобразим его сообщение в его же окне отправки,

// флаг toserver необходим поскольку данная функция

// может работать в режиме зеркала см. CChatCppDlg::OnReceive(void).

if(toserver == true )

{

if(sb.typemessage == m_TypeMessage::tmChat)

{

CString strChat;

m_wndChat.GetWindowText(strChat);

strChat += " " + CString(sb.name) + ": " + CString(sb.buffer) + "&bsol;r&bsol;n";

m_wndChat.SetWindowText(strChat);

int number_line = m_wndChat.GetLineCount();

m_wndChat.LineScroll(number_line);

}

if(sb.typemessage == m_TypeMessage::tmDisconnect)

{

CString strChat;

m_wndChat.GetWindowText(strChat);

strChat += " " + CString(sb.name) + ": " + "Чат остановлен!" + "&bsol;r&bsol;n";

m_wndChat.SetWindowText(strChat);

int number_line = m_wndChat.GetLineCount();

m_wndChat.LineScroll(number_line);

}

}

}

else if(m_ButtonStartClient.GetCheck() == BST_CHECKED)

{

int send = m_mainSocket.Send(&sb, sizeof(SENDBUFFER));

if(send == sizeof(SENDBUFFER))

m_wndSend.SetWindowText("");

}

}

// Формируем и отправляем сообщение об отключении от сети.

void CChatCppDlg::SendDisconnect(void)

{

SENDBUFFER sb;

CString s;

m_wndName.GetWindowText(s);

int len = s.GetLength();

memcpy(sb.name, s.GetBuffer(), sizeof(TCHAR)*len);

sb.typemessage = m_TypeMessage::tmDisconnect;

// Отсоединение сервера останавливает чат.

if(m_ButtonStartServer.GetCheck() == BST_CHECKED)

sb.stopchat = true;

SendBuffer(sb, true);

}

/////////////////////////////////////////////////////////БЛОК 1.5////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////БЛОК 2.2////////////////////////////////////////////////////////////////

// Событие подключения, происходит на стороне клиента.

void CChatCppDlg::OnConnect(BOOL Error)

{

if(Error == TRUE)

{

AfxMessageBox("Попытка подключения была отвергнута!&bsol;nВозможно сервер еще не создан!");

StopChat();

}

else

{

m_ButtonSend.EnableWindow(TRUE);

SetWindowText("Сеть работает!");

}

}

/////////////////////////////////////////////////////////БЛОК 2.2////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////БЛОК 1.6////////////////////////////////////////////////////////////////

// Сервер отправляет клиентам количество людей в чате.

void CChatCppDlg::SendCountPeople(void)

{

int countpeople = 1/*сервер*/ + (int)m_vecSockets.size()/*клиенты*/;

m_wndCountPeople.SetWindowText("В чате " +

IntToStr(countpeople) + " чел.");

// Отправим сообщение о количествах людей в чате.

SENDBUFFER sb;

sb.typemessage = m_TypeMessage::tmCountPeople;

sb.countpeople = countpeople;

for(int i = 0; i < (int)m_vecSockets.size(); i++)

{

int send = m_vecSockets[i]->Send(&sb, sizeof(SENDBUFFER));

}

}

/////////////////////////////////////////////////////////БЛОК 1.6////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////БЛОК 1.7////////////////////////////////////////////////////////////////

// Запрос имени чатующего перед созданием сокета.

bool CChatCppDlg::QueryName(void)

{

CString strName;

m_wndName.GetWindowText(strName);

if(strName == g_EmptyName || strName.IsEmpty() == true)

returnfalse;

returntrue;

}

/////////////////////////////////////////////////////////БЛОК 1.7////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////БЛОК 3//////////////////////////////////////////////////////////////////

Исходный код инициализацию сокета:

#include "stdafx.h"

#include "ChatCpp.h"

#include "ChatCppDlg.h"

#ifdef _DEBUG

#define new DEBUG_NEW

#endif

// CChatCppApp

BEGIN_MESSAGE_MAP(CChatCppApp, CWinApp)

ON_COMMAND(ID_HELP, CWinApp::OnHelp)

END_MESSAGE_MAP()

// CChatCppApp construction

CChatCppApp::CChatCppApp()

{

// TODO: add construction code here,

// Place all significant initialization in InitInstance