Кафедра вычислительных машин, комплексов, систем и сетей — КиберПедия 

Состав сооружений: решетки и песколовки: Решетки – это первое устройство в схеме очистных сооружений. Они представляют...

История развития хранилищ для нефти: Первые склады нефти появились в XVII веке. Они представляли собой землянные ямы-амбара глубиной 4…5 м...

Кафедра вычислительных машин, комплексов, систем и сетей

2019-09-17 182
Кафедра вычислительных машин, комплексов, систем и сетей 0.00 из 5.00 0 оценок
Заказать работу

ФЕДЕРАЛЬНОЕ АГЕНТСТВО ВОЗДУШНОГО ТРАНСПОРТА

ФЕДЕРАЛЬНОЕ ГОСУДАРСТВЕННОЕ ОБРАЗОВАТЕЛЬНОЕ УЧРЕЖДЕНИЕ

ВЫСШЕГО ПРОФЕССИОНАЛЬНОГО ОБРАЗОВАНИЯ

«МОСКОВСКИЙ ГОСУДАРСТВЕННЫЙ

ТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ

ГРАЖДАНСКОЙ АВИАЦИИ»

____________________________________________________________________________________________________________________

Кафедра вычислительных машин, комплексов, систем и сетей

Н.И. Черкасова

 

ПРОГРАММИРОВАНИЕ

СЕТЕВЫХ ПРИЛОЖЕНИЙ

ДЛЯ ОС СЕМЕЙСТВА WINDOWS

 

Утверждено Редакционно-

издательским Советом МГТУ ГА

в качестве учебного пособия

Москва – 2007

 

УДК 004.32:004.7(075.8)

ББК 32.973.202-018.1я73-1

    Ч-48

Печатается по решению редакционно-издательского совета

Московского государственного технического университета ГА

 

              Рецензенты: канд. физ.-мат. наук, доц. Л.А. Надейкина;

                                    канд техн. наук Ю.Н. Шайдуров

 

              Черкасова Н.И.

Ч 48     Программирование сетевых приложений для ОС семейства Windows: Учебное пособие. - М.: МГТУ ГА, 2007. – 72 с. 2 табл., 4 ил., лит.: 5 наим.

 

ISBN 978-5-86311-588-7

 

Данное учебное пособие издается в соответствии с рабочей программой учебной дисциплины «Сетевые операционные системы» по Учебному плану специальности 230101 для студентов IV курса дневного обучения, утвержденному в 2007 г.

В учебном пособии рассматриваются особенности программирования сетевых приложений с использованием АРI ОС семейства Windows, сетевые АРI – Windows NetBIOS, именованные каналы, почтовые ящики,Windows Sockets.

Рассмотрено и одобрено на заседаниях кафедры 23.10.07 г. и методического совета 25.10.07 г.

 

Ч
2404000000-037                                                                               

Ц33(03)-07                                                                        

                                                                                                             

 

 

Содержание

                                                                                                                           

1. Программирование сетевых приложений с использованием API ОС семейства Windows. Сетевые API - Windows NetBIOS ……………….....   4
1.1. Разрешение имен сетевых ресурсов в ОС Windows 2000. Маршру-тизатор многосетевого доступа. Многосетевой UNS- провайдер…..   4
1.1.1.Разрешение имен сетевых ресурсов в ОС Windows 2000. Networking APIs………………………………………………….   4
1.1.2. Маршрутизатор многосетевого доступа………………………. 5
1.1.3. Многосетевой UNС провайдер…………………………………. 6
1.2.Универсальные правила именования (UNC –имена)………………… 7
1.3.Интерфейс NetBIOS. Имена NetBIOS. Номера LANA……………….. 8
1.3.1. Интерфейс NetBIOS……………………………………………... 8
1.3.2. Имена NetBIOS…………………………………………………... 8
1.3.3. Номера LANA…………………………………………………… 9
2.Сетевые API. Именованные каналы и почтовые ящики…………………... 10
2.1.Каналы передачи данных МаilSlot…………………………………….. 10
2.1.1.Основные механизмы почтовых ящиков. Размеры сообщений.. 10
2.1.2.Архитектура почтовых ящиков. Создание серверного и клиентского приложений………………………………………..   11
2.1.3. Основные функции реализации почтового ящика……………. 12
2.1.4. Сервер с отменой блокирующих запросов ввода-вывода……. 16
Приложение 1………………………………………………………………. 16
2.2.Каналы передачи данных Named Pipe - Именованные каналы……… 20
2.2.1.Особенности именованных каналов как средство реализации сетевых приложений……………………………………………...   20
2.2.2.Реализации именованных каналов. Структура серверного и клиентского приложений…………………………………………   24
2.2.3.Функции для работы с каналами………………………………... 26
Приложение 2……………………………………………………………….. 41
3. Сетевое программирование с помощью Windows Sockets……………….. 47
3.1.Интерфейс прикладного программирования Windows Sockets (Winsock)………………………………………………………………...   47
3.2.Функционирование Winsock…………………………………………… 48
3.3. Реализация Winsock……………………………………………………. 49
3.4.Транспортные протоколы, поддерживаемые Win 32………………… 50
3.5.Разработка приложения. Инициализация Winsock. Структура серверного и клиентского приложений……………………………….   55
3.6. Основные функции WinSock………………………………………….. 57
Приложение 3……………………………………………………………….. 63
Литература………………………………………………………………………. 71

 

Программирование сетевых приложений с использованием API ОС семейства Windows. Сетевые API - Windows NetBIOS

Разрешение имен сетевых ресурсов в ОС Windows 2000.

Маршрутизатор многосетевого доступа.

Многосетевой UNS - провайдер

Многосетевой UNC провайдер

Это еще один компонент, который решает, какой редиректор вызвать для обработки запроса на удаленный ввод/вывод, если в систему загружены дополнительные редиректоры для доступа к сетям других типов. Многосетевой UNC (Multiple UNC Provider, MUP) - драйвер, определяющий, к какой сети следует обратиться, когда приложение использует стандартный Win32 API ввода/вывода для открытия удаленных файлов. Этот сетевой компонент обрабатывает запросы к файлам или устройствам, содержащим имя UNC (это имя, начинающееся с символов \\, которые указывают, что данный ресурс находится в сети). Драйвер mup.sys, подобно MPR, определяет, какой локальный редиректор распознает удаленный ресурс. Драйвер mup.sys активизируется, когда приложение пытается открыть удаленный файл или устройство, задавая имя UNC. Получив подобный запрос, подсистема Win32 заменяет символы \\ строкой \DosDevices\UNC и передает запрос исполнительной системе. Объект \DosDevices\UNC является символической связью на объект-устройство \Device\mup, создаваемый драйвером mup.sys. Драйвер mup.sys является довольно простым драйвером и реализует процедуры распределения create/ open. После получения запроса на открытие, драйвер mup.sys посылает особые контрольные пакеты каждому редиректору, зарегистрированному драйвером mup.sys. Этим запросом mup.sys спрашивает редиректор, может ли тот распознать оставшуюся часть имени UNC. Если да, то редиректор должен информировать драйвер mup.sys о числе символов в строке имени UNC, которые он распознает как уникальный идентификатор удаленного ресурса. Драйвер mup.sys кэширует эту часть строки имени и в последствии посылает имена, начинающиеся с данной подстроки сразу этому редиректору. Для того чтобы редиректор мог взаимодействовать с драйвером mup.sys, редиректор должен зарегистрировать себя для драйвера mup.sys во время инициализации, и в дальнейшем отвечать на запросы о распознавании имени, выдаваемые драйвером mup.sys. Редиректор, который первым зарегистрировал себя для драйвера mup.sys, имеет больший приоритет. Этот приоритет определяет, какой редиректор будет обрабатывать запрос в том случае, если более одного редиректора распознает имя удаленного ресурса. После того, как какой-нибудь редиректор распознает имя удаленного ресурса, mup.sys подставляет в начало строки имени удаленного ресурса имя объекта-устройства редиректора и помещает эту строку в файловый объект, соответствующий этом ресурсу. С этого момента запросы к этому удаленному ресурсу идут к редиректору напрямую, и mup.sys больше не вовлекается.

1.2. Универсальные правила именования (UNC –имена)

    Имена UNC – это стандартный способ доступа к файлам и устройствам без назначения этим объектам буквы локального диска, спроецированного на удалённую файловую систему. Это позволяет приложениям не зависеть от имен дисков и прозрачно работать с сетью.

    UNC –имена имеют вид:

\\сервер\ресурс\путь.

Первая часть представляет имя севера, представленное в любом виде – NetBIOS-имя, имя домена и т.д., -.- обозначает локальный компьютер. Вторая часть – это имя общего ресурса, и третья – путь к требуемому файлу. Например путь к файлу – smp.mp3, находящемуся в папке C:\Myfiles\Music, представленной для общего доступа под именем Share на компьютере MyServer в UNC –имени имеет вид:

\\ MyServer\ Share\ smp.mp3.

    Обращение к файлам по сети с помощью UNC–имени скрывает от приложения детали формирования сетевого соединения. Все детали соответствующего соединения организуются конкретными компонентами самой операционной системы.

Интерфейс NetBIOS

До начала 90-х годов Network Basic Input/Output System (NetBIOS) стандртный интерфейс прикладного программирования API был самым популярным интерфейсом программирования API для PC. NetBIOS поддерживал связь как надежную, ориентированную на логические соединения, так и ненадежную, т.е данный интерфейс обуславливает программный интерфейс для сетевой связи, но не физический способ передачи данных по сети. В 1985 сформирован цельный протокол, интегрированный с данным интерфейсом - NetBEUI (NetBIOS Extended User Interface). Следует отметить, что только определенные протоколы реализуют интерфейс NetBIOS. Однако существуют реализации NetBIOS API и для других сетевых протоколов, хотя и не для всех (TCP/IP, например, его поддерживает), что делает интерфейс независимым от протоколов и позволяет корректно написанному приложению выполняться почти на любом компьютере, независимо от физической сети. Однако чтобы два приложения NetBIOS API могли связываться друг с другом по сети, на рабочих станциях должен быть хотя бы один общий транспортный протокол. При этом следует отметить, что NetBEUI – немаршрутизируемый протокол, и при наличии маршрутизатора в сети необходимо использовать маршрутизируемый протокол. Windows 2000 поддерживает NetBIOS для совместимости с унаследованными приложениями. Microsoft не рекомендует разработчикам приложений использовать NetBIOS.

Имена NetBIOS

NetBIOS использует правила именования, согласно которым компьютерам и сетевым службам назначаются 16-byte имена, называемые NetBIOS-именем, 16-й byte в NetBIOS–имени интерпретируется как модификатор, который указывает, является ли это имя уникальным или групповым. Уникальное NetBIOS может быть назначено только одному компьютеру или службе в сети, а групповое имя – нескольким. Адресуя сообщение на групповое имя, клиент может вести широковещательную рассылку.

Для поддержки взаимодействия с системами под управлением Windows NT 4 и потребительскими версиямиWindows, Windows 2000 автоматически определяет NetBIOS-имя для домена как первые 15 bytes Domain Name System (DNS) имени, назначенного домену администратором. Например, если доменное имя - mspress.microsoft.com, NetBIOS-имя домена должно быть mspress. Windows 2000 требует, чтобы во время установки администратор назначил каждому компьютеру NetBIOS name.

Номера LANA

Другая концепция, используемая в NetBIOS - LAN adapter (LANA) номера. LANA - номер присваивается каждому NetBIOS -совместимому протоколу, расположенному на более высоком уровне, чем сетевой адаптер. Например, если в компьютере есть два сетевых адаптера и TCP/IP и NetBEUI, доступных для этих адаптеров, будет назначено четыре LANA-номера. LANA-номера очень важны, т.к. NetBIOS приложения должны явно закреплять имена своих сервисов за каждым LANA, через которые они готовы принимать клиентские соединения. Если приложение ждет соединения с клиентом по определенному имени, клиенты получают доступ к приложению только через протоколы, для которых зарегистрировано это имя.

Когда компьютер загружается, он регистрирует свое имя на локальном севере Windows Internet Naming Server, который сообщает об ошибке, если другой компьютер использует то же имя. Сервер поддерживает список всех зарегистрированных NetBIOS names.

Сопоставление NetBIOS-имён и IP-адресов(TCP/IP protocol addresses) поддерживается сетевой службой Windows Internet Name Service (WINS). Если WINS не установлена, NetBIOS использует широковещательную рассылку в пределах Windows сети.

 

 

Приложение  1

Листинг программы – простой сервер почтового ящика

#include "stdafx.h"

#include <windows.h>

#include <conio.h>

#include <iostream.h>

#include <stdio.h>

#include <string.h>

int main(int argc, char* argv[])

{

    HANDLE Mailslot;

    char path[255];

    char buffer[255];

    DWORD NumberOfBytes;

    cin>>path;

    if ((Mailslot=CreateMailslot(path,0,MAILSLOT_WAIT_FOREVER,NULL))

==INVALID_HANDLE_VALUE)

    {

              printf("Unable to create mailslot!\n");

              GetLastError();

              return 0;

    }

    printf("Sozdan server s imenem %s!",path);

    getch();

    while(ReadFile(Mailslot,buffer,255,&NumberOfBytes,NULL)!=0)

    {

              printf("Prinyato:\n");

              buffer[NumberOfBytes]=0;

              printf("%s\n",buffer);

    }

    return 0;

}

Листинг программы – простой клиент почтового ящика

#include "stdafx.h"

#include <windows.h>

#include <stdio.h>

#include <conio.h>/*

#define ServerName "\\\\.\\mailslot\\myslot" */

void main(void)

{

    HANDLE Mailslot;

    DWORD BytesWritten;

    char chf[256];

    char chfb[256];

    char chfi[256];

//nst char* cs1 = "exit";const char* cs1 = "exit";        

const char* cs = "server\\mailslot\\name";

    puts(" puts resurs");

//  puts(cs1);

    puts(cs);

        printf("cmd>");

gets(chf);

sprintf(chfi,"\\\\%s",chf);

//  CHAR ServerName[256];

//int c = 1;

    {

              printf("Usage: client <server name>\n");

              return;

    }

    sprintf(ServerName, "\\\\%s\\mailslot\\myslot", argv[1]);*/

    if ((Mailslot = CreateFile(chfi, GENERIC_WRITE,

              FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,

              NULL)) == INVALID_HANDLE_VALUE)

    {

              printf("CreateFile failed with error %d\n", GetLastError());

printf("exit\n");

              _getch();

              return;

    }

puts("puts data ");

    printf("cmd> ");

gets(chfb);

if (WriteFile(Mailslot, chfb,strlen(chfb)+1,

   &BytesWritten, NULL) == 0)

    /*if (WriteFile(Mailslot, "This is a test", 14, &BytesWritten,

              NULL) == 0)*/

    {

              printf("WriteFile failed with error %d\n", GetLastError());

printf("exit\n");

              _getch();

              return;

    }

    printf("Wrote %d bytes\n", BytesWritten);

printf("exit\n");

              _getch();

    CloseHandle(Mailslot);

}

Листинг программы - сервер с отменой блокирующих запросов ввода-вывода

#include "stdafx.h"

#include <windows.h>

#include <stdio.h>

#include <conio.h>

 

BOOL StopProcessing;

int adf =1;

DWORD WINAPI ServeMailslot(LPVOID lpParameter);

void SendMessageToMailslot(void);

void main(void) {

    DWORD ThreadId;

    HANDLE MailslotThread;

int adf =1;

    StopProcessing = FALSE;

    MailslotThread = CreateThread(NULL, 0, ServeMailslot, NULL,

              0, &ThreadId);

    printf("Press a key to stop the server Myslot\n");

    _getch();

    StopProcessing = TRUE;

    SendMessageToMailslot();

    if (WaitForSingleObject(MailslotThread, INFINITE) == WAIT_FAILED)

    {

              printf("WaitForSingleObject failed with error %d\n",

                       GetLastError());

              return;

    }

}

DWORD WINAPI ServeMailslot(LPVOID lpParameter)

{

    char buffer[2048];

    DWORD NumberOfBytesRead;

    DWORD Ret;

    HANDLE Mailslot;

    if ((Mailslot = CreateMailslot("\\\\.\\Mailslot\\Myslot", 2048,

              MAILSLOT_WAIT_FOREVER, NULL)) == INVALID_HANDLE_VALUE)

    {

              printf("Failed to create a MailSlot %d\n", GetLastError());

              return 0;

    }

    while((Ret = ReadFile(Mailslot, buffer, 2048,

              &NumberOfBytesRead, NULL))!= 0)

    {

printf("Received %d bytes\n", NumberOfBytesRead);

buffer[NumberOfBytesRead]=0;

              printf("%s\n",buffer);

              if (StopProcessing)

    }

    CloseHandle(Mailslot);

    return 0;

}

void SendMessageToMailslot(void)

{

    HANDLE Mailslot;

    DWORD BytesWritten;

    if ((Mailslot = CreateFile("\\\\.\\Mailslot\\Myslot",

              GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING,

              FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE)

    {

              printf("CreateFile failed with error %d\n", GetLastError());

              return;

    }

    if (WriteFile(Mailslot, "STOP", 4, &BytesWritten, NULL) == 0)

    {

              printf("WriteFile failed with error %d\n", GetLastError());

              return;

    }

    CloseHandle(Mailslot);

}

 

Приложение 2

Листинг программы – простой клиент именованного канала

#include "stdafx.h"

#include <windows.h>

#include <stdio.h>

#include <conio.h>

#define PIPE_NAME "\\\\.\\Pipe\\Jim"

void main(void) {

    HANDLE PipeHandle;

    DWORD BytesWritten;

    DWORD BytesReaden;

char buffer[256];

    if (WaitNamedPipe(PIPE_NAME, NMPWAIT_WAIT_FOREVER) == 0)

    {

              printf("WaitNamedPipe failed with error %d\n",

                       GetLastError());

              _getch();

              return;

    }

    if ((PipeHandle = CreateFile(PIPE_NAME,

              GENERIC_READ | GENERIC_WRITE, 0,

              (LPSECURITY_ATTRIBUTES) NULL, OPEN_EXISTING,

              FILE_ATTRIBUTE_NORMAL,

              (HANDLE) NULL)) == INVALID_HANDLE_VALUE)

    {

              printf("CreateFile failed with error %d\n", GetLastError());

                       _getch();

              return;

    }

    if (WriteFile(PipeHandle, "This is a test", 14, &BytesWritten,

              NULL) == 0)

    {

              printf("WriteFile failed with error %d\n", GetLastError());

              CloseHandle(PipeHandle);

                       _getch();

              return;

    }

    printf("Wrote %d bytes", BytesWritten);

    printf("\n");

    if (ReadFile(PipeHandle, buffer, 256, &BytesReaden,

              NULL) == 0)

    {

              printf("ReadFile failed with error %d\n", GetLastError());

              CloseHandle(PipeHandle);

                       _getch();

              return;

    }

printf("Read %d bytes\n",BytesReaden);

buffer[BytesReaden]='\0';

//  printf("Wrote %d bytes", BytesWritten);

printf(buffer);

printf("\n");

    CloseHandle(PipeHandle);

              _getch();

}

 

Листинг программы – простой сервер именованного канала

#include "stdafx.h"

#include <windows.h>

#include <stdio.h>

#include <conio.h>

void main(void)

{

    HANDLE PipeHandle;

    DWORD BytesRead;

    CHAR buffer[256];

DWORD BytesWritten;

    if ((PipeHandle = CreateNamedPipe("\\\\.\\Pipe\\Jim",

              PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 1,

              0, 0, 1000, NULL)) == INVALID_HANDLE_VALUE)

    {

              printf("CreateNamedPipe failed with error %d\n",

                       GetLastError());

              return;

    }

 

    printf("Server is now running\n");

 

    if (ConnectNamedPipe(PipeHandle, NULL) == 0)

    {

              printf("ConnectNamedPipe failed with error %d\n",

                       GetLastError());

              CloseHandle(PipeHandle);

              _getch();

              return;

    }

 

    if (ReadFile(PipeHandle, buffer, sizeof(buffer),

              &BytesRead, NULL) <= 0)

    {

              printf("ReadFile failed with error %d\n", GetLastError());

 

              CloseHandle(PipeHandle);

              _getch();

              return;

    }

 

printf("Read %d bytes\n",BytesRead);

buffer[BytesRead]='\0';

//  printf("Wrote %d bytes", BytesRead);

    printf("\n");

 

printf(buffer);

printf("\n");

//  printf("%.*s\n", BytesRead, buffer);

    if (WriteFile(PipeHandle, "This is a snswer", 14, &BytesWritten,

              NULL) == 0)

    {

              printf("WriteFile failed with error %d\n", GetLastError());

              CloseHandle(PipeHandle);

                       _getch();

              return;

    }

printf("Wrote %d bytes", BytesWritten);

printf("\n");

    if (DisconnectNamedPipe(PipeHandle) == 0)

    {

              printf("DisconnectNamedPipe failed with error %d\n",

                       GetLastError());

              _getch();

              return;

    }

 

    CloseHandle(PipeHandle);

}

Листинг программы – усовершенствованный сервер именованного канала

#include <windows.h>

#include <stdio.h>

#include <conio.h>

#define NUM_PIPES 5

#define BUFFER_SIZE 256

 

void main(void)

{

    HANDLE PipeHandles[NUM_PIPES];

    DWORD BytesTransferred;

    CHAR Buffer[NUM_PIPES][BUFFER_SIZE];

    INT i;

    OVERLAPPED Ovlap[NUM_PIPES];

    HANDLE Event[NUM_PIPES];

 

    BOOL DataRead[NUM_PIPES];

    DWORD Ret;

    DWORD Pipe;

 

    for(i = 0; i < NUM_PIPES; i++)

    {

              if ((PipeHandles[i] = CreateNamedPipe("\\\\.\\PIPE\\jim",

                       PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,

                       PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, NUM_PIPES,

                       0, 0, 1000, NULL)) == INVALID_HANDLE_VALUE)

              {

                       printf("CreateNamedPipe for pipe %d failed "

                                 "with error %d\n", i, GetLastError());

                       _getch();

                       return;

              }

 

              if ((Event[i] = CreateEvent(NULL, TRUE, FALSE, NULL))

                       == NULL)

              {

                       printf("CreateEvent for pipe %d failed with error %d\n",

                           i, GetLastError());

                       continue;

              }

              DataRead[i] = FALSE;

 

              ZeroMemory(&Ovlap[i], sizeof(OVERLAPPED));

              Ovlap[i].hEvent = Event[i];

              // Listen for client connections using ConnectNamedPipe()

              if (ConnectNamedPipe(PipeHandles[i], &Ovlap[i]) == 0)

              {

                       if (GetLastError()!= ERROR_IO_PENDING)

                       {

                                 printf("ConnectNamedPipe for pipe %d failed with",

                                 " error %d\n", i, GetLastError());

                                 CloseHandle(PipeHandles[i]);

                                 _getch();

                                 return;

                       }

              }

    }

 

    printf("Server is now running\n");

 

 

    while(1)

    {

              if ((Ret = WaitForMultipleObjects(NUM_PIPES, Event,

                       FALSE, INFINITE)) == WAIT_FAILED)

              {

                       printf("WaitForMultipleObjects failed with error %d\n",

                                 GetLastError());

                       _getch();

                       return;

              }

              Pipe = Ret - WAIT_OBJECT_0;

              ResetEvent(Event[Pipe]);

              if (GetOverlappedResult(PipeHandles[Pipe], &Ovlap[Pipe],

                       &BytesTransferred, TRUE) == 0)

              {

                       printf("GetOverlapped result failed %d start over\n",

                                 GetLastError());

                       if (DisconnectNamedPipe(PipeHandles[Pipe]) == 0)

                       {

                           printf("DisconnectNamedPipe failed with error %d\n",

                                          GetLastError());

                                 _getch();

                                 return;

                       }

                       if (ConnectNamedPipe(PipeHandles[Pipe],

                                 &Ovlap[Pipe]) == 0)

                       {

                                 if (GetLastError()!= ERROR_IO_PENDING)

                                 {

                                          // Severe error on pipe. Close this

                                          // handle forever.

              printf("ConnectNamedPipe for pipe %d failed with""error %d\n", i, GetLastError());

                                          CloseHandle(PipeHandles[Pipe]);

                                 }

                       }

                       DataRead[Pipe] = FALSE;

              }

              else

              {

                       if (DataRead[Pipe] == FALSE)

                       {

                                 ZeroMemory(&Ovlap[Pipe], sizeof(OVERLAPPED));

                                 Ovlap[Pipe].hEvent = Event[Pipe];

                                 if (ReadFile(PipeHandles[Pipe], Buffer[Pipe],

                                          BUFFER_SIZE, NULL, &Ovlap[Pipe]) == 0)

                                 {

                                          if (GetLastError()!= ERROR_IO_PENDING)

                                          {

                                                   printf("ReadFile failed with error %d\n",

                                                   GetLastError());

                                          }

                                 }

Buffer[Pipe][BytesTransferred]='\0';

printf("%s\n",Buffer[Pipe]);

                                 DataRead[Pipe] = TRUE;

                       }

                       else

                       {

                                     

                                 printf("Received %d bytes, echo bytes back\n",

                                          BytesTransferred);

                  //  _getch();

              //            DataRead[Pipe] = TRUE;

                                 ZeroMemory(&Ovlap[Pipe], sizeof(OVERLAPPED));

                                 Ovlap[Pipe].hEvent = Event[Pipe];

                                 if (WriteFile(PipeHandles[Pipe], "Stop",

                                 BUFFER_SIZE, NULL, &Ovlap[Pipe]) == 0)

                                 {

                                          if (GetLastError()!= ERROR_IO_PENDING)

                                          {

                                                   printf("WriteFile failed with error %d\n",

                                                   GetLastError());

                                          }

                                 }

                                 DataRead[Pipe] = FALSE;

                              }

                   }

       }                     

}

 

Функционирование Winsock

    Для создания Winsock-приложения необходимо создать сокет, являющийся конечной точкой коммуникационного соединения. Сокет необходимо привязать к адресу конкретного локального компьютера. Поскольку сокет не зависит от протокола, можно выбрать любой протокол, установленный в системе, где работает сокет. Далее схемы работы различных типов сокетов отличаются. Winsock-сервер, ориентированный на логическое соединение, выполняет на сокете операцию listen, указывая число поддерживаемых соединений. Далее выполняется операция accept, которая при наличии ждущего запроса на соединение завершается немедленно, в противном случае после поступления запроса. После установления соединения accept возвращает новый сокет с серверной стороны. Сервер может выполнять операции передачи и приема данных.

   

Рис. 3. Коммуникационная связь между клиентом и сервером Winsock, ориентированными на логическое соединение

 

Клиенты подключаются к серверу с помощью вызова функции connect с указанием адреса удаленного компьютера. После установления соединения клиент может принимать и посылать сообщения через свой сокет. На рис. 3 представлена коммуникационная связь между клиентом и сервером, ориентированными на логическое соединение.

После привязки к адресу сервер, не требующий логических соединений, ничем не отличается от аналогичного клиента. Сервер посылает и получает сообщение через сокет, просто указывая требуемый адрес. Отправитель получает код ошибки в ходе следующей операции приема, если предыдущее сообщение не было доставлено.

Реализация Winsock

Прикладной интерфейс Windows Sockets состоит из DLL Ws2_32.dll, которая обеспечивает приложениям доступ к Winsock-функциям (рис. 4). Ws2_32.dll вызывает сервисы пространства имен и провайдеров сервисов транспорта для выполнения операций по разрешению имен и передачи сообщений. Библиотека Msafd.dll действует как провайдер сервисов транспорта. Msafd.dll использует библиотеки-помощники для Winsock (которые являются специфичными для протоколов), для взаимодействия с драйверами протоколов уровня ядра. Например, Wshtcpip.dll является помощником для протокола TCP/IP, а Wshnetbs.dll - для протокола NetBEUI. Библиотека Mswsock.dll реализует расширенную функциональность Microsoft Winsock.

Провайдер сетевого транспорта Msafddll использует сервисы драйвера файловой системы AFD.sys (Ancillary Function driver, AFD) для реализации функций сокетов. AFD является TDI-клиентом и исполняет сетевые операции с сокетами, такие как посылка и получение сообщений путем отправки запросов TDI IRP драйверам протоколов. AFD не запрограммирован для использования определенных драйверов протоколов, поэтому Msafd.dll информирует AFD об имени протокола, используемого определенным сокетом так, чтобы AFD мог открыть объект-устройство, представляющее этот протокол.

 

Рис. 4. Интерфейс WinSockets

Таблица 2

Сетевые протоколы, поддерживаемые Win32

Протокол Имя Тип сообщений Установление соединения Надежность Порядок пакетов Корректное завершение сеанса Поддержка широковещания Поддержка многоадресности QoS Max размер сообщений в байтах
1 2 3 4 5 6 7 8 9 10 11

IP

MSAFD TCP Поток да да да да нет нет нет без огр.
MSAFD UDP Сооб-щения нет нет нет нет да да нет 65467
RSVP TCP Поток да да да да нет нет да без огр.
RSVP UDP Сооб-щения нет нет нет нет да да да 65467

 

Продолжение табл. 2

1 2 3 4 5 6 7 8 9 10 11

IPX /

SPX

MSAFD nwln kipx [IPX] Сооб-щения нет нет нет нет да да нет 576
MSAFD nwin kspx [SPX] Сооб-щения да да да нет нет нет нет без огр.
MSAFD nwin kspx [SPX] псевдо поток Сооб-щения да да да нет нет нет нет без огр.
MSAFD nwin kspx [SPXII] Сооб-щения да да да да нет нет нет без огр.
MSAFD nwin kspx [SPXII] псевдо поток Сооб-щения да да да да нет нет нет без огр.

NetBIOS

Sequential Packets Последо-ватель-ность пакетов Сооб-щения да да да нет нет нет нет 65535
Datagrams дейта-граммы Сооб-щения нет нет нет нет да* нет нет 65535

ATM

MSAFD ATM AAL5 Поток да нет да нет нет да да без огр.
NATIVE ATM AAL5 Сооб-щения да нет да нет нет да да без огр.
Infrared Sockets MSAFD IrDA Поток да да да да нет нет нет без огр.

* - поддерживает отправку дейтаграмм как уникальным, так и групповым клиентам, общее широковещание не поддерживается.

Основные функции WinSock

Структура WSADATA

В структуре WSADATA содержится информация о реализации Windows Sockets.

typedef struct WSAData {

WORD wVersion;

WORD wHighVersion;

char szDescription[WSADESCRIPTION_LEN+1];

char szSystemStatus[WSASYS_STATUS_LEN+1];

unsigned short iMaxSockets;

unsigned short iMaxUdpDg;

char FAR* lpVendorInfo;

} WSADATA,

 *LPWSADATA;

 

 

Параметры:

wVersion

Указывается версия Windows Sockets спецификации Ws2_32.dll. Старший байт определяет младшее число версии; байт младшего разряда определяет главное число версии.

wHighVersion

Указывается самая высокая версия Windows Sockets, спецификации Ws2_32.dll, которая может поддерживаться. Старший байт определяет младшее число версии; байт младшего разряда определяет главное число версии.

Это тоже самое значение параметра wVersion, которое требуется в параметре wVersionRequested, который передают в функции WSAStartup - самая высокая версия спецификации Windows Sockets, которую Ws2_32.dll может поддерживать.

szDescription terminated

NULL - законченный ASCII строки, в который Ws2_32.dll копирует описание выполнения Windows Sockets. Текст (до 256 символов в длине) может содержать любые символы, кроме символов форматирования и контроля. Наиболее вероятное использование - это показ в статусе сообщения.

szSystemStatus

NULL - законченный ASCII строки, в который Ws2_32.dll копирует соответствующий статус или информацию о конфигурации. В Ws2_32.dll следует использовать этот параметр, только если информация может быть полезной для пользователей. Этот параметр не следует рассматривать как расширение параметра szDescription.

iMaxSockets

Максимальное число сокетов, которые могут быть открыты. Этот член должен игнорироваться для версии 2 Windows Sockets и более поздних.

Параметр IMaxSockets сохранен для совместимости со спецификацией 1.1 Windows Sockets, но не должен использоваться при разработке новых приложений.

iMaxUdpDg

Максимальный размер дейтаграммного сообщения. Этот параметр игнорируется для Windows Sockets версии 2 или более поздней.

Параметр iMaxUdpDg сохраняется для совместимости с Windows Sockets спецификации 1,1, но его не следует использовать при разработке новых приложений.

lpVendorInfo

Указатель, зависящий от фирмы изготовителя. Этот параметр следует игнорировать для Windows Sockets версии 2 или более поздней.

Параметр lpVendorInfo сохраняется для совместимости с Windows Sockets спецификации 1,1.

Функция WSAStartup

int WSAStartup (WORD wVersionRequested, LPWSADATA lpWSAData);

В параметре wVersionRequested указывается версия интерфейса Windows Sockets, необходимая для работы приложения. Старший байт параметра указывает младший номер версии (minor version), младший байт - старший номер версии (major version).

Перед вызовом функции WSAStartup параметр lpWSAData должен содержать указатель на структуру типа WSADATA, в которую будут записаны сведения о конкретной реализации интерфейса Windows Sockets.

В случае успеха функция WSAStartup возвращает нулевое значение. Если происходит ошибка, возвращается одно из следующих значений:

Значение                                                          Описание

WSASYSNOTREADY           Сетевое программное обеспечение не готово для работы

WSAVERNOTSUPPORTED  Функция не поддерживается данной реализацией интерфейса Windows Sockets

WSAEINVAL                        Библиотека DLL, обеспечивающая ин-терфейсe Windows Sockets, не соответствует версии, указанной приложением в параметре wVersionRequested

Функция WSACleanup

int WSACleanup (void);

Эта функция может возвратить нулевое значение при успехе или значение SOCKET_ERROR в случае ошибки.

Для получения кода ошибки можно воспользоваться функцией WSAGetLastError.

Функция socket

Эта функция используется для создания сокета. Прототип:

SOCKET socket (int af, int type, int protocol) 

Первый параметр определяет семейство адресов протоколов. Мы будем рассматривать только сокеты AF_INET для TCP\IP.

Второй параметр определяет тип канала связи с сокетом, который должен быть использован. Существует несколько типов каналов связи с сокетом, доступных при рассматриваемом взаимодействии:

1. SOCK_STREAM - при этом типе связи поступающим в канал байтам информации гарантируется "доставка" в порядке их поступления; пока непрерывный поток байтов не прекратится, никакие другие данные приниматься каналом не будут (аналогом такой связи является pipe-механизм);

2. SOCK_DGRAM - этот тип связи используется для посылки отдельных пакетов информации, называемых datagrams; при этом не гарантируется, что пакеты будут доставлены на место назначения в порядке поступления, а в действительности не гарантируется, что они все вообще будут доставлены (пример такого типа связи - обычная почтовая связь).

Третий параметр позволяет программисту выбрать нужный протокол для канала связи. Если этот параметр равен нулю, ОС выберет нужный протокол автоматически.

Функция socket возвращает описатель сокета (который можно использовать, например, в функциях read и write аналогично файловому дескриптору). Если же сокет по каким-либо причинам не был создан (например, очень много открытых файлов), возвращается


Поделиться с друзьями:

Своеобразие русской архитектуры: Основной материал – дерево – быстрота постройки, но недолговечность и необходимость деления...

Папиллярные узоры пальцев рук - маркер спортивных способностей: дерматоглифические признаки формируются на 3-5 месяце беременности, не изменяются в течение жизни...

Семя – орган полового размножения и расселения растений: наружи у семян имеется плотный покров – кожура...

Автоматическое растормаживание колес: Тормозные устройства колес предназначены для уменьше­ния длины пробега и улучшения маневрирования ВС при...



© cyberpedia.su 2017-2024 - Не является автором материалов. Исключительное право сохранено за автором текста.
Если вы не хотите, чтобы данный материал был у нас на сайте, перейдите по ссылке: Нарушение авторских прав. Мы поможем в написании вашей работы!

0.36 с.