// сокета и связывание его с одним из 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) + "\r\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) + ": Чат остановлен!" + "\r\n";
}
else
{
strChat += " " + CString(sb.name) + " - покинул(а) чат!" + "\r\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) + "\r\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) + ": " + "Чат остановлен!" + "\r\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("Попытка подключения была отвергнута!\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