- •Методические указания к лабораторным работам Санкт-Петербург
- •2004 Г.
- •Лабораторная работа №1
- •Лабораторная работа №2
- •Лабораторная работа №3:
- •1. Local Info
- •2. Connections
- •4. Nb Scanner
- •10. Finger
- •11. LookUp
- •12. Get Time
- •13. Telnet client
- •14. Ip Monitor
- •15. Host Monitor
- •Interface
- •Ip-Monitor
- •Лабораторная работа №4:
- •Лабораторная работа №5:
- •Лабораторная работа № 6.
- •5.5. Передача и прием данных
- •5.7. Приложение client
5.7. Приложение client
Исходные тексты приложения CLIENT, предназначенного для совместного использования с только что описанным приложением SERVER, приведены ниже.
После запуска этого приложения вы должны создать канал связи с приложением SERVER, выбрав из меню File строку Connect, после чего можно посылать сообщение Test message, выбирая из этого же меню строку Send Message.
Сервер, получив сообщение, отобразит его на экране в отдельной диалоговой панели.
Файл 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 ("mycomputer");
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 ("mycomputer");
Разумеется, вы должны также изменить имя компьютера.
Можно также указать адрес узла в виде десятичных цифр, для чего следует убрать символ комментария со следующей строки:
// dest_sin.sin_addr .s_addr = inet_addr ("200.200.200.201");
Идентификаторы ресурсов приложения CLIENT определены в файле resource.h, представленном в листинге 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 содержит определения ресурсов приложения.
Файл 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
///////////////////////////////////////////////////////
#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
///////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////
// Generated from the TEXTINCLUDE 3 resource.
//
///////////////////////////////////////////////////////#endif
// not APSTUDIO_INVOKED
Варианты заданий к работе:
Предварительное задание: разобраться с идеологией написания приложений с сокетами.
Вариант 1
Написать программу-сервер и программу-клиент, работающие на разных компьютерах. Программа-клиент читает строки со стандартного ввода и пересылает их программе-серверу, которая заносит их в файл.Для каждого компьютера-клиента ведется собственный файл. Сервер должен уметь обслуживать несколько соединений от различных клиентов одновременно.
Вариант 2
Написать программу-сервер, которая, после подсоединения к ней клиента, принимает от клиента данные со стандартного ввода и отправляет их остальным подключенным клиентам, если они есть. В противном случае клиенту посылается сообщение о ошибке, которое клиент должен принять и интерпретировать.
Вариант 3
Написать программу-сервер и программу-клиент. Клиент соединяется с сервером и передает ему имя файла. Сервер открывает указанный файл со своего локального диска и пересылает содержимое файла клиенту, который сохраняет файл на свой локальный диск.
Вариант 4
Написать программу чат-сервер. Клиент подсоединяется к серверу. Вcе текстовые строки, введенные клиентом принимаются сервером и рассылаются всем подсоединенным клиентам (включая отправителя).
Вариант 5
Написать программу-сервер и программу-клиент, тестирующие производительность сети по скорости передачи по сети больших объемов данных. Клиент отправляет запрос серверу, сервер в ответ пересылает псевдослучайный массив объемом в 50 Мб. Клиент измеряет скорость передачи данных.
Вариант 6
Написать программу-сервер и программу-клиент. Клиент соединяется с сервером и передает ему строку символов. Сервер перекодирует строку символов из кодировки ANSI в кодировку ASCII (кодировка window в кодировку DOS) и передает ее обратно клиенту.
Вариант 7
Написать программу-сервер и программу - клиент. Клиент читает файл, пересылает его серверу. Сервер, в свою очередь, пересылает файл всем подключенным клиентам кроме отправителя. Клиент, получив файл, записывает его.