Реферат по предмету "Программирование"


Программируем под IIS на Visual C++

Программируем под IIS на Visual C++

Одной из распространенных задач администрирования
web-сайтов является анализ log-файлов и сбор данных из них. Поговорим об этой
задаче на примере IIS 5.0 (Internet Information Service). В связи с тем, что
данный HTTP сервер поддерживает несколько форматов таких файлов (формат W3C,
формат NCSA, а также свой формат IIS), анализ log-файлов превращается в
довольно трудоемкую задачу. Кроме того для формата W3C список полей может
конфигурироваться, что задачу не облегчает.

Но к счастью вместе с IIS 5.0 в составе прочих
компонентов, поставляется компонент MSWC.IISLog, который предназначен для
получения данных из log-файлов и предоставляет для этой цели интерфейс
ILogScripting. Находится он в файле %windir%system32inetsrvlogscrpt.dll. С
помощью этого интерфейса можно читать данные из log-файла, записывать
прочтенные данные в другой файл.

Перед тем как начать работу с какими-либо log-файлом,
его нужно открыть. Для этого служит метод OpenLogFile:

HRESULT
OpenLogFile( [in] BSTR szLogFileName,

                  [in] IOMode Mode,

                  [in] BSTR szServiceName,

                  [in] long iServiceInstance,

                  [in] BSTR szOutputLogFileFormat),


где в параметре szLogFileName задается полный путь к
файлу; параметр Mode может принимать следующие значения:

ForReading - файл будет открыт для чтения

ForWriting - файл будет открыт для записи;

в параметре szServiceName задается название службы,
которой был создан данный файл (например "W3SVC"); парметр
iServiceInstance указывает номер экземпляра сервера данной службы (напр. 1); в
параметре szOutputLogFileFormat задается название формата, в котором будут
читаться или записываться данные (например "W3C"). Если метод
выполнился успешно то возвращается 0.

Для чтения данных из файла служит метод ReadLogRecord:

HRESULT ReadLogRecord(),

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




get_DateTime





Отображение даты и времени
по Гринвичу (GMT)







get_ServiceName





Отображение имени службы







get_ServerName





Отображение имени сервера







get_ClientIP





Отображение имени узла
клиента







 get_UserName





 Отображение имени пользователя







 get_ServerIP





 Отображение IP-адреса сервера







 get_Method





 Отображение типа операции







 get_URIStem





 Отображение адреса URL







 get_URIQuery





 Отображение всех параметров, передаваемых с
запросом







get_TimeTaken





Отображение общего времени
обработки







 get_BytesSent





 Отображение числа переданных байтов







 get_BytesReceived





 Отображение числа полученных байтов







 get_Win32Status





 Отображение кода состояния Win32







 get_ProtocolStatus





 Отображение состояния протокола







 get_ServerPort





 Отображение номера порта







 get_ProtocolVersion





Отображение строки версии







 get_UserAgent





 Отображение строки агента пользователя







 get_Cookie





 Отображение имени Cookie клиента







 get_Referer





 Отображение страницы источника ссылки







get_CustomFields





Отображение массива
специальных заголовков






  

Все эти методы имеют один формат: HRESULT get_MethodName(VARIANT *pValue). В параметре pValue будет возвращено интересующее нас
значение. Если значение запрашиваемого параметра равно "-", то тип
pValue будет VT_EMPTY. Если же по каким-то причинам параметр не будет найден в
log-файле (напр. параметр отключен, или текущая строка - незначащая), то тип
pValue будет VT_NULL.

Для того, чтобы мы сильно не увлеклись существует
метод AtEndOfLog, который подобно привычному feof возвращает (или не возвращает
:)) признак достижения конца файла и выглядит приблизительно так:

HRESULT
AtEndOfLog([out, retval] VARIANT_BOOL* pfEndOfRead)

В параметре pfEndOfRead, собственно, и возвращается
интересующий нас признак, что позволяет нам все таки когда-нибудь завершить
обработку log-файла.

Помимо всего этого имеется еще метод WriteLogRecord,
который позволяет записывать данные, полученные из одного log-файла в другой.
Формат его следующий:

HRESULT WriteLogRecord([in] ILogScripting*
pILogScripting),

где

pILogScripting - это указатель на экземпляр
ILogScripting, в котором содержатся прочитанные данные. Этот метод похож на
ReadLogRecord тем, что записывает в файл одну строку (напомню, что
ReadLogRecord читает одну строку).

Для закрытия открытых файлов служит метод
CloseLogFiles:

HRESULT
CloseLogFiles([in] IOMode Mode),

в котором параметр Mode может принимать следующие
значения:

ForReading - будут закрыты файлы, открытые для чтения

ForWriting - будут закрыты файлы, открытые для записи

AllOpenFiles - будут закрыты все открытые файлы

Чтобы доступиться к компоненту MSWC.IISLog из C++ надо
иметь .h файл, описывающий интерфейс ILogScripting. Сделать его нам поможет
утилита OLEViewer, которая входит в состав Visual Studio. В меню
"File" этой утилиты выберем пункт "View TypeLib" и укажем
файл logscrpt.dll (естественно полный путь к нему). В новом окне откроется
библиотека типов нашего объекта, которую мы сохраним в качестве .idl файла.

Для этого в меню "File" выберем пункт
"Save as", укажем тип файла "idl", и сохраним его в некое
место (например туда, где находится проект), к примеру, назвав его
"logscrpt.idl". Все бы хорошо, да только в новоиспеченном файле
придется сделать косметические изменения. Во-первых в самое начало файла надо
вставить следующие строчки:

cpp_quote("DEFINE_GUID(CLSID_LogScripting,
0x26B9ED02, 0xA3D8, 0x11D1, 0x8B, 0x9C, 0x08, 0x00, 0x09, 0xDC, 0xC2,
0xFA);")

cpp_quote("DEFINE_GUID(IID_ILogScripting,
0x26B9ECFF, 0xA3D8, 0x11D1, 0x8B, 0x9C, 0x08, 0x00, 0x09, 0xDC, 0xC2,
0xFA);")

Во-вторых строчки

typedef enum {

  ForReading =
1,

  ForWriting =
2,

  AllOpenFiles =
32

} IOMode;

надо перенести так, чтобы они находились до
определения ILogScripting интерфейса.

Теперь осталось только сгенерировать файл logscrpt.h с
помощью команды midl.exe logscrpt.idl /h logscrpt.h (проверьте путь к
компилятору midl).

В заключение приведу пример программы работы с
интерфейсом, которая получает в качестве параметров командной строки путь к
log-файлу, название службы, название формата файла, номер экземпляра сервера и
выдает на экран список всех URL адресов, к которым были зафиксированы обращения
в этом файле. Вот пример вызова этой программы:

logging.exe d:logsw3svc2ex01060515.log W3SVC W3C 2

#include

#include

#include

#include

#include
"logscrpt.h"

#define
SOME_ERROR(lpszErrorText, nErrorNum)

printf("%s: %X

",
lpszErrorText, nErrorNum);

throw nErrorNum;

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

{

HRESULT hres;

VARIANT vParam;

short nEndOfFile;

_bstr_t bstrLogFile;

_bstr_t
bstrServiceName;

_bstr_t
bstrLogFormat;

long
nServerInstance;

_bstr_t bstrUriStem;

// проверка наличия параметров

if  (argc

{

printf("Usage:
%s LogFileName ServiceNa

         me LogFormatName ServerInstance

", argv[0]);

return 0;

}

// получаем параметры из коммандной строки

try {

bstrLogFile =
argv[1];

bstrServiceName =
argv[2];

bstrLogFormat =
argv[3];

if  (!(nServerInstance = atol(argv[4])))

// экземпляр сервера не может быть 0

nServerInstance =
1;

}

catch (...) {

printf("Something
wrong in parameters!

");

return 0;

}

// это будет ссылка на интерфейс

ILogScripting
*pLogScripting = NULL;

try {

// инициализируем COM

if  (!SUCCEEDED(hres = CoInitialize(NULL)))

{

SOME_ERROR("CoInitialize
error", hres);

}

// теперь создадим экзепляр интерфейса

if  (!SUCCEEDED(hres =
CoCreateInstance(CLSID_LogScripting,

NULL, CLSCTX_ALL,
IID_ILogScripting,

(void
**)&pLogScripting)))

{

SOME_ERROR("CoCreateInstance
error", hres);

}

// открываем log-файл bstrLogFile для чтения,
указывая, что этот

// файл относится к первому экземляру сервера службы
W3SVC, а //

// формат у него W3C

if  (!SUCCEEDED(hres =

pLogScripting-OpenLogFile(BSTR(bstrLogFile),
ForReading,

BSTR(bstrServiceName),
1, BSTR(bstrLogFormat))))

{

SOME_ERROR("OpenLogFile
error", hres);

}

// теперь можно приступить к анализу содержимого файла

for ( ;; ) {

// проверим на достижение конца файла

if  (!SUCCEEDED(hres =

             
pLogScripting-AtEndOfLog(&nEndOfFile)))

{

 SOME_ERROR("AtEndOfLog error",
hres);

}

if  (nEndOfFile)

 // счастливо выходим

 break;

// читаем следующую запись файла

if  (!SUCCEEDED(hres =
pLogScripting-ReadLogRecord()))

{

 SOME_ERROR("ReadLogRecord error",
hres);

}

// получаем из нее параметр адрес URL

if  (!SUCCEEDED(hres =
pLogScripting-get_URIStem(&vParam)))

{

 SOME_ERROR("ReadLogRecord error",
hres);

}

if  (vParam.vt == VT_BSTR)

{

 // если
параметр не пуст распечатаем его на экране

 bstrUriStem =
vParam.bstrVal;

 printf("Uri-stem: %s

",
LPSTR(bstrUriStem));

}

}

// закрываем файл

if  (!SUCCEEDED(hres = pLogScripting-CloseLogFiles(ForReading)))

{

SOME_ERROR("CloseLogFiles
error", hres);

}

}

catch (...) {}

// последние действия по деинициализации

if 
(pLogScripting != NULL)

pLogScripting-Release();

CoUninitialize();

return hres;

}

Dima Mukalov

Список литературы

Для подготовки данной работы были использованы
материалы с сайта http://www.realcoding.net/

Работа с WinSocket в Visual C++

Socket (гнездо, разъем) - абстрактное программное
понятие, используемое для обозначения в прикладной программе конечной точки
канала связи с коммуникационной средой, образованной вычислительной сетью. При
использовании протоколов TCP/IP можно говорить, что socket является средством
подключения прикладной программы к порту (см. выше) локального узла сети.

Socket-интерфейс представляет собой просто набор
системных вызовов и/или библиотечных функций языка программирования СИ,
разделенных на четыре группы:

Ниже рассматривается подмножество функций
socket-интерфейса, достаточное для написания сетевых приложений, реализующих
модель "клиент-сервер" в режиме с установлением соединения.

1. Функции локального управления

Функции локального управления используются, главным
образом, для выполнения подготовительных действий, необходимых для организации
взаимодействия двух программ-партнеров. Функции носят такое название, поскольку
их выполнение носит локальный для программы характер.

1.1 Создание socket'а

Создание socket'а осуществляется следующим системным
вызовом #include int socket (domain, type, protocol) int
domain; int type; int protocol;

Аргумент domain задает используемый для взаимодействия
набор протоколов (вид коммуникационной области), для стека протоколов TCP/IP он
должен иметь символьное значение AF_INET (определено в sys/socket.h).

Аргумент type задает режим взаимодействия:

SOCK_STREAM - с установлением соединения;

SOCK_DGRAM - без установления соединения.

Аргумент protocolзадает конкретный протокол
транспортного уровня (из нескольких возможных в стеке протоколов). Если этот
аргумент задан равным 0, то будет использован протокол "по умолчанию"
(TCP для SOCK_STREAM и UDP для SOCK_DGRAM при использовании комплекта
протоколов TCP/IP).

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

При обнаружении ошибки в ходе своей работы функция
возвращает число "-1".

1.2. Связывание socket'а

Для подключения socket'а к коммуникационной среде,
образованной вычислительной сетью, необходимо выполнить системный вызов bind,
определяющий в принятом для сети формате локальный адрес канала связи со
средой. В сетях TCP/IP socket связывается с локальным портом. Системный вызов
bind имеет следующий синтаксис:

#include
    

#include

#include
  

int bind (s, addr,
addrlen)

int s;   

struct sockaddr
*addr;

int addrlen;

Аргумент s задает дескриптор связываемого socket'а.

Аргумент addr в общем случае должен указывать на
структуру данных, содержащую локальный адрес, приписываемый socket'у. Для сетей
TCP/IP такой структурой является sockaddr_in.

Аргумент addrlen задает размер (в байтах) структуры
данных, указываемой аргументом addr.

Структура sockaddr_in используется несколькими
системными вызовами и функциями socket-интерфейса и определена в include-файле
in.h следующим образом:

struct sockaddr_in
{

short sin_family;

u_short sin_port;

struct in_addr
sin_addr;

char sin_zero[8];

};

Поле sin_family определяет используемый формат адреса
(набор протоколов), в нашем случае (для TCP/IP) оно должно иметь значение
AF_INET.

Поле sin_addr содержит адрес (номер) узла сети.

Поле sin_port содержит номер порта на узле сети.

Поле sin_zero не используется.

Определение структуры in_addr (из того же
include-файла) таково:

struct in_addr {

union {        

u_long S_addr;             /*         

другие (не интересующие нас)           

члены объединения             */           

} S_un;

#define s_addr
S_un.S_addr

};

Структура sockaddr_in должна быть полностью заполнена
перед выдачей системного вызова bind. При этом, если поле sin_addr.s_addr имеет
значение INADDR_ANY, то системный вызов будет привязывать к socket'у номер
(адрес) локального узла сети.

В случае успеха bind возвращает 0, в противном случае
- "-1".

2. Функции установления связи

Для установления связи "клиент-сервер"
используются системные вызовы listen и accept (на стороне сервера), а также
connect (на стороне клиента). Для заполнения полей структуры socaddr_in,
используемой в вызове connect, обычно используется библиотечная функция
gethostbyname, транслирующая символическое имя узла сети в его номер (адрес).

2.1. Ожидание установления связи

Системный вызов listen выражает желание выдавшей его
программы-сервера ожидать запросы к ней от программ-клиентов и имеет следующий
вид:

#include


int listen (s, n)

int s;

int n;

Аргумент s задает дескриптор socket'а, через который
программа будет ожидать запросы к ней от клиентов. Socket должен быть
предварительно создан системным вызовом socketи обеспечен адресом с помощью
системного вызова bind.

Аргумент n определяет максимальную длину очереди
входящих запросов на установление связи. Если какой-либо клиент выдаст запрос
на установление связи при полной очереди, то этот запрос будет отвергнут.

Признаком удачного завершения системного вызова listen
служит нулевой код возврата.

2.2. Запрос на установление соединения

Для обращения программы-клиента к серверу с запросом
на установление логической соединения используется системный вызов connect,
имеющий следующий вид #include #include
#include int connect (s, addr,
addrlen) int s; struct sockaddr_in *addr; int addrlen;

Аргумент s задает дескриптор socket'а, через который
программа обращается к серверу с запросом на соединение. Socket должен быть
предварительно создан системным вызовом socketи обеспечен адресом с помощью
системного вызова bind.

Аргумент addr должен указывать на структуру данных,
содержащую адрес, приписанный socket'у программы-сервера, к которой делается
запрос на соединение. Для сетей TCP/IP такой структурой является sockaddr_in.
Для формирования значений полей структуры sockaddr_in удобно использовать
функцию gethostbyname.

Аргумент addrlen задает размер (в байтах) структуры
данных, указываемой аргументом addr.

Для того, чтобы запрос на соединение был успешным,
необходимо, по крайней мере, чтобы программа-сервер выполнила к этому моменту
системный вызов listen для socket'а с указанным адресом.

При успешном выполнении запроса системный вызов connect
возвращает 0, в противном случае - "-1" (устанавливая код причины
неуспеха в глобальной переменной errno).

Примечание. Если к моменту выполнения connect
используемый им socket не был привязан к адресу посредством bind ,то такая
привязка будет выполнена автоматически.

Примечание. В режиме взаимодействия без установления
соединения необходимости в выполнении системного вызова connect нет. Однако,
его выполнение в таком режиме не является ошибкой - просто меняется смысл
выполняемых при этом действий: устанавливается адрес "по умолчанию"
для всех последующих посылок дейтаграмм.

2.3. Прием запроса на установление связи

Для приема запросов от программ-клиентов на
установление связи в программах-серверах используется системный вызов accept,
имеющий следующий вид:

#include
    

#include
    

int accept (s,
addr, p_addrlen)

int s;       

struct sockaddr_in
*addr;

int *p_addrlen;

Аргумент s задает дескриптор socket'а, через который
программа-сервер получила запрос на соединение (посредством системного запроса
listen ).

Аргумент addr должен указывать на область памяти,
размер которой позволял бы разместить в ней структуру данных, содержащую адрес
socket'а программы-клиента, сделавшей запрос на соединение. Никакой
инициализации этой области не требуется.

Аргумент p_addrlen должен указывать на область памяти
в виде целого числа, задающего размер (в байтах) области памяти, указываемой
аргументом addr.

Системный вызов accept извлекает из очереди,
организованной системным вызовом listen, первый запрос на соединение и
возвращает дескриптор нового (автоматически созданного) socket'а с теми же
свойствами, что и socket, задаваемый аргументом s. Этот новый дескриптор
необходимо использовать во всех последующих операциях обмена данными.

Кроме того после удачного завершения accept:

область памяти, указываемая аргументом addr, будет
содержать структуру данных (для сетей TCP/IP это sockaddr_in), описывающую
адрес socket'а программы-клиента, через который она сделала свой запрос на
соединение;

целое число, на которое указывает аргумент p_addrlen,
будет равно размеру этой структуры данных.

Если очередь запросов на момент выполнения accept
пуста, то программа переходит в состояние ожидания поступления запросов от
клиентов на неопределенное время (хотя такое поведение accept можно и
изменить).

Признаком неудачного завершения accept служит
отрицательное возвращенное значение (дескриптор socket'а отрицательным быть не
может).

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

2.4. Формирование адреса узла сети

Для получения адреса узла сети TCP/IP по его
символическому имени используется библиотечная функция

#include
    

#include
    

struct hostent
*gethostbyname (name)       

char *name;

Аргумент name задает адрес последовательности литер,
образующих символическое имя узла сети.

При успешном завершении функция возвращает указатель
на структуру hostent, определенную в include-файле netdb.h и имеющую следующий
вид struct hostent { char *h_name; char **h_aliases; int h_addrtype; int
h_lenght; char *h_addr; };

Поле h_name указывает на официальное (основное) имя
узла.

Поле h_aliases указывает на список дополнительных имен
узла (синонимов), если они есть.

Поле h_addrtype содержит идентификатор используемого
набора протоколов, для сетей TCP/IP это поле будет иметь значение AF_INET.

Поле h_lenght содержит длину адреса узла.

Поле h_addr указывает на область памяти, содержащую
адрес узла в том виде, в котором его используют системные вызовы и функции
socket-интерфейса.

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

3. Функции обмена данными

В режиме с установлением логического соединения после
удачного выполнения пары взаимосвязанных системных вызовов connect (в клиенте)
и accept (в сервере) становится возможным обмен данными.

Этот обмен может быть реализован обычными системными
вызовами read и write, используемыми для работы с файлами (при этом вместо
дескрипторов файлов в них задаются дескрипторы socket'ов).

Кроме того могут быть дополнительно использованы
системные вызовы send и recv, ориентированные специально на работу с
socket'ами.

Примечание. Для обмена данными в режиме без
установления логического соединения используются, как правило, системные вызовы
sendtoи recvfrom. Sendto позволяет специфицировать вместе с передаваемыми
данными (составляющими дейтаграмму) адрес их получателя. Recvfrom одновременно
с доставкой данных получателю информирует его и об адресе отправителя.

3.1. Посылка данных

Для посылки данных партнеру по сетевому взаимодействию
используется системный вызов send, имеющий следующий вид

#include
    

#include


int send (s, buf,
len, flags)

int s;       

char *buf;

int len;

int flags;

Аргумент s задает дескриптор socket'а, через который
посылаются данные.

Аргумент buf указывает на область памяти, содержащую
передаваемые данные.

Аргумент len задает длину (в байтах) передаваемых
данных.

Аргумент flags модифицирует исполнение системного
вызова send. При нулевом значении этого аргумента вызов send полностью
аналогичен системному вызову write.

При успешном завершении send возвращает количество
переданных из области, указанной аргументом buf, байт данных. Если канал
данных, определяемый дескриптором s, оказывается "переполненным", то
send переводит программу в состояние ожидания до момента его освобождения.

3.2. Получение данных

Для получения данных от партнера по сетевому
взаимодействию используется системный вызов recv, имеющий следующий вид

#include
   

#include
    

int recv (s, buf,
len, flags)

int s;

char *buf;

int len;

int flags;

Аргумент s задает дескриптор socket'а, через который
принимаются данные.

Аргумент buf указывает на область памяти,
предназначенную для размещения принимаемых данных.

Аргумент len задает длину (в байтах) этой области.

Аргумент flags модифицирует исполнение системного
вызова recv. При нулевом значении этого аргумента вызов recv полностью
аналогичен системному вызову read.

При успешном завершении recv возвращает количество
принятых в область, указанную аргументом buf, байт данных. Если канал данных,
определяемый дескриптором s, оказывается "пустым", то recv переводит
программу в состояние ожидания до момента появления в нем данных.

4. Функции закрытия связи

Для закрытия связи с партнером по сетевому
взаимодействию используются системные вызовы close и shutdown.

4.1. Системный вызов close

Для закрытия ранее созданного socket'а используется
обычный системный вызов close, применяемый в ОС UNIX для закрытия ранее
открытых файлов и имеющий следующий вид

int close (s)

int s;

Аргумент s задает дескриптор ранее созданного
socket'а.

Однако в режиме с установлением логического соединения
(обеспечивающем, как правило, надежную доставку данных) внутрисистемные
механизмы обмена будут пытаться передать/принять данные, оставшиеся в канале
передачи на момент закрытия socket'а. На это может потребоваться значительный
интервал времени, неприемлемый для некоторых приложений. В такой ситуации
необходимо использовать описываемый далее системный вызов shutdown.

4.2. Сброс буферизованных данных

Для "экстренного" закрытия связи с партнером
(путем "сброса" еще не переданных данных) используется системный
вызов shutdown, выполняемый перед close и имеющий следующий вид

int shutdown (s,
how)

int s;

int how;

Аргумент s задает дескриптор ранее созданного
socket'а.

Аргумент how задает действия, выполняемые при очистке
системных буферов socket'а:

0 - сбросить и далее не принимать данные для чтения из
socket'а;

1 - сбросить и далее не отправлять данные для посылки
через socket;

2 - сбросить все данные, передаваемые через socket в
любом направлении.

5. Пример использования socket-интерфейса

В данном разделе рассматривается использование
socket-интерфейса в режиме взаимодействия с установлением логического
соединения на очень простом примере взаимодействия двух программ (сервера и
клиента), функционирующих на разных узлах сети TCP/IP.

Содержательная часть программ примитивна:

сервер, приняв запрос на соединение, передает клиенту
вопрос "Who are you?";

клиент, получив вопрос, выводит его в стандартный
вывод и направляет серверу ответ "I am your client" и завершает на
этом свою работу;

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

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

5.1. Программа-сервер

Текст программы-сервера на языке программирования СИ
выглядит следующим образом

1  #include  

2  #include  

3  #include  

4  #include  

5  #include   

6  #define SRV_PORT 1234 

7  #define BUF_SIZE 64 

8  #define TXT_QUEST "Who are
you?n"  

9  main () {

10    int s, s_new;

11    int from_len;

12    char buf[BUF_SIZE];

13    struct sockaddr_in sin, from_sin; 

14    s = socket (AF_INET, SOCK_STREAM, 0);

15    memset ((char *)&sin, '', sizeof(sin));


16    sin.sin_family = AF_INET;

17    sin.sin_addr.s_addr = INADDR_ANY;

18    sin.sin_port = SRV_PORT;

19    bind (s, (struct sockaddr *)&sin,
sizeof(sin));

20    listen (s, 3);

21    while (1) {

22      from_len = sizeof(from_sin);

23      s_new = accept (s, &from_sin,
&from_len);

24      write (s_new, TXT_QUEST,
sizeof(TXT_QUEST));

25      from_len = read (s_new, buf, BUF_SIZE);

26      write (1, buf, from_len);

27      shutdown (s_new, 0);

28      close
(s_new);

29      };

30    }

Строки 1...5 описывают включаемые файлы, содержащие
определения для всех необходимых структур данных и символических констант.

Строка 6 приписывает целочисленной константе 1234
символическое имя SRV_PORT. В дальнейшем эта константа будет использована в
качестве номера порта сервера. Значение этой константы должно быть известно и
программе-клиенту.

Строка 7 приписывает целочисленной константе 64
символическое имя BUF_SIZE. Эта константа будет определять размер буфера,
используемого для размещения принимаемых от клиента данных.

Строка 8 приписывает последовательности символов,
составляющих текст вопроса клиенту, символическое имя TXT_QUEST. Последним
символом в последовательности является символ перехода на новую строку 'n'.
Сделано это для упрощения вывода текста вопроса на стороне клиента.

В строке 14 создается (открывается) socket для
организации режима взаимодействия с установлением логического соединения
(SOCK_STREAM) в сети TCP/IP (AF_INET), при выборе протокола транспортного
уровня используется протокол "по умолчанию" (0).

В строках 15...18 сначала обнуляется структура данных
sin, а затем заполняются ее отдельные поля. Использование константы INADDR_ANY
упрощает текст программы, избавляя от необходимости использовать функцию
gethostbyname для получения адреса локального узла, на котором запускается
сервер.

Строка 19 посредством системного вызова bind
привязывает socket, задаваемый дескриптором s, к порту с номером SRV_PORT на
локальном узле. Bind завершится успешно при условии, что в момент его
выполнения на том же узле уже не функционирует программа, использующая этот
номер порта.

Строка 20 посредством системного вызова listen
организует очередь на три входящих к серверу запроса на соединение.

Строка 21 служит заголовком бесконечного цикла
обслуживания запросов от клиентов.

На строке 23, содержащей системный вызов accept,
выполнение программы приостанавливается на неопределенное время, если очередь
запросов к серверу на установление связи оказывается пуста. При появлении
такого запроса accept успешно завершается, возвращая в переменной s_new
дескриптор socket'а для обмена информацией с клиентом.

В строке 24 сервер с помощью системного вызова write
отправляет клиенту вопрос.

В строке 25 с помощью системного вызова read читается
ответ клиента.

В строке 26 ответ направляется в стандартный вывод,
имеющий дескриптор файла номер 1. Так как строка ответа содержит в себе символ
перехода на новую строку, то текст ответа будет размещен на отдельной строке
дисплея.

Строка 27 содержит системный вывод shutdown,
обеспечивающий очистку системных буферов socket'а, содержащих данные для чтения
("лишние" данные могут там оказаться в результате неверной работы
клиента).

В строке 28 закрывается (удаляется) socket,
использованный для обмена данными с очередным клиентом.

Примечание. Данная программа (как и большинство
реальных программ-серверов) самостоятельно своей работы не завершает, находясь
в бесконечном цикле обработки запросов клиентов. Ее выполнение может быть
прервано только извне путем посылки ей сигналов (прерываний) завершения.
Правильно разработанная программа-сервер должна обрабатывать такие сигналы,
корректно завершая работу (закрывая, в частности, посредством close socket с
дескриптором s).

5.2. Программа-клиент

Текст программы-клиента на языке программирования СИ
выглядит следующим образом

1  #include  

2  #include  

3  #include  

4  #include  

5  #include   

6  #define SRV_HOST "delta" 

7  #define SRV_PORT 1234 

8  #define CLNT_PORT 1235 

9  #define BUF_SIZE 64

10  #define TXT_ANSW "I am your
clientn" 

11  main () {

12    int s;

13    int from_len;

14    char buf[BUF_SIZE];

15    struct hostent *hp;

16    struct sockaddr_in clnt_sin, srv_sin; 

17    s = socket (AF_INET, SOCK_STREAM, 0);

18    memset ((char *)&clnt_sin, '',

                    sizeof(clnt_sin));

19    clnt_sin.sin_family = AF_INET;

20    clnt_sin.sin_addr.s_addr = INADDR_ANY;

21    clnt_sin.sin_port = CLNT_PORT;

22    bind (s, (struct sockaddr *)&clnt_sin,

                sizeof(clnt_sin)); 

23    memset ((char *)&srv_sin, '',

             sizeof(srv_sin));

24    hp = gethostbyname (SRV_HOST);

25    srv_sin.sin_family = AF_INET;

26    memcpy ((char

*)&srv_sin.sin_addr,hp->h_addr,hp->h_length);


27    srv_sin.sin_port = SRV_PORT;

28    connect (s, &srv_sin, sizeof(srv_sin));


29    from_len = recv (s, buf, BUF_SIZE, 0);

30    write (1, buf, from_len);

31    send (s, TXT_ANSW, sizeof(TXT_ANSW), 0);

32    close (s);


33    exit (0);

34    }

В строках 6 и 7 описываются константы SRV_HOST и
SRV_PORT, определяющие имя удаленного узла, на котором функционирует
программа-сервер, и номер порта, к которому привязан socket сервера.

Строка 8 приписывает целочисленной константе 1235
символическое имя CLNT_PORT. В дальнейшем эта константа будет использована в
качестве номера порта клиента.

В строках 17...22 создается привязанный к порту на
локальном узле socket.

В строке 24 посредством библиотечной функции
gethostbyname транслируется символическое имя удаленного узла (в данном случае
"delta"), на котором должен функционировать сервер, в адрес этого
узла, размещенный в структуре типа hostent.

В строке 26 адрес удаленного узла копируется из
структуры типа hostent в соответствующее поле структуры srv_sin, которая позже
(в строке 28) используется в системном вызове connect для идентификации
программы-сервера.

В строках 29...31 осуществляется обмен данными с
сервером и вывод вопроса, поступившего от сервера, в стандартный вывод.

Строка 32 посредством системного вызова close
закрывает (удаляет) socket.
Список литературы

Для подготовки данной работы были использованы
материалы с сайта http://www.realcoding.net/


Не сдавайте скачаную работу преподавателю!
Данный реферат Вы можете использовать для подготовки курсовых проектов.

Поделись с друзьями, за репост + 100 мильонов к студенческой карме :

Пишем реферат самостоятельно:
! Как писать рефераты
Практические рекомендации по написанию студенческих рефератов.
! План реферата Краткий список разделов, отражающий структура и порядок работы над будующим рефератом.
! Введение реферата Вводная часть работы, в которой отражается цель и обозначается список задач.
! Заключение реферата В заключении подводятся итоги, описывается была ли достигнута поставленная цель, каковы результаты.
! Оформление рефератов Методические рекомендации по грамотному оформлению работы по ГОСТ.

Читайте также:
Виды рефератов Какими бывают рефераты по своему назначению и структуре.

Сейчас смотрят :

Реферат Romeo And Juliet Imagery Of Love Essay
Реферат Descartes Existence Of God Essay Research Paper
Реферат Причини першої світової війни
Реферат Технология GPRS
Реферат Картины природы в поэме М. Ю. Лермонтова Мцыри и их значение
Реферат Экономика недвижимости
Реферат Народная школа земство и правительство
Реферат Требования к условиям труда
Реферат Нормы гражданского права в сфере денежного обращения
Реферат Культура и искусство Кампучии
Реферат Соотношение и физиологические свойства лейкоцитов периферической крови и красного костного мозга в условиях повышенной концентрации кальция питьевых вод и кратковременной интенсивной мышечной деятельности
Реферат Анализ рынка страховых услуг 2
Реферат Роль общения в развитии личности подростка
Реферат Организация технического обслуживания машинно-тракторного парка Янаульской МТС
Реферат Тенденции и технологии управления клубной системой