#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[] = "WClientUDP ";
// Заголовок главного окна приложения
char szAppTitle[] = "Windows Socket UDP Client Demo";
// Идентификатор органа управления Statusbar
HWND hwndSb;
|
|
// Сокет клиента
SOCKET srv_socket;
// Адрес сервера
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 = sizeof(WNDCLASSEX);
wc.hIconSm = LoadImage(hInst,
MAKEINTRESOURCE(IDI_APPICON_SM), IMAGE_ICON, 16, 16, 0);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
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))
if(!RegisterClass((LPWNDCLASS)&wc.style))
return FALSE;
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)
{
HANDLE_MSG(hWnd, WM_CREATE, WndProc_OnCreate);
HANDLE_MSG(hWnd, WM_COMMAND, WndProc_OnCommand);
HANDLE_MSG(hWnd, WM_SIZE, WndProc_OnSize);
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_DGRAM, 0);
if(srv_socket == INVALID_SOCKET)
{
MessageBox(NULL, "socket Error", "Error", MB_OK);
return;
}
// Связываем адрес IP с сокетом
dest_sin.sin_family = AF_INET;
dest_sin.sin_addr.s_addr = INADDR_ANY;
dest_sin.sin_port = 0;
if(bind (srv_socket, (LPSOCKADDR)&dest_sin,
sizeof(dest_sin)) == SOCKET_ERROR)
{
// При ошибке закрываем сокет
closesocket (srv_socket);
MessageBox(NULL, "bind Error", "Error", MB_OK);
return;
}
// Устанавливаем адрес IP и номер порта
dest_sin.sin_family = AF_INET;
// Определяем адрес узла
// Адрес локального узла для отладки
phe = gethostbyname ("localhost ");
// Адрес удаленного узла
// phe = gethostbyname ("maxsinev");
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);
// В случае успеха выводим сообщение об установке
// соединения с узлом
SendMessage(hwndSb, SB_SETTEXT, 0,
(LPARAM)"Connected");
}
// -----------------------------------------------------
// Функция SendMsg
// -----------------------------------------------------
void SendMsg(HWND hWnd)
{
char szBuf[80];
lstrcpy(szBuf, "Test string");
// Посылаем сообщение
send to(srv_socket, szBuf, lstrlen(szBuf), 0,
(PSOCKADDR)&dest_sin, sizeof(dest_sin));
}
Функция SetConnection создает сокет типа SOCK_DGRAM, так как передача данных будет выполняться с использованием протокола UDP:
srv_socket = socket(AF_INET, SOCK_DGRAM, 0);
Далее выполняется привязка сокета к адресу с помощью функции bind. При этом указывается нулевое значение порта и адрес INADDR_ANY, так как на данном этапе эти параметры не имеют значения.
Затем функция SetConnection записывает адрес сервера в структуру dest_sin. Этот адрес потребуется для передачи сообщений серверу.
При использовании протокола UDP и если не создан канал между приложениями, для передачи данных следует использовать функцию send to:
send to(srv_socket, szBuf, lstrlen(szBuf), 0,
(PSOCKADDR)&dest_sin, sizeof(dest_sin));
В качестве предпоследнего параметра этой фукнции нужно передать адрес заполненной структуры, содержащей адрес узла, куда будет посылаться пакет данных. Через последний параметр функции send to необходимо передать размер указанной структуры.
Привдедем список возможных кодов ошибок для функции send to:
Код ошибки | Описание |
WSANOTINITIALISED | Перед использованием функции необходимо вызвать функцию WSAStartup |
WSAENETDOWN | Сбой в сети |
WSAEACCES | Не был установлен флаг широковещательного адреса |
WSAEINTR | Работа функции была отменена при помощи функции WSACancelBlockingCall |
WSAEINPROGRESS | Выполняется блокирующая функция интерфейса Windows Sockets |
WSAEFAULT | Неправильно указан адрес буфера, содержащего передаваемые данные |
WSAENETRESET | Необходимо сбросить соединение |
WSAENOBUFS | Произошло зацикливание буферов |
WSAENOTSOCK | Указанный дескриптор не является дескриптором сокета |
WSAESHUTDOWN | Сокет был закрыт функцией shutdown |
WSAEWOULDBLOCK | Сокет отмечен как неблокирующий, но запрошенная операция приведет к блокировке |
WSAEMSGSIZE | Размер датаграммы больше, чем это допускается данной реализацией интерфейса Windows Sockets |
WSAECONNABORTED | Сбой из-за слишком большой задержки или по другой причине |
WSAECONNRESET | Сброс соединения удаленным узлом |
WSAEADDRNOTAVAIL | Указанный адрес недоступен |
WSAEAFNOSUPPORT | Данный тип сокета не может работать с указанным семейством адресов |
WSAEDESTADDRREQ | Необходимо указать адрес получателя датаграммы |
WSAENETUNREACH | В данное время и из данного узла невозможно получить доступ к сети |
Заметим, что клиент может создать канал связи с сервером, вызвав функцию connect, и передавать по этому каналу пакеты UDP, пользуясь функциями send и recv. Этот способ удобен тем, что при передаче пакета не нужно каждый раз указывать адрес получателя.
|
|