Página principal   Módulos   Lista de namespaces   Hierarquia de classes   Lista de componentes   Lista de ficheiros   Membros do namespace   Componentes membro   Ficheiros membro   Páginas relacionadas  

mensageiro.C

Ir para a documentação deste ficheiro.
00001 
00007 #include <cassert>
00008 
00009 #include <IPC++/mensageiro.H>
00010 
00011 IPC::Mensageiro::Mensageiro(key_t const chave)
00012 {
00013     assert(not existe_instancia);
00014 
00015     existe_instancia = true;
00016 
00017     // Obtenção de PID do processo corrente e do UID do utilizador.
00018     meu_PID = int(getpid());
00019     meu_UID = int(getuid());
00020 
00021     estabeleceSemaforoDeAcesso(chave);
00022 
00023     entraEmAcessoExclusivo();
00024 
00025     estabeleceCaixaDoCorreio(chave);
00026 
00027     try {
00028         
00029         /* Tenta ler PID de um servidor do canal 1, que é o canal onde
00030            os servidores se registam.  Se a leitura falhar, não existe
00031            servidor registado, pelo que o corrente processo se
00032            assumirá como servidor. Note-se que esta utilização de
00033            excepções como substitutos de instruções de selecção não é
00034            boa ideia em geral. */
00035         PID_do_outro = leBasicoInt(1, false);
00036 
00037         saiDeAcessoExclusivo();
00038         
00039         /* Encontrou registo de vervidor.  Nesse caso é
00040            cliente. */
00041         sou_um_servidor = false;
00042 
00043         // Depois escreve o seu PID no canal do servidor */
00044         escreveBasicoInt(PID_do_outro, meu_PID);
00045         
00046     } catch(Erro) {
00047         
00048         /* Não encontrou registo de servidor.  Nesse caso é
00049            servidor e espera por um cliente. */
00050         sou_um_servidor = true;
00051         
00052         /* O servidor regista a existência de actividade
00053            escrevendo uma mensagem irrelevante no canal 2, que
00054            é usado pelos servidores para saberem se a caixa do
00055            correio deve ser eliminada quando eles terminam a
00056            execução. */
00057         escreveBasicoInt(2, 0);
00058         
00059         /* O servidor escreve o seu PID no canal 1. */
00060         escreveBasicoInt(1, meu_PID);
00061         
00062         saiDeAcessoExclusivo();
00063 
00064         /* Depois fica à espera do PID do cliente mas já no
00065            seu próprio canal. */
00066         PID_do_outro = leBasicoInt(meu_PID);
00067     }
00068 
00069     // Envia o UID ao "outro".
00070     escreveBasicoInt(PID_do_outro, meu_UID);
00071 
00072     // Recebe o UID do "outro".
00073     UID_do_outro = leBasicoInt(meu_PID);
00074 }
00075 
00076 IPC::Mensageiro::~Mensageiro() 
00077 {
00078     try {
00079         if(sou_um_servidor) {
00080 
00081             /* Se é servidor espera por fim do cliente antes de
00082                terminar em paz. */
00083             std::string mensagem;
00084             while((mensagem = leBasico(meu_PID)) != "TeRmInEi")
00085                 ;
00086                 
00087             entraEmAcessoExclusivo();
00088 
00089             /* Servidor elimina um marcador de existência de
00090                actividade. */
00091             leBasicoInt(2);
00092 
00093             /* Se não há nenhum marcador de existência de actividade,
00094                remove a caixa do correio e o respectivo semáforo. Ver mais
00095                acima nota acerca de blocos de tentativa para substituir
00096                instruções de selecção. */
00097             try {
00098                 leBasicoInt(2, false);
00099                 escreveBasicoInt(2, 0);
00100             } catch(Erro) {
00101                 removeCaixaDoCorreio();
00102             }
00103 
00104                 saiDeAcessoExclusivo();
00105         } else {
00106             // Clientes avisam servidores que vão terminar.
00107             escreveBasico(PID_do_outro, "TeRmInEi");
00108         }
00109     } catch(Erro) {
00110         /* Se houve erro, ignorar...  Excepções em destrutores são
00111            má ideia.  Deixar uma caixa do correio criada não
00112            incomoda muito... */
00113     }
00114 }
00115 
00116 std::string IPC::Mensageiro::leBasico(int const tipo, 
00117                                       bool const deve_esperar) const
00118 {
00119     typedef std::string::size_type Tamanho;
00120 
00121     int tipo_de_leitura = deve_esperar ? 0 : IPC_NOWAIT;
00122 
00123     // Receber tamanho da mensagem:
00124     msgbuf *mensagem_ipc = 
00125         static_cast<msgbuf*>(malloc(sizeof(long) + sizeof(Tamanho)));
00126 
00127     if(msgrcv(identificador_da_caixa_do_correio, 
00128               mensagem_ipc, sizeof(Tamanho), tipo, tipo_de_leitura) == -1)
00129         throw Erro();
00130 
00131     Tamanho tamanho;
00132     memcpy(static_cast<void*>(&tamanho), 
00133            static_cast<void*>(mensagem_ipc->mtext),
00134            sizeof(Tamanho));
00135 
00136     free(mensagem_ipc);
00137 
00138     // Receber memsagem:
00139     mensagem_ipc = 
00140         static_cast<msgbuf*>(malloc(sizeof(long) + tamanho + 1));
00141 
00142     if(msgrcv(identificador_da_caixa_do_correio, 
00143               mensagem_ipc, tamanho + 1, tipo, tipo_de_leitura) == -1)
00144         throw Erro();
00145 
00146     std::string mensagem = mensagem_ipc->mtext;
00147 
00148     free(mensagem_ipc);
00149 
00150     return mensagem;
00151 }
00152 
00153 void IPC::Mensageiro::escreveBasico(int const tipo, 
00154                                     std::string const& mensagem) const
00155 {
00156     typedef std::string::size_type Tamanho;
00157 
00158     // Enviar tamanho da mensagem:
00159     msgbuf *mensagem_ipc = 
00160         static_cast<msgbuf*>(malloc(sizeof(long) + sizeof(Tamanho)));
00161 
00162     mensagem_ipc->mtype = tipo;
00163     Tamanho tamanho = mensagem.size();
00164     memcpy(static_cast<void*>(mensagem_ipc->mtext),
00165            static_cast<void*>(&tamanho), sizeof(Tamanho));
00166 
00167     if(msgsnd(identificador_da_caixa_do_correio, 
00168               mensagem_ipc, sizeof(Tamanho), IPC_NOWAIT) == -1)
00169         throw Erro();
00170 
00171     free(mensagem_ipc);
00172 
00173     // Enviar memsagem:
00174     mensagem_ipc = 
00175         static_cast<msgbuf*>(malloc(sizeof(long) + tamanho + 1));
00176 
00177     mensagem_ipc->mtype = tipo;
00178     strcpy(mensagem_ipc->mtext, mensagem.c_str());
00179 
00180     if(msgsnd(identificador_da_caixa_do_correio, 
00181               mensagem_ipc, tamanho + 1, IPC_NOWAIT) == -1)
00182         throw Erro();
00183 
00184     free(mensagem_ipc);
00185 }
00186 
00187 void IPC::Mensageiro::estabeleceSemaforoDeAcesso(key_t const chave)
00188 {
00189 #if defined(__GNU_LIBRARY__) and not defined(_SEM_SEMUN_UNDEFINED)
00190     // A união semun é definida pela inclusão de <sys/sem.h>
00191 #else
00192     // Caso contrário tem de se definir a união explicitamente:
00193     union semun {
00194         int val;                    /* value for SETVAL */
00195         struct semid_ds *buf;       /* buffer for IPC_STAT, IPC_SET */
00196         unsigned short int *array;  /* array for GETALL, SETALL */
00197         struct seminfo *__buf;      /* buffer for IPC_INFO */
00198     };
00199 #endif
00200     
00201     int permissoes = (chave == key_t(getuid()))? 0660 : 0666;
00202 
00203     // Criação de semáforo de acesso à caixa do correio/obtenção de
00204     // identificador de semáforo de acesso à caixa do correio existente:
00205     identificador_do_semaforo = 
00206         semget(chave, 1, IPC_CREAT | IPC_EXCL | permissoes);
00207     if(identificador_do_semaforo == -1)
00208         if(errno == EEXIST) {
00209             identificador_do_semaforo = semget(chave, 1, 0);
00210             if(identificador_do_semaforo == -1)
00211                 throw Erro();
00212         } else
00213             throw Erro();
00214     else {
00215         semun ctl_arg;
00216         ctl_arg.val = 1;
00217         
00218         if(semctl(identificador_do_semaforo, 0, SETVAL, ctl_arg) == -1)
00219             throw Erro();
00220     }
00221 }
00222 
00223 bool IPC::Mensageiro::existe_instancia = false;
00224 
00225 
00226 #ifdef TESTE
00227 
00228 #include <iostream>
00229 
00230 extern "C" {
00231 #include <unistd.h>
00232 }
00233 
00234 using namespace std;
00235 using namespace IPC;
00236 
00237 int main() 
00238 {
00239     fork();
00240 
00241     try {
00242         Mensageiro mensageiro;
00243         
00244         mensageiro.envia("olá");
00245 
00246         mensageiro.envia(string("olát"));
00247 
00248         string s1 = "olé";
00249         mensageiro.envia(s1);
00250         
00251         string const s2 = "olí";
00252         mensageiro.envia(s2);
00253 
00254         char* s3 = "oló";
00255         mensageiro.envia(s3);
00256         
00257         char const* s4 = "oló1";
00258         mensageiro.envia(s4);
00259         
00260         char* const s5 = "oló2";
00261         mensageiro.envia(s5);
00262         
00263         char const* const s6 = "oló3";
00264         mensageiro.envia(s6);
00265 
00266         mensageiro.envia(1.0);
00267         
00268         double x1 = 2.0;
00269         mensageiro.envia(x1);
00270 
00271         double const x2 = 3.0;
00272         mensageiro.envia(x2);
00273 
00274         mensageiro.envia(1);
00275         
00276         int i1 = 2;
00277         mensageiro.envia(i1);
00278 
00279         int const i2 = 3;
00280         mensageiro.envia(i2);
00281 
00282         mensageiro.envia('a');
00283 
00284         char c1 = 'b';
00285         mensageiro.envia(c1);
00286 
00287         char const c2 = 'c';
00288         mensageiro.envia(c2);
00289 
00290         mensageiro.leMensagem();
00291         assert(mensageiro.mensagemLida<string>() == "olá");
00292 
00293         mensageiro.leMensagem();
00294         assert(mensageiro.mensagemLida<string>() == "olát");
00295 
00296         mensageiro.leMensagem();
00297         assert(mensageiro.mensagemLida<string>() == "olé");
00298 
00299         mensageiro.leMensagem();
00300         assert(mensageiro.mensagemLida<string>() == "olí");
00301 
00302         mensageiro.leMensagem();
00303         assert(mensageiro.mensagemLida<string>() == "oló");
00304 
00305         mensageiro.leMensagem();
00306         assert(mensageiro.mensagemLida<string>() == "oló1");
00307 
00308         mensageiro.leMensagem();
00309         assert(mensageiro.mensagemLida<string>() == "oló2");
00310 
00311         mensageiro.leMensagem();
00312         assert(mensageiro.mensagemLida<string>() == "oló3");
00313 
00314         mensageiro.leMensagem();
00315         assert(mensageiro.mensagemLida<double>() == 1.0);
00316 
00317         mensageiro.leMensagem();
00318         assert(mensageiro.mensagemLida<double>() == 2.0);
00319 
00320         mensageiro.leMensagem();
00321         assert(mensageiro.mensagemLida<double>() == 3.0);
00322 
00323         mensageiro.leMensagem();
00324         assert(mensageiro.mensagemLida<int>() == 1);
00325 
00326         mensageiro.leMensagem();
00327         assert(mensageiro.mensagemLida<int>() == 2);
00328 
00329         mensageiro.leMensagem();
00330         assert(mensageiro.mensagemLida<int>() == 3);
00331 
00332         mensageiro.leMensagem();
00333         assert(mensageiro.mensagemLida<char>() == 'a');
00334 
00335         mensageiro.leMensagem();
00336         assert(mensageiro.mensagemLida<char>() == 'b');
00337 
00338         mensageiro.leMensagem();
00339         assert(mensageiro.mensagemLida<char>() == 'c');
00340     } catch(IPC::Erro& erro) {
00341         cerr << string(erro) << endl;
00342         assert(false);
00343     }
00344 }
00345 
00346 #endif // TESTE

Gerado em Tue Dec 3 15:19:35 2002 para Pacotes por doxygen1.3-rc1