Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

Глобальные сети компьютеров. Практическое введение в Internet, E-Mail, FTP, WWW и HTML, программирование для Windows Sockets

© Александр Фролов, Григорий Фролов
Том 23, М.: Диалог-МИФИ, 1993, 283 стр.

[Назад] [Содеожание] [Дальше]

5.7. Приложение CLIENT

Исходные тексты приложения CLIENT, предназначенного для совместного использования с только что описанным приложением SERVER, приведены в листинге 5.4.

После запуска этого приложения вы должны создать канал связи с приложением SERVER, выбрав из меню File строку Connect, после чего можно посылать сообщение Test message, выбирая из этого же меню строку Send Message.

Сервер, получив сообщение, отобразит его на экране в отдельной диалоговой панели.

Листинг 5.4. Файл client/client.c


#include <windows.h>
#include <windowsx.h>
#include <winsock.h>
#include <commctrl.h>
#include "resource.h"

// -----------------------------------------------------
// Описание функций
// -----------------------------------------------------

// Функция главного окна
LRESULT WINAPI
WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

// Функция для обработки сообщения WM_CREATE 
BOOL WndProc_OnCreate(HWND hWnd, LPCREATESTRUCT lpCreateStruct);

// Функция для обработки сообщения WM_DESTROY 
void WndProc_OnDestroy(HWND hWnd);

// Функция для обработки сообщения WM_COMMAND 
void WndProc_OnCommand(HWND hWnd, int id, 
  HWND hwndCtl, UINT codeNotify);

// Функция для обработки сообщения WM_SIZE 
void WndProc_OnSize(HWND hWnd, UINT state, int cx, int cy);

// Установка соединения
void SetConnection(HWND hWnd);

// Передача сообщения
void SendMsg(HWND hWnd);

// Порт сервера
#define SERV_PORT 5000

#define IDS_STATUSBAR 802

// -----------------------------------------------------
// Глобальные переменные
// -----------------------------------------------------

// Идентификатор приложения
HINSTANCE hInst;

// Название приложения
char szAppName[] = "WClient";

// Заголовок главного окна приложения
char szAppTitle[] = "Windows Socket Client Demo";

// Идентификатор органа управления Statusbar 
HWND hwndSb;

// Сокет клиента
SOCKET srv_socket ;

// Локальный сокет
SOCKADDR _IN local_sin;

// Адрес сервера
SOCKADDR _IN dest_sin;

// -----------------------------------------------------
// Функция WinMain
// -----------------------------------------------------

int APIENTRY 
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
        LPSTR lpCmdLine, int nCmdShow)
{
  WNDCLASSEX wc;
  HWND hWnd;
  MSG msg;

  hInst = hInstance;

  // Преверяем, не было ли это приложение запущено ранее
  hWnd = FindWindow(szAppName, NULL);
  if(hWnd)
  {
    // Если окно приложения было свернуто в пиктограмму,
    // восстанавливаем его
    if(IsIconic(hWnd))
	  ShowWindow(hWnd, SW_RESTORE);

    // Выдвигаем окно приложения на передний план
	  SetForegroundWindow(hWnd);
    return FALSE;
  }

  // Регистрируем класс окна
  memset(&wc, 0, sizeof(wc));
  
  // Поля wc.cbSize	и wc.hIconSm определены в структуре
  // WNDCLASSEX, которой можно пользоваться для
  // регистрации класса окна в Windows 95
  wc.cbSize = sizeof(WNDCLASSEX);

  // Поле wc.hIconSm задает идентификатор маленькой
  // пиктограммы, которая будет отображаться в левой
  // части заголовка окна (в области системного меню).
  // Загружаем пиктограмму из ресурсов приложения при
  // помощи функции LoadImage, так как функция
  // LoadIcon может загрузить только обычную пиктограмму
  wc.hIconSm = LoadImage(hInst,
    MAKEINTRESOURCE(IDI_APPICON_SM), IMAGE_ICON, 16, 16, 0);
  
  // Завершаем заполнение структуры WNDCLASSEX
  wc.style = CS_HREDRAW | CS_VREDRAW;
  wc.lpfnWndProc = (WNDPROC)WndProc;
  wc.cbClsExtra  = 0;
  wc.cbWndExtra  = 0;
  wc.hInstance = hInst;
  
  // Для загрузки обычной пиктограммы вы можете
  // использовать функцию LoadImage
  wc.hIcon = LoadImage(hInst,
    MAKEINTRESOURCE(IDI_APPICON), IMAGE_ICON, 32, 32, 0);
  
  wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
  wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);
  wc.lpszClassName = szAppName;

  // Вызываем функцию RegisterClassEx, которая выполняет
  // регистрацию окна
  if(!RegisterClassEx(&wc))

    // В случае ошибки пытаемся зарегистрировать окно
    // функцией RegisterClass
    if(!RegisterClass((LPWNDCLASS)&wc.style))
	  return FALSE;
    
  // Инициализация библиотеки органов управления
  // общего назначения. Необходима для работы с
  // органом управления Statusbar 
  InitCommonControls();
  
  // Создаем главное окно приложения
  hWnd = CreateWindow(szAppName, szAppTitle, WS_OVERLAPPEDWINDOW,
    CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInst, NULL);
  if(!hWnd) return(FALSE);

  // Отображаем окно
  ShowWindow(hWnd, nCmdShow);
  UpdateWindow(hWnd);

  // Запускаем цикл обработки сообщений
  while(GetMessage(&msg, NULL, 0, 0))
  {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }
  return msg.wParam;
}

// -----------------------------------------------------
// Функция WndProc
// -----------------------------------------------------

LRESULT WINAPI
WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  switch(msg)
  {
    // Для сообщения WM_CREATE  назначаем обработчик,
    // расположенный в функции WndProc_OnCreate
    HANDLE_MSG(hWnd, WM_CREATE , WndProc_OnCreate);

    // Для сообщения WM_COMMAND  назначаем обработчик,
    // расположенный в функции WndProc_OnCommand
    HANDLE_MSG(hWnd, WM_COMMAND , WndProc_OnCommand);

    // Для сообщения WM_SIZE  назначаем обработчик,
    // расположенный в функции WndProc_OnSize
    HANDLE_MSG(hWnd, WM_SIZE , WndProc_OnSize);

    // Для сообщения WM_DESTROY  назначаем обработчик,
    // расположенный в функции WndProc_OnDestroy
    HANDLE_MSG(hWnd, WM_DESTROY , WndProc_OnDestroy);

    default:
       return(DefWindowProc(hWnd, msg, wParam, lParam));
  }
}

// -----------------------------------------------------
// Функция WndProc_OnCreate
// -----------------------------------------------------

BOOL WndProc_OnCreate(HWND hWnd, 
                      LPCREATESTRUCT lpCreateStruct)
{
  int rc;
  WSADATA  WSAData;
  char szTemp[128];

  // Инициализация и проверка версии Windows Sockets
  rc = WSAStartup (MAKEWORD(1, 1), &WSAData);
  if(rc != 0)
  {
    MessageBox(NULL, "WSAStartup  Error", "Error", MB_OK);
    return FALSE;
  }

  // Отображаем описание и версию системы Windows Sockets
  // в окне органа управления Statusbar 
  wsprintf(szTemp, "Server use %s %s", 
    WSAData.szDescription,WSAData.szSystemStatus);

  hwndSb = CreateStatusWindow(WS_CHILD | WS_VISIBLE 
    | WS_BORDER | SBARS_SIZEGRIP, 
    szTemp, hWnd, IDS_STATUSBAR);

  return TRUE;
}

// -----------------------------------------------------
// Функция WndProc_OnDestroy
// -----------------------------------------------------

#pragma warning(disable: 4098)
void WndProc_OnDestroy(HWND hWnd)
{
  // Освобождение ресурсов, полученных для
  // работы с Windows Sockets
  WSACleanup ();

  // Завершение цикла обработки сообщений
  PostQuitMessage(0);
  return FORWARD_WM_DESTROY (hWnd, DefWindowProc);
}

// -----------------------------------------------------
// Функция WndProc_OnSize
// -----------------------------------------------------

#pragma warning(disable: 4098)
void 
WndProc_OnSize(HWND hWnd, UINT state, int cx, int cy)
{
  SendMessage(hwndSb, WM_SIZE , cx, cy);
  return FORWARD_WM_SIZE (hWnd, state, cx, cy, DefWindowProc);
}

// -----------------------------------------------------
// Функция WndProc_OnCommand
// -----------------------------------------------------

#pragma warning(disable: 4098)
void 
WndProc_OnCommand(HWND hWnd, int id, 
  HWND hwndCtl, UINT codeNotify)
{
  switch (id)
  {
    case IDM_EXIT:

      // Уничтожение главного окна прилоджения
      DestroyWindow(hWnd);
      break;

    case IDM_CONNECT:
      
      // Установка соединения с сервером
      SetConnection(hWnd);
      break;

    case IDM_SEND:
      
      // Посылка сообщения серверу
      SendMsg(hWnd);
      break;

	default:
      MessageBox(NULL, "Unknown command", "Error", MB_OK);
  }

  return FORWARD_WM_COMMAND (hWnd, id, hwndCtl,
    codeNotify, DefWindowProc);
}

// -----------------------------------------------------
// Функция SetConnection
// -----------------------------------------------------

void SetConnection(HWND hWnd)
{
  PHOSTENT  phe;
	
  // Создаем сокет 
  srv_socket  = socket(AF_INET , SOCK_STREAM, 0);
  if(srv_socket  == INVALID_SOCKET)
  {
    MessageBox(NULL, "socket  Error", "Error", MB_OK);
    return;
  }

  // Устанавливаем адрес IP и номер порта
  dest_sin.sin_family = AF_INET ;

  // Определяем адрес узла

  // Адрес локального узла для отладки
  phe = gethostbyname ("localhost ");
  
  // Адрес удаленного узла
  //phe = gethostbyname ("frolov");
  
  if(phe == NULL)
  {
    closesocket  (srv_socket);
    MessageBox(NULL, "gethostbyname  Error", "Error", MB_OK);
    return;
  }

  // Копируем адрес узла
  memcpy((char FAR *)&(dest_sin.sin_addr ), phe->h_addr ,
	  phe->h_length);

  // Другой способ указания адреса узла
  //  dest_sin.sin_addr .s_addr = inet_addr ("200.200.200.201");

  // Копируем номер порта
  dest_sin.sin_port = htons(SERV_PORT);

  // Устанавливаем соединение
  if(connect(srv_socket , (PSOCKADDR  )&dest_sin, 
    sizeof(dest_sin)) < 0)
  {
    closesocket  (srv_socket);
    MessageBox(NULL, "connect Error", "Error", MB_OK);
    return;
  }

  // В случае успеха выводим сообщение об установке
  // соединения с узлом
  SendMessage(hwndSb, SB_SETTEXT, 0, 
    (LPARAM)"Connected");
}

// -----------------------------------------------------
// Функция SendMsg
// -----------------------------------------------------

void SendMsg(HWND hWnd)
{
	char szBuf[80];
	lstrcpy(szBuf, "Test string");

  // Посылаем сообщение
  send (srv_socket , szBuf, lstrlen(szBuf), 0);
}

Вы сможете разобраться с исходными текстами этого прилжоения самостоятельно, так как все использованные в нем функции были нами уже описаны. Обратим ваше внимание только на функцию SetConnection, предназначенную для установки канала связи с сервером.

Если вы будете проверять работу приложений SERVER и CLIENT на одном и том же компьютере, адрес сервера должен быть указан следующим образом:

phe = gethostbyname ("localhost ");

Для того чтобы установить канал связи с компьютером по его имени, закройте символом комментария приведенную выше строку и уберите символ комментария со строки, расположенной ниже:

//phe = gethostbyname ("frolov");

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

Можно также указать адрес узла в виде десятичных цифр, для чего следует убрать символ комментария со следующей строки:

//  dest_sin.sin_addr .s_addr = inet_addr ("200.200.200.201");

Идентификаторы ресурсов приложения CLIENT определены в файле resource.h, представленном в листинге 5.5.

Листинг 5.5. Файл client/resource.h


//{{NO_DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
// Used by CLIENT.rc
//
#define IDI_APPICON                     101
#define IDI_APPICON_SM                  102
#define IDR_MENU1                       105
#define IDM_START                       40001
#define IDM_EXIT                        40002
#define IDM_STOP                        40003
#define IDM_CONNECT                     40004
#define IDM_SEND                        40005

// Next default values for new objects
// 
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NO_MFC                     1
#define _APS_NEXT_RESOURCE_VALUE        106
#define _APS_NEXT_COMMAND_VALUE         40006
#define _APS_NEXT_CONTROL_VALUE         1000
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif

Файл client.rc (листинг 5.6) содержит определения ресурсов приложения.

Листинг 5.6. Файл client/client.rc


//Microsoft Developer Studio generated resource script.
//
#include "resource.h"

#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"

/////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS

/////////////////////////////////////////////////////////////////////
// Russian resources

#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS)
#ifdef _WIN32 
LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
#pragma code_page(1251)
#endif //_WIN32 

#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//

1 TEXTINCLUDE DISCARDABLE 
BEGIN
    "resource.h\0"
END

2 TEXTINCLUDE DISCARDABLE 
BEGIN
    "#include ""afxres.h""\r\n"
    "\0"
END

3 TEXTINCLUDE DISCARDABLE 
BEGIN
    "\r\n"
    "\0"
END

#endif    // APSTUDIO_INVOKED

/////////////////////////////////////////////////////////////////////
//
// Icon
//

// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_APPICON             ICON    DISCARDABLE     "client.ico"
IDI_APPICON_SM          ICON    DISCARDABLE     "clientsm.ico"

/////////////////////////////////////////////////////////////////////
//
// Menu
//

IDR_MENU1 MENU DISCARDABLE 
BEGIN
    POPUP "&File"
    BEGIN
        MENUITEM "&Connect",                    IDM_CONNECT
        MENUITEM "S&end message",               IDM_SEND
        MENUITEM SEPARATOR
        MENUITEM "&Exit",                       IDM_EXIT
    END
END

#endif    // Russian resources
/////////////////////////////////////////////////////////////////////



#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//

/////////////////////////////////////////////////////////////////////
#endif    // not APSTUDIO_INVOKED

[Назад] [Содеожание] [Дальше]