- •Крок 1 – Що такеWindows Sockets
- •Крок 2 – Ініціалізація
- •Крок 3 – Отримання імені хоста
- •If (bind(servsocket, (lpsockaddr)
- •Int bind(
- •Int namelen
- •Крок 6 – Зв’язок вікна з сокетом для отримання повідомлень
- •Назву вікна визначимо як
- •Void BindSocket();
- •Int listen (
- •Void StopServer();
- •If (!cDocument::OnNewDocument())
- •Void chttpServerView::OnDraw(cdc* pDc)
- •Void chttpServerView::OnLButtonDown(uint nFlags, cPoint point)
- •Invalidate();
- •Крок 9 – Відсилаємо документ
- •Invalidate();
- •If (wsagetasyncerror(lParam))
- •Void cServerWinsock::SendData(lpctstr buf, int len)
- •If accept() send()
- •Крок 10 – Порядок байтів
- •Коли Ви повинні перетворювати порядок байтів
- •Коли Вам не потрібно перетворювати порядок байтів
- •Функції перетворення порядку байтів у Windows Sockets
- •If (bind(servsocket, (lpsockaddr) &socketaddr, sizeof(socketaddr)))
- •Розрив зв’язку
- •Крок 12 – Робимо файл звіту
- •Void chttpServerView::OnToolsOptions()
- •Void chttpServerView::OnToolsOptions()
- •Void cServerWinsock::LogWrite(cString csStr)
- •If (wsaStartup(winsock_version, &wsaData))
- •Invalidate();
- •Функції адрес
- •Функції розширення Microsoft Winsock
Void chttpServerView::OnLButtonDown(uint nFlags, cPoint point)
{
// TODO: Add your message handler code here and/or call default
if (!blTestStartServer)
{
if (HTTPServer.StartServer(m_hWnd))
{
CHTTPServerDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pDoc->csInfo="Server Start";
Invalidate();
blTestStartServer=TRUE;
}
}
CView::OnLButtonDown(nFlags, point);
}
void CHTTPServerView::OnRButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
if (blTestStartServer)
{
HTTPServer.StopServer();
CHTTPServerDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pDoc->csInfo="Server Stop";
Invalidate();
blTestStartServer=FALSE;
}
CView::OnRButtonDown(nFlags, point);
}
Коли до сервера звернеться клієнт, буде згенеровано повідомлення WM_SERVER_ACCEPT, обробкою якого ми і займемося. Для цього додамо один рядок у блок обробки повідомлень
BEGIN_MESSAGE_MAP(CHTTPServerView, CView)
//{{AFX_MSG_MAP(CHTTPServerView)
ON_WM_LBUTTONDOWN()
ON_WM_CANCELMODE()
ON_WM_RBUTTONDOWN()
//}}AFX_MSG_MAP
ON_MESSAGE(WM_SERVER_ACCEPT, OnServerAccept)
END_MESSAGE_MAP()
і також функцію-обробник
afx_msg LRESULT CHTTPServerView::OnServerAccept(WPARAM wParam, LPARAM lParam)
{
CHTTPServerDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pDoc->csInfo="Client Connected !";
Invalidate();
return 0L;
}
Треба усунути одну помилку, яку ми допустили на п’ятому (фактично – четвертому) кроці при вказуванні порту в BindSocket. Це відсутність функції перетворення порядку байтів хоста в порядок байтів TCP/IP.
socketaddr.sin_port = htons(PORT_ADDR);
А тепер можна й протестувати. Компілюємо і запускаємо програму, лівої кнопкою стартуємо сервер, відкриваємо Internet Explorer або інший браузер і вводимо до його рядка адресу http://localhost; якщо обрано інший порт, то адреса буде вигледіти так: http://localhost:порт, тобто після назви хоста через двокрапку вказується номер порту у десятковому вигляді (наприклад http://localhost:8080).
Якщо ви програмуєте під Windows 2000 і заходили у систему не з правами адміністратора, то ви не зможете використовувати порти з номером менше 1024, так як вони зарезервовані для системних програм.
Якщо все гаразд, то у вікні програми з’явиться надпис “Client connected”. Але у браузері нічого не з’явиться бо нічого не відсилаємо браузеру на його запит. Як відсилати дані ми розглянемо у наступному кроці.
Крок 9 – Відсилаємо документ
Проект залишаємо той же, потрібно внести зміни лише в одну функцію – OnServerAccept.
afx_msg LRESULT
CHTTPServerView::OnServerAccept
(WPARAM wParam, LPARAM lParam)
{
CHTTPServerDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pDoc->csInfo="Client Connect !";
Invalidate();
If (wsagetasyncerror(lParam))
{
AfxMessageBox("Error detecting client");
return 0L;
}
if (WSAGETSELECTEVENT(lParam) == FD_ACCEPT)
{
int length=sizeof(SOCKADDR);
SOCKADDR_IN socketclientaddr;
HTTPServer.clientsocket=accept(HTTPServer.servsocket, (LPSOCKADDR) &socketclientaddr, (LPINT) &length);
if (HTTPServer.clientsocket == INVALID_SOCKET)
{
AfxMessageBox("Invalid Client Socket");
return 0L;
}
CString buff="HTTP/1.0 200 OK\n\n\
<HTML>\
<TITLE> Simple HTTP Server</TITLE>\
<BODY>\
<P>\
<FONT size=\"7\">Our Server Working Perfectly!!!\
</BODY>\
</HTML>";
HTTPServer.SendData(buff, buff.GetLength());
closesocket(HTTPServer.clientsocket);
}
return 0L;
};
До цієї функції-обробника передаються параметри SOCKET у wParam (у нашому випадку так як сокет один, то ми їм не користуємося, але якщо б було декілька сокетів, то єдиний спосіб дізнатися, від якого сокету надійшло повідомлення, це wParam) і код події у lParam (у нашому випадку нам повинно приходити лише FD_ACCEPT, але на всяк випадок перевіряємо). Якщо усе гаразд, то викликаємо accept для створення сокету клієнта (він створюється шляхом копіювання сокету вказаного у параметрі цієї функції, і після копіювання сокет з якого ми копіювали знов переводиться у стан чекання). Тепер можна надсилати дані. Посилку даних виносимо до окремої функції.