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

1 ... 60 61 62 [ 63 ] 64 65 66 ... 98


cerr usage: argv[0] Oocknameport>

[<remote-host>]\n ; return 1;

int port = -1, rc;

/* проверить, указан ли номер порта или имя гнезда */ (void)sscanf( argv[l], %d ,sport);

/* создать дейтаграммное гнездо */

sock sp( port==-l ? AF UNIX : AF INET, SOCK DGRAM }; if (Isp.goodO) return 1;

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

if (sp.bind(port==-l ? argv[l] : argv[2),port} < 0} return 2; /* прочитать сообщение MSGl от клиента */

if ((rc=sp.readfrom( buf, sizeof buf, 0, socknm, sport, -1}) < 0) return 1;

cerr server: recvfrom from socknm msg: buf endl;

/* направить сообщение MSG2 клиенту */

if ((rc= sp.writeto( MSG2, strlen(MSG2}+1, 0, socknm, port, -1)} < 0) return 2;

/* установить адрес клиента, принимаемый no умолчанию */ if ((rc = sp.connect(socknm, port)} < 0} return 3;

/* прочитать сообщение MSGS от клиента */

if ((rc = sp.read(buf, sizeof buf, 0)) < 0) return 4;

cerr server: receive msg: buf \n ;

/* направить сообщение MSG4 клиенту */

if (write(sp.fd(),MSG4,strlen(MSG4)+l}<0) return 5;

m Эта программа похожа на программу sockjstreamjsrv. С. Различаются они лишь тем, что создаваемое гнездо объявляется как SOCK DGRAM (это делается посредством функции sockr.sock). Программа получает в командной строке имя гнезда (необходимо для создания гнезда домена UNIX) или номер порта и/или имя хоста (для создания гнезда домена Internet). Имя гнезда должно быть известно клиенту, желающему установить с ним соединение. После того как гнездо будет создано, программа начнет читать сообщение клиента, пользуясь функцией sockr.readfrom, которая возвращает имя гнезда клиента. Программа отвечает клиенту, посылая ему сообщение MSG2 с помощью функции sockrwriteto. После этого программа посредством вызова 5осА;.;соийесгустанавливает соединение с клиентом, применяя при этом адрес, заданный по умолчанию. Затем для чтения сообщения MSG3 используется

функция sockr.read и, в заключение, с помощью API v/rite посылается сообщение MSG4.

Клиентская программа sock datagram cls. С, взаимодействующая с только что рассмотренной программой, приведена ниже:

♦include sock.h const char* MSGl = Hello MSGl const char* MSGS = Hello MSGS

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

char buf[80], socknm[80]; if (argc < 2} {

cerr usage: argv[0]

meport> [ <remote-host>]\n ;

return 1;

int men, port = -1, rc;

/* проверить, указан ли номер порта или имя гнезда */ (void)sscanf(argv[l], %d , sport};

/* создать гнездо с использовани11/дейтаграмм */ sock sp( port==-l ? AF UNIX : AFJtHET, SOCK DGRAM }; if (Isp.goodO) return 1; ah

if (port==-l} ( /* гнездо домена UNIX */

sprintf(buf, %s%d , argv[l], getpidO); /* создание имени

клиентского гнезда */ if (sp.bind(buf,port} < 0} return 2; /* присвоение имени

гнезду */

} else

if (sp.bind(0,0) < 0) return 2; присвоение имени гнезду

/* запись сообщения MSG серверу */

if (,(rc=sp.writeto( MSGl, strlen (MSGl)+1, 0, .

Port==-l? argv[l] : argv[2], port, -1)) < 0} return 6;

/* чтение сообщения MSG2, поступившего от сервера */

if ((rc=sp.readfrom( buf, sizeof bu, 0, socknm, Sport, -1)} < 0} return 7;

cerr client: recvfrom socknm, << msg: buf endl;

/* выяснить адрес сервера, заданный no умолчанию */ if (sp.connect(socknm,port) < 0) return 8;

/* направить сообщение MSGS серверу */

if (sp.write(MSGS, strlen(MSGS}+1) < 0} return 9;



/* чтение сообщения MSG4 сервера */

if ((rc=read(sp.fdО,buf,sizeof buf))==-!) return 10; cerr client: read msg: buf endl; 4980

sp.shutdown();

} ij

в командной строке этой программы в качестве аргумента указывается * имя гнезда клиента либо номер порта и/или имя хоста. Программа модифицирует имя гнезда (для домена UNIX) путем добавления к нему PID своего процесса. В случае использования гнезд домена Internet добавляется еще и номер порта. Создав гнездо (посредством вызова функций sock::sock и sock::bind), программа посылает серверу сообщение MSG1 с помощью sock::writeto и ожидает ответного сообщения MSG2, вызывая для этого функцию sockr.readfrom. Затем программа выясняет адрес сервера, заданный по умолчанию (с помощью функции sock:.connect). Для отправки сообщения MSG3 серверному процессу используются функция sock::write и API read. Эти функции позволяют также принять сообщение MSG4 от сервера. Перед завершением своей работы программа вызывает функцию sock:.shutdown для удаления гнезда.

Пример работы этих программ с использованием гнезд домена UNIX имеет следующий вид:

% СС -о soc)c datagram srv soc)< datagram srv.С -Isocket -Insl % СС -о sock datagram cls sock datagram cls.С -Isocket -Insl % sock datagram srv SOCK DG & % sock datagram cls SOCK DG

server: recvfrom from SOCK DG572 msg: Hello MSGl

client: recvfrom SOCK DG msg: Hello MSG2

server: receive msg: Hello MSG3

client: read msg: Hello MSG4

[1] + Done sock datagram srv SOCK DG

Отметим, что в командной строке имя гнезда было зацано как SOCK DG, в то время как полное его имя - SOCK DG572. Выходная информация этих программ сходна с результатами работы программ, в которых используются потоковые гнезда.

В случае создания гнезд домена Intemet результат работы этих же программ будет следующим:

% sock datagram srv О fruit & Socket port: 32838 % sock datagram cls 32838 fruit Socket port: 32840

server: recvfrom from fruit msg: Hello MSGl client: recvfrom fruit msg: Hello MSG2 server: receive msg: Hello MSG3 client: read msg: Hello MSG4 [1] + Done sock datagram srv 0 fruit

В ЭТОМ примере номер порта, используемого первым процессом, равен 32838. Он выполняется на машине с именем fruit. Номер порта второго процесса - 32840. Он также выполняется на машине fruit. Оба процесса взаимодействуют точно так же, как и в случае гнезд домена UNIX. Выходная информация программ, за исключением номеров портов, совпадает.

11.3. Пример приложения типа клиент/сервер, предназначенного для обработки сообщений

В этом разделе представлена новая версия приложения типа клиент/сервер, рассмотренного в разделе 10.3.7. В этой версии используются потоковые гнезда, с помощью которых организуется канал связи между сервером сообщений и любым из его клиентских процессов. Поскольку сервер соединяется непосредственно с каждым клиентским процессом, всякое посылаемое клиентом сообщение является, по сути, представленной в виде строки символов командой, которую необходимо выполнить (например, LOCAL TIME, GMTTIME, QWUITCMD и др.). Сервер посылает свой ответ клиенту тоже в виде строки символов.

Ниже приведена программа сервера х:ообщений sock msg srv. С:

♦include sock.h ♦include <sys/times.h> ♦include <sys/types.h>

♦define MSGl Invalid cmd to message server

typedef enum { L0CAL TIME, GMT TIME, QUIT CMD, ILLEGAL CMD ) CMDS;

/* обработать команды клиента */

int process cmd (int fd )

char buf[80]; time t tim; char* cptr;

/* читать команды клиента до символов EOF или QUIT CMD */

while (read(fd, buf, sizeof buf) > 0)

int cmd = ILLEGAL CMD;

(void)sscanf(buf, %d ,&cmd); switch (cmd) (

case LOCAL TIME:

tim = time(0);

cptr = ctime(&tim);

write(fd, cptr, strlen(cptr)+1);

break;



case GMT TIME: tim = time(0);

cptr = asctime(gmtime(Stim}}; write(fd, cptr, strlen(cptr)+1}; break;

case QUIT CMD: return cmd;

default:

write(fd, MSGl, sizeof MSGl};

return 0;

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

char buf [80], sock;nm[80]; int port=-l, nsid, rc; fd set select set; struct timeval timeRec;

if (argc < 2) {

cerr usage: argv[0] <socknameport> [<host>]\n ; return 1,-

/* проверить, указан ли номер порта в имени гнезда */ (void)sscanf(argv[l], %d ,Sport);

/* создать потоковое гнездо */

sock sp( port!=-l ? AF INET : AF UNIX, SOCK STREAM }; if (Isp.goodO) return 1;

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

if (sp.bind(port==-l ? argv[l] : argv[2],port) < 0} return 2;

for (;;) проверка наличия клиентских соединений

timeRec.tv sec =1; задает тайм-аут опроса равным 1 секунде timeRec.tv usec= 0; FD ZERO( &select set ); FD SET( sp.fdO, sselect set );

/* ожидать наступления тайм-аута или начала процедуры чтения для гнезда */

ГС = select(FD SETSIZE, Sselect set, О, О, StimeRec }; if (rc > О &S FD ISSET(sp.fd(}, sselect set})

/* принять из клиентского гнезда запрос на соединение */

if ((nsid = sp.accept(О, 0)} < 0) return 1;

/* обработать команды */

if (process cmd(nsid)==QUIT CMD) break;

close(nsid); /* повторно использовать дескриптор файла */

/* в противном случае выполнять какие-либо другие действия */

sp.shutdown(}; return 0;

Синтаксис вызова сервера сообщений такой же, как и в случае вызова программы sock stream srv.C. Создается потоковое гнездо, которому точно так же присваивается имя. Однако после того, как гнездо организовано, сервер с помощью API select проверяет, имеются ли в нем запросы на обслуживание. Проверка осуществляется с интервалом, равным i секунде, чтобы в перерывах между проверками сервер мог выполнять другие операции.

Когда клиент посылает серверу команду на обслуживание, он вызывает функцию process cmd, с помощью которой обрабатываются все команды на обслуживание, инициированные клиентом. Функция process cmd возвращает результат, когда клиент посылает серверу команду QUITCMD. Сервер освобождает дескриптор файла nsid, который обозначает гнездо, созданное вызовом функции sockr.accept. После этого сервер либо продолжает опрашивать потоковое гнездо на предмет соединения с другим клиентом, либо просто удаляет его и завершается.

Программа-клиент sockjnsg cls.Cъитшлт следующим образом:

tinclude sock.h tdefine QUIT CMD 2

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

if (argc < 2} (

cerr usage: argv[0] <socknameport> [<host>]\n ; return 1;

int port=-l, rc; I

I* проверить, указан ли номер порта */ (void)sscanf(argv[l], %d ,Sport};

/* host может быть именем гнезда или хост-именем */

char buf[80], *host= (port==-l} ? argv[l] : argv[2], socknm[80];

/* создать клиентское гнездо */

sock sp( port I=-1 ? AF INET : AF UNIX, SOCK STREAM }; if (Isp.goodO } return 1;

/* установить соединение с серверным гнездом */ if (sp.connect(host,port} < 0) return 8;



1 ... 60 61 62 [ 63 ] 64 65 66 ... 98

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