Запускайте VC и выбирайте MFC AppWizard, имя проекту дайте HTTPServer. На шаге 1 поставьте Single Document, на шаге 3 отключите ActiveX Control нам пока это не нужно, на шаге 4 отключите всё, и жмите Finish.
Давайте на основе прошлых шагов создадим класс CSeverWinSock. Переходите в ClassView, нажимайте правую кнопку мыши и выбирайте Add New Class. Выбирите Generic Class внесите имя и жмите OK, я не буду разбирать подробности переноса, скажу только, что все функции printf поменяю на AfxmessageBox, и все функции из void станут BOOL. Посмотрите проект. Но описание класса и две важные функции приведу:
class CSeverWinSock { public: CSeverWinSock(); virtual ~CSeverWinSock(); BOOL StartWinSock(); BOOL SocketGetHostName(); BOOL CreateSocket(); BOOL LinkWindowSocket(HWND m_hWnd); BOOL ListenSocket(); void CloseScoket(); BOOL LinkSoketPort(); BOOL StopWinSock(); BOOL StartServer(HWND m_hWnd); void StopServer(); private: SOCKET servsocket; }; void CSeverWinSock::StopServer() { CloseScoket(); StopWinSock(); } BOOL CSeverWinSock::StartServer() { if (!StartWinSock()) return FALSE; if (!SocketGetHostName()) return FALSE; if (!CreateSocket()) return FALSE; if (!LinkSoketPort()) return FALSE; if (!LinkWindowSocket(m_hWnd)) return FALSE; if (!ListenSocket()) return FALSE; return TRUE; }
Итак, нам нужно запустить и остановить сервер. Мы будем это делать по нажатию левой кнопки мыши - запускать, правой - останавливать. Но сначала заведем переменную csInfo для вывода на экран состояния. Мы опишем её в классе CHTTPServerDoc и там же инициализируем.
// ...... // Implementation public: CString csInfo; virtual ~CHTTPServerDoc(); #ifdef _DEBUG virtual void AssertValid() const; virtual void Dump(CDumpContext& dc) const; #endif //...... BOOL CHTTPServerDoc::OnNewDocument() { if (!CDocument::OnNewDocument()) return FALSE; csInfo="Stop Server"; return TRUE; }
В классе CHTTPServerView опишем вывод на экран:
void CHTTPServerView::OnDraw(CDC* pDC) { CHTTPServerDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); pDC->TextOut(10,10,pDoc->csInfo); }
В классе CHTTPServerView заведем логическую переменную blTestStartServer и в конструкторе скажем, что она FALSE - типа сервер стоит.
CHTTPServerView::CHTTPServerView() { blTestStartServer=FALSE; }
Добавим для класса CHTTPServerView реакцию на нажатие правой и левой кнопки мыши. А также в описание этого класса ссылку на наш заголовочный файл.
#pragma once #endif // _MSC_VER > 1000 #include "SeverWinSock.h"
Включим в описание класса CHTTPServerView экземпляр класса CSeverWinSock:
public: BOOL blTestStartServer; virtual ~CHTTPServerView(); CSeverWinSock HTTPServer; #ifdef _DEBUG
Ну вот и всё готово. Теперь можно обрабатывать нажатие мышки.
//////////////////////////////////// // CHTTPServerView message handlers void CHTTPServerView::OnLButtonDown(UINT nFlags, CPoint point) { 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) { 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_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 Connect !!!!!"; Invalidate(); return 0L; }
Надо устранить еще одну ошибку допушенную мною в прошлом шаге, при указании порта в LinkSoketPort. Это функция конвертации.
socketaddr.sin_port = htons(PORT_ADDR);
Собирайте проект. Устанавливайте связь с интернетом и запускайте.
А вот теперь нужно протестировать. Я тестировал на Windows 98 с удаленным доступом к Internet. Так как IP адрес динамический я его посмотрел используя IPconfig и ввел в Exploler. Вот смотрите рисунок ниже. Конечно соединение прошло, но Internet Explorer нечего не показал, хотя пытался. Конечно :-) Нужен код типа Client_Read, но мы его сделаем :-) в следующем шаге.