русс | укр

Языки программирования

ПаскальСиАссемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование

Все о программировании


Linux Unix Алгоритмические языки Аналоговые и гибридные вычислительные устройства Архитектура микроконтроллеров Введение в разработку распределенных информационных систем Введение в численные методы Дискретная математика Информационное обслуживание пользователей Информация и моделирование в управлении производством Компьютерная графика Математическое и компьютерное моделирование Моделирование Нейрокомпьютеры Проектирование программ диагностики компьютерных систем и сетей Проектирование системных программ Системы счисления Теория статистики Теория оптимизации Уроки AutoCAD 3D Уроки базы данных Access Уроки Orcad Цифровые автоматы Шпаргалки по компьютеру Шпаргалки по программированию Экспертные системы Элементы теории информации

If (gethostname(szInfo,sizeof(szInfo)))


Дата добавления: 2015-01-16; просмотров: 654; Нарушение авторских прав


printf(“Local host name has not been configured\n”);

Else

printf(“Host name is %s.\n”, szInfo);

 

if (WSACleanup())

printf(“Winsock cleanup FAILED!\n”);

else

printf(“Winsock cleanup is successful.\n”);

 

system(«pause»);

 

return;

}

 

Отличие этого примера от предыдущего заключается в использовании информационной функции gethostname(), имеющей следующий прототип:

int gethostname (

char FAR * name,

int namelen

);

В эту функцию передается буфер и его длина для возврата имени. При отсутствии ошибок эта функция вернет 0. Результат штатной работы программы приведен на рисунке 2.4.2.

Рисунок 2.4.2 – Работа функции gethostname()

 

Рассмотрим процедуру создания и закрытия сокетов, изменив предыдущий пример:

 

#include <stdio.h>

#include <winsock.h>

 

const int WINSOCK_VERSION = 0x0101;

 

void main()

{

SOCKET serverSocket;

Char szInfo[BUFSIZ];

WSADATA wsaData;

 

if (WSAStartup(WINSOCK_VERSION, &wsaData))

printf(“Winsock startup FAILED!\n”);

else

printf(“Winsock startup is successful.\n”);

 

if (gethostname(szInfo,sizeof(szInfo)))

printf(“Local host name has not been configured\n”);

else

printf(“Host name is %s.\n”, szInfo);

 

serverSocket = socket(PF_INET, SOCK_STREAM, 0);

 

if (serverSocket == INVALID_SOCKET)

printf(“Socket creation FAILED!\n”);

closesocket(serverSocket);

 

if (WSACleanup())

printf(“Winsock cleanup FAILED!\n”);

else

printf(“Winsock cleanup is successful.\n”);

 

system(«pause»);

 

return;

}

 

Добавлена следующая переменная:

SOCKET serverSocket;

Тип SOCKET определяется в файле winsock.h следующим образом:

/*

* The new type to be used in all



* instances which refer to sockets.

*/

 

typedef UINT_PTR SOCKET;

А UINT_PTR в файле basetsd.h как

typedef _W64 unsigned int UINT_PTR, *PUINT_PTR;

То есть, по сути, является замаскированным целочисленным числом без знака типа unsigned int и содержит идентификатор сокета в системе.

За создание сокета отвечает следующая строчка:

serverSocket = socket(PF_INET, SOCK_STREAM, 0);

Функция socket() создает сокет заданного типа и возвращает его идентификатор в случае успеха или константу INVALID_SOCKET (также определена в файле winsock.h) в противном случае. Все три аргумента функции являются целочисленными, задают тип сокета указанием нужных констант, список которых можно найти в заголовочном файле, в документации среды разработки или в RFC 790, от сентября 1981 года. Первый аргумент – тип сетевой модели, PF_INET соответствует сетевой модели Интернета (TCP/IP), PF_OSI модели OSI, PF_APPLETALK модели AppleTalk и т.д. Однако указание, например, PF_OSI в качестве сетевой модели приведет к ошибке создания сокета, поскольку в рамках Windows данная модель не поддерживается, а аргумент функции и константы введены для возможности расширения интерфейса и, возможно, использования в будущих операционных системах. Дальше указывается тип потока: SOCK_STREAM используется для TCP, а SOCK_DGRAM для UDP. Третий аргумент – собственно протокол, где 0 по умолчанию IP.

После работы сокет необходимо закрыть:

closesocket(serverSocket);

Единственным параметром функции является сокет, который требуется закрыть.

Попробуем реализовать простой сервер, работающий по протоколу http и использующий соответственно порт 80.

Рассмотрим, как производится подключение к серверу. Сначала программа подключается к адресу IP с созданием сокета. Программа будет ждать подключения. Для подключения программа клиент тоже создает сокет и пытается подключиться к сокету сервера. Как только сервер зарегистрирует попытку подключения, он создаст новый сокет. И этот новый сокет будет использоваться для взаимодействия с клиентом. А тот сокет, к которому была попытка подключения, будет ждать следующего. Сокет может быть создан на основе TCP или UDP. На этой основе производится взаимодействие сервера и многими программами.

Для организации связи серверу необходимо вызвать функцию bind() для действительного сокета и связать его с номером порта, который будет «прослушиваться» для ожидания подключения. Функция требует заполненную структуру SOCKADDR_IN с такими параметрами связи, как порт и атрибуты. Ее прототип:

struct sockaddr_in{

short sin_family;

unsigned short sin_port;

struct in_addr sin_addr;

char sin_zero[8];};

В данной структуре присутствует вложенная структура sin_addr, она описана следующим образом:

struct in_addr {

union {

struct{

unsigned char

s_b1,

s_b2,

s_b3,

s_b4;

} S_un_b;

struct{

unsigned short

s_w1,

s_w2;

} S_un_w;

unsigned long S_addr;

} S_un;

};

Смысл полей достаточно прозрачен: тип сетевого адреса (соответствующий разным сетевым моделям), адрес, порт.

После описания структур и заполнения данными можно вызывать bind() с проверкой результата на ошибку:

SOCKADDR_IN socketaddr;

socketaddr.sin_family = AF_INET;

socketaddr.sin_addr.s_addr = INADDR_ANY;

socketaddr.sin_port = htons(80);

 

if (bind(serverSocket,(LPSOCKADDR)&socketaddr,sizeof(socketaddr)) == SOCKET_ERROR)

printf(“Socket binding FAILED!”);

else

printf(“Socked binding is successful.\n”);

Ее прототип:

int bind (

SOCKET s,

const struct sockaddr FAR* name,

int namelen

);

Если всё нормально, то данная функция вернет 0 в противном случае SOCKET_ERROR. Как видно адрес не указывается (INADDR_ANY это константа нуля), поскольку создается сокет для сервера. Полный текст программы выглядит следующим образом:

 

#include <stdio.h>

#include <winsock.h>

 

const int WINSOCK_VERSION = 0x0101;

 

void main()

{

SOCKET serverSocket;

SOCKADDR_IN socketaddr;

char szInfo[BUFSIZ];

WSADATA wsaData;

 

if (WSAStartup(WINSOCK_VERSION, &wsaData))

printf(“Winsock startup FAILED!\n”);

else

printf(“Winsock startup is successful.\n”);

 

if (gethostname(szInfo,sizeof(szInfo)))

printf(“Local host name has not been configured\n”);

else

printf(“Host name is %s.\n”, szInfo);

 

serverSocket = socket(PF_INET, SOCK_STREAM, 0);

 

if (serverSocket == INVALID_SOCKET)

printf(“Socket creation FAILED!\n”);

 

socketaddr.sin_family = AF_INET;

socketaddr.sin_addr.s_addr = INADDR_ANY;

socketaddr.sin_port = htons(80);

if (bind(serverSocket, (LPSOCKADDR)&socketaddr, sizeof(socketaddr)) == SOCKET_ERROR)

printf(“Socket binding FAILED!\n”);

Else

printf(“Socked binding is successful.\n”);

 

closesocket(serverSocket);

 

if (WSACleanup())

printf(“Winsock cleanup FAILED!\n”);

else

printf(“Winsock cleanup is successful.\n”);

 

system(«pause»);

 

return;

}

 

В компьютерах архитектуры Intel 80x86 и совместимыми с ними слово (двухбайтовое число) хранится следующим образом:

младщий байт n;

старший байт n+1,

где n – номер ячейки в памяти.

К сожалению в Интернете наоборот:

младщий байт n+1;

старший байт n.

Для решения этой проблемы WinSock API предоставляет следующие функции:

1. htohl – Преобразует 32 битные локальные числа к сетевым, сортируя байты;

2. htohs – Преобразует 16 битные локальные числа к сетевым, сортируя байты;

3. ntonl – Преобразует 32 битные сетевые числа к локальным, сортируя байты;

4. ntons – Преобразует 16 битные сетевые числа к локальным, сортируя байты.

 

На данном этапе, программа почти готова принимать сообщения по сети, однако как узнать, что клиент установил соединение с сервером? Для этого используются события и сообщения ОС Windows. Как известно, обработчиком сообщений является окно, а, следовательно, необходимо связать сокет с дескриптором окна. Для этого служит функция WSAAsyncSelect(). Как следует из приставки WSA, она относится к расширениям Windows для функций Беркли, то есть, специфична для этой ОС.

 

Int error;

error = WSAAsyncSelect(serverSocket, hWnd, WM_SERVER_ACCEPT, FD_ACCEPT);

 

if (error == SOCKET_ERROR)

printf(“WSAAsyncSelect() FAILED!\n”);

 

Прототип функции имеет следующий вид:

int WSAAsyncSelect (

SOCKET s,

HWND hWnd,

unsigned int wMsg,

long lEvent

);

Первым аргументом передается сокет, вторым – дескриптор окна, третьим – сообщение, которое будет послано, четвертым – событие, при котором генерируется сообщение. FD_ACCEPT означает, что сообщение сгенерируется при запросе от клиента.

Здесь интересен параметр unsigned int wMsg – этот параметр говорит о том, какое сообщение будет послано в случае подключения к серверу. Сообщения WM_SERVER_ACCEPT в Windows не существует, это пользовательское сообщение, его можно описать следующим образом:

const int WM_SERVER_ACCEPT = WM_USER + 1;

Включается «прослушивание» функцией listen().

Error = listen(serverSocket, 10);

 

if (error == SOCKET_ERROR)

printf(«listen() FAILED!\n»);

Прототип функции listen() выглядит следующим образом:

int listen (

SOCKET s,

int backlog

);

Первый аргументом является сокет, вторым – максимально количество подключений.

К сожалению, просто добавить в текст последней программы функцию WSAAsyncSelect не получится. Первая проблема очевидна – это отсутствие дескриптора окна у консольного приложения, вторая – отсутствие обработки поступающих сообщений. И если первую еще можно решить, например, поиском дескриптора окна по его заголовку функцией FindWindow(), то вторая приводит к необходимости создания оконной процедуры и полноценного Windows приложения.

Ниже приведен текст Winsock программы, выступающей в роли сервера HTTP:

 

// Стандартный включаемый файл Windows

#include <windows.h>

#include <winsock.h>

const int WINSOCK_VERSION = 0x0101;

const int WM_SERVER_ACCEPT = WM_USER + 1;

 

// Прототип функции обратного вызова для обработки сообщений

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

 

bool Start(HWND);

void Stop();

char g_szStatus[512];

SOCKET g_serverSocket;

 

// Функция вызывается автоматически, когда программа запускается

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)

{

HWND hWnd;

MSG msg;

WNDCLASSEX wndclass;

 

// Настройка класса окна

wndclass.cbSize = sizeof(WNDCLASSEX);

wndclass.style = CS_HREDRAW | CS_VREDRAW;

wndclass.lpfnWndProc = WndProc;

wndclass.cbClsExtra = 0;

wndclass.cbWndExtra = 0;

wndclass.hInstance = hInstance;

wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);

wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);

wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);

wndclass.lpszMenuName = NULL;

wndclass.lpszClassName = “Window Class”; // Имя класса

wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

 

// Регистрация класса окна

if(RegisterClassEx(&wndclass) == 0)

{

// Сбой программы, выход

return 0;

}

 

// Создание окна

hWnd = CreateWindowEx(

WS_EX_OVERLAPPEDWINDOW,

«Window Class», // Имя класса

«Сервер», // Текст заголовка

WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,



<== предыдущая лекция | следующая лекция ==>
Windows Sockets | CW_USEDEFAULT,


Карта сайта Карта сайта укр


Уроки php mysql Программирование

Онлайн система счисления Калькулятор онлайн обычный Инженерный калькулятор онлайн Замена русских букв на английские для вебмастеров Замена русских букв на английские

Аппаратное и программное обеспечение Графика и компьютерная сфера Интегрированная геоинформационная система Интернет Компьютер Комплектующие компьютера Лекции Методы и средства измерений неэлектрических величин Обслуживание компьютерных и периферийных устройств Операционные системы Параллельное программирование Проектирование электронных средств Периферийные устройства Полезные ресурсы для программистов Программы для программистов Статьи для программистов Cтруктура и организация данных


 


Не нашли то, что искали? Google вам в помощь!

 
 

© life-prog.ru При использовании материалов прямая ссылка на сайт обязательна.

Генерация страницы за: 0.009 сек.