Обмен сообщениями и импульсами в ОС QNX. Обмен сообщениями при стандартной организации модели "клиент-сервер", управляемой по запросу, страница 8

Программа client5.c:

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <errno.h>

#include <hw/inout.h>

#include <sys/neutrino.h>

#include <sys/iomsg.h>

#define MY_SERV "my_server_name"

struct sigevent secpas;

int key = 0;

const struct sigevent *keyboardIsr(void *area, int id) {

if (key == in8(0x60)) {

return NULL;

}

else {

key = in8(0x60);

if (key > 100) {

return NULL;

}

else {

return &secpas;

}

}

}

int main() {

int coid, pulse_code = 0;

int id;

ThreadCtl(_NTO_TCTL_IO, 0);

secpas.sigev_notify = SIGEV_INTR;

id = InterruptAttach(1, &keyboardIsr, NULL, NULL, 0);

// Присоединение к каналу

if ((coid = name_open( MY_SERV, 0 )) == -1) {

printf("Failed to find server");

return EXIT_FAILURE;

}   

while (1) {

InterruptWait(0, NULL);

if (key == 1) {

printf("Client: disconnect\n");

break;

}

if (++pulse_code == 128) break;

printf("Client: send pulse: pulse.code = %d, pulse.value = %d\n", pulse_code, key);

MsgSendPulse(coid, 10, pulse_code, key);

}

InterruptDetach(id);

name_close(coid);

return EXIT_SUCCESS;

}

Результат выполнения программ представлен на рис. 1.12.

Рис. 1.12. Результат выполнения программ

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

3.  Обработка клиентских запросов агентами (субсерверами)

В соответствии с моделью «сервер/субсервер» имеется сервер, который создаёт ряд других процессов (агентов). Каждый из этих агентов посылает сообщение серверу, но сервер не отвечает им, пока не получит запрос от клиента. Затем сервер передаёт запрос клиента одному из агентов, отвечая на его сообщение заданием, которое агент обязан выполнить.

Рассмотрим соответствующие программы.

Программа server6.c:

#include <stdio.h>

#include <errno.h>

#include <process.h>

#include <stdlib.h>

#include <string.h>

#include <sys/dispatch.h>

#define SERV_NAME "channel"

name_attach_t *attach;

// Свободных агентов, массив своб. агентов, клиентов в ожидании, массив ожидающих клиентов

int num_agents = 0, agents[5], num_clients = 0, clients[100];

// Счётчик цикла, id клиента и id клиента, задачу которого выполнил агент

int i, rcvid, rec_rcvid;

// Буфер принятого сообщения, полезное сообщение, отправитель сообщения

char rec_buf[200], msg[200], sender[20];

// Перенаправление задачи клиенту

void send_to_agent();

int main() {

// Регистрация префикса и создание канала

if (!(attach = name_attach(NULL, SERV_NAME, 0))) {

printf("Server: name_attach() error\n");

return EXIT_FAILURE;

}

// Запускаем агентов

for (i=0; i < 5; i++){

spawnl(P_NOWAIT, "agent", "agent", NULL);

}

while (1) {

// Принимаем сообщения    

rcvid = MsgReceive(attach->chid, &rec_buf, sizeof(rec_buf), NULL);

// Не пульсы

if (rcvid) {

printf("Server: received message \"%s\"", rec_buf);

sscanf(rec_buf, "%s %d %s", sender, &rec_rcvid, msg);

if (!strcmp(sender, "agent")) {

// Сообщение получили от агента

printf(" from agent\n");

// Агент не занят

agents[num_agents] = rcvid;

num_agents++;

if (rec_rcvid) {

// Если агент отработал задачу, уведомляем клиента

MsgReply(rec_rcvid, 0, &msg, sizeof(msg));

if (num_clients > 0) {

// Если имеется очередь клиентов, перенаправляем задачу последнего агенту

printf("Server: client from queue\n");