Программирование >>  Структура ядра и системные вызовы 

1 ... 58 59 60 [ 61 ] 62 63 64 ... 98


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

При успешном выполнении эта функция возвращает О, а в случае неудачи -1. j

11.1.5. Функция accept

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

#include <sys/types.h> #include <sys/socket.h>

accept { int sid, struct socloddr* addr p, int len p );

Эта функция вызывается в серверном процессе для установления соединения с клиентским гнездом (которое делает запрос на установление соединения посредством вызова функции connect).

Аргумент представляет собой дескриптор гнезда, возвращенный функцией socket. Аргумент addr р - это указатель на адрес объекта типа struct sock; в нем хранится имя клиентского гнезда, с которым устанавливает соединение серверное гнездо.

Аргумент len р изначально устанавливается равным максимальному размеру объекта, указанному аргументом addr р. При возврате он содержет размер имени клиентского гнезда, на которое указывает аргумент addr р.

Если аргумент addr р или аргумент len р имеет значение NULL, эта функция не передает имя клиентского гнезда обратно в вызывающий процесс.

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

11.1.6. Функция send

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

#include <sys/types.h> #include <sys/socket.h>

int send ( int sid, const char* buf, int len, int flag );

Эта функция передает содержащееся в аргументе buf сообщение длиной Men байтов в гнездо, заданное аргументом sid и соединенное с данным гнездом.

Аргументу flag обычно присваивается значение О, но он может иметь и значение MSG OOB. В этом случае сообщение, содержащееся в buf должно бьггь передано как высокоприоррггетное (out-of-band message).

Через гнезда можно передавать сообщения двух типов: обычные и высокоприоритетные. По умолчанию все сообщения, передаваемые гнездом, являются обычными, если явно не указано, что они высокоприоритетные. Если из гнезда передается более одного сообщения одного типа, другое гнездо принимает их по алгоррггму FIFO. Гнездо-получатель может выбрать тип сообщений, которые оно хотело бы получать. Сообщения с высоким приоррггетом следует использовать только в экстренных случаях.

Если процесс пользуется гнездом с установлением соединения или гнездом без установления соединения, для которого указан адрес получателя по умолчанию (посредством вызова функции connect), он может передавать обычные сообщения с помощью либо API send, либо API write. При этом функции send и sendto можно использовать для передачи сообщений нулевой длины, а write - нельзя. Кроме того, в BSD 4.2 и 4.3 функция write при обращении к гнезду, соединение с которым не установлено, дает сбой. В System V.4 такой вызов вроде бы выполняется успещно, но никакие данные не передаются.

В случае неудачи эта функция возвращает -1; в случае успешного выполнения возвращается число переданных байтов данных.

11.1.7. Функция sendto

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

#include <sys/types.h> #include <sys/socket.h>

int sendto ( int sid, const char* buf, int len, int flag,

struct soclcaddr* addr p, int* len p );

Эта функция делает то же самое, что и API send, только вызывающий процесс указывает также адрес гнезда-получателя (в аргументах addr р И 1еп р).

Аргументы sid, buf, len и flag - те же самые, что в API send. Аргумент addr p - это указатель на объект, который содержит имя гнезда-получателя. Аргумент len р содержит число байтов в объекте, на который указывает аргумент addr р.

В случае неудачи данная функция возвращает -1; в случае успещного выполнения возвращается число переданных байтов данных.



11.1.8. Функция recv

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

#include <sys/types.h> #incrude <sys/socket.h>

int recv ( int sid, char* buf, int len, int flag );

Эта функция принимает сообщение через гнездо, указанное в аргументе sid. Принятое сообщение копируется в буфер buf, а максимальный размер йы/задается аргументом len.

Если в аргументе flag указан флаг MSG OOB, то приему подлежит высокоприоритетное сообщение. В противном случае ожидается обычное сообщение. Кроме того, в аргументе flag может бьггь указан флаг MSG PEEK, означающий, что процесс желает взглянуть на полученное сообщение, но не собирается удалять его из потокового гнезда. Такой процесс может повторно вызвать функцию recv для приема сообщения позже.

Если процесс пользуется гнездом (с установлением соединения или без установления соединения), для которого указан адрес получателя по умолчанию (посредством вызова API bind), он может принимать обычные сообщения через это гнездо с помощью либо API recv, либо API read. В BSD 4.2 и 4.3 функция read при использовании с гнездом, с которым не установлено соединение, дает сбой. В System V.4 в подобном случае функция read возвращает нулевое значение в блокирующем режиме и -1 в неблокирующем.

В случае неудачи функция recv возвращает -I; в случае успешного выполнения возвращается число байтов данных, записанных в буфер buf

11.1.9. Функция recvfrom

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

#include <sys/types.h> #include <sys/socket.h>

int recvfrom ( int sid, const char* buf, int len, int flag, struct sockaddr* addr p, int* len p );

Эта функция делает то же самое, что и API recv, только при ее вызове задаются аргументы addr р и len р, позволяющие узнать имя гнезда-отправителя.

Аргументы sid, buf, len и flag - те же самые, что в API recv. Аргумент addr р - это указатель на объект, который содержит имя гнезда-отправителя.

Аргумент len р сообщает число байтов в объекте, на который указывав аргумент addr р.

В случае неудачи функция recvfrom возвращает -I; в случае успешногс выполнения возвращается число принятых байтов данных.

11.1.10. функция shutdown

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

#include <sys/types.h> #include <sys/socket.h>

int shutdown ( int sid, int mode );

Данная функция закрывает соединение между серверным и клиeнтcки гнездами.

Аргумент sid - это дескриптор гнезда, возвращенный функцией socket Аргумент mode задает режим закрытия. Вот его возможные значения:

Режим Смысл

0 Закрывает гнездо для чтения. При попытке продолжить чтение будут возвращаться нулевые байты (EOF)

1 Закрывает гнездо для записи. Дальнейшие попытки передать данные в это гнездо приведут к выдаче кода неудачного завершения, -1

2 Закрывает гнездо для чтения и записи. Дальнейшие попытки передать данные в это гнездо приведут к вьщаче кода неудачного завершения -1,

а при продолжении чтения будет возвращаться нулевое значение (EOF)

В случае неудачи данная функция возвращает -I, а в случае успешногс выполнения - нуль.

11.2. Создание потоковых гнезд

В этом разделе описана пара программ типа клиент/сервер, на примере которых показывается, как нужно создавать потоковые гнезда для IPC Используемые здесь потоковые гнезда могут бьггь гнездами домена UNI> или гнездами домена Intemet. В последнем случае клиентский и серверные процессы могут выполняться как на одной машине, так и на разных.

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

1- В прикладных программах можно обходиться без адресов гнезд. Пользователи таких прикладных программ манипулируют адресами гнезд путе\ указания имен гнезд или хост-имен и номеров портов.



2. Функции-члены read и write класса sock аналогичны одноименным файловым API ОС UNIX.

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

Класс sock определяется в заголовке sock.h:

#ifndef SOCK H ♦define SOCK H

♦include ♦include ♦include ♦include ♦include ♦include ♦include ♦include ♦include ♦include finclude ♦include const int

<iostream.h>

<stdio.h>

<stdlib.h>

<unistd.h>

<memory.h>

<string.h>

<sys/types.h>

<sys/socket.h>

<arpa/inet.h>

<netinet/in.h>

<netdb.h>

<sys/systeminfо.h> BACKLOG NUM = 5;

class sock {

private:

int sid; дескриптор гнезда

int domain; домен гнезда

int socktype; .,. тип гнезда

int rc; 7 код возврата функции-члена

/* создать имя Internet-гнезда на основании хост-имени и номера порта */ int constr name( struct sockaddr in& addr, const char* hostnm, int port }

addr.sin family = domain; if (!hostnm)

addr.sin addr.s addr = INADDR ANY; else {

struct hostent *hp = gethostbyname(hostnm); if {hp==0} (

perror( gethostbyname ); return -1;

memcpy((char*}Saddr.sin addr,(char*}hp->h addr, hp->h length};

addr.sinjport htons(port}; return sizeof(addr);

/* сформировать имя гнезда домена UNIX на основании путевого имени */

int constr name( struct sockaddrs addr, const char* Pathnm ) {

addr.sa family = domain; strcpy(addr.sa data, Pathnm );

return sizeof(addr.sa family) + strlen(pathnm) + 1;

/* преобразовать IP-адрес в хост-имя */ char* ip2name( const struct in addr in } {

- u long laddr;

if ((int)(laddr = inet addr(inet ntoa{in}}) == -1} return 0; struct hostent *hp = gethostbyaddr((char *)sladdr, sizeof (laddr}, AF INET); if (hp == NULL) return 0;

for {char **p = hp->h addr list; *p != 0; p++) {

(void) memcpy((char*)sin.s addr, *p, sizeof (in.s addr}}; if (hp->h name) return hp->h name;

return 0;

public:

sock( int dom, int type, int protocol=0 } : domain(dom}, socktype(type) (

if ((sid=socket(domain=dom, socktype=type,protocol})<0} perror( socket );

-sockO ( shutdown 0; close(sid}; }; деструктор int fd() ( return sid; }; /* возвращает дескриптор гнезда */ int goodO { return sid >= 0; }; /* статус объекта sock */ int bind( const char* name, int port=-l ) ( /* присвоение

UNIX-имени */

if (port == -1) ( гнездо домена UNIX struct sockaddr addr; int len = constr name( addr, name}; if ((rc= ::bind(sid,&addr,len}}<0} perror( bind ); } else {

struct sockaddr in addr; int len = constr name( addr, name, port}; if ((rc= ::bind(sid, (struct sockaddr *}Saddr, len))<0 II (rc=getsockname(sid, (struct sockaddr*)Saddr, &len}}<0} perror( bind or getsockname ); else cerr Socket port: ntohs(addr.sin port) endl;

if {rc!=-l && socktype!=SOCK DGRAM && (rc=listen

(sid,BACKLOG NUM)} < 0}

perror ( listen ); return rc; };



1 ... 58 59 60 [ 61 ] 62 63 64 ... 98

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика