Você está na página 1de 24
Universidade do Estado do Rio de Janeiro Instituto de Matemática e Estatística Departamento de Informática

Universidade do Estado do Rio de Janeiro Instituto de Matemática e Estatística Departamento de Informática e Ciência da Computação

Projetando Servidores Concorrentes Genéricos em C++0x

Aluno: Pedro Lamarão

Orientador: Alexandre Sztajnberg

Abril 2009

Introdução

Objetivos

Roteiro

Interface de Programação de Sockets POSIX

Mecanismos de Projeto e Implementação do C++0x

Um Binding POSIX/C++ para a Interface de Sockets

Projetando Servidores Concorrentes em C++

Exemplo

Considerações Finais

Introdução

Estratégias de Concorrência para Servidores como atender a múltiplos clientes simultaneamente

Mecanismos de Concorrência em POSIX como ler e escrever de/para múltiplos dispositivos de I/O simultaneamente

Mecanismos de Abstração em C++0x podemos utilizar abstrações mais confortáveis para tratar os problemas acima

Objetivos

Desenvolver um binding POSIX/C++ para sockets

Interface mais “limpa”:

orientação a objetos

programação genérica

uma implementação de referência

Propor um padrão para projeto de servidores concorrentes em C++

Estratégias de concorrência

Servidores concorrentes genéricos

Handlers genéricos

Implementação de referência

POSIX/C Sockets

POSIX é uma norma que especifica a interface de programação entre sistema operacional e programas de usuário

POSIX/C é POSIX na linguagem C

Sockets são dispositivos para comunicação entre processos

A programação de servidores concorrentes utilizando sockets em C possui limitações:

verificação tediosa de erros informação com mínima tipagem ?

POSIX/C Sockets

struct addrinfo hint = { AI_PASSIVE, AF_INET, SOCK_STREAM, 0, 0, 0, 0, 0 }; struct addrinfo* ai; int st = getaddrinfo("", "echo", &hint, &ai); if (st != 0) { fprintf(stderr, "%s\n", gai_strerror(status));

exit(1);

}

sockaddr_storage addr; memcpy(&addr, ai->ai_addr, ai->ai_addrlen); socklen_t addrlen = ai->ai_addrlen;

freeaddrinfo(ai);

POSIX/C Sockets

sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(7); addr.sin_addr.s_addr = htonl(IPADDR_ANY); socklen_t addrlen = sizeof(sockaddr_in);

POSIX/C Sockets

int listener = socket(AF_INET, SOCK_STREAM, 0); if (listener == -1) { perror(NULL);

exit(1);

}

st = bind(listener, (struct sockaddr*)&addr, addrlen); if (status == -1) { perror(NULL);

exit(1);

}

st = listen(listener, SOMAXCONN); if (status == -1) { perror(NULL);

exit(1);

}

POSIX/C Sockets

is_running = 1; while (is_running) { int client = accept(listener, NULL, 0); if (client == -1) { perror(NULL);

exit(1);

}

echo_handler (client);

}

close(listener);

C++0x

C++ é C com melhores mecanismos de abstração

C++ e C são normas ISO

C++0x é a nova revisão da norma C++

Provavelmente será C++1x quando terminar

C++0x

Vantagens do C++0x

exceções para propagação de erros

classes para representação de recursos

templates para programação genérica

Como posso utilizar estas vantagens para fazer melhores programas concorrentes utilizando sockets?

exceções para evitar o tédio

classes para gerência de recursos

funções parametrizadas no tipo do endereço

listas de objetos adequadas aos algoritmos genéricos

class socket { public:

C++0x

socket (); socket (int family, int socktype, int protocol =

0);

socket (socket const& x) = delete; socket (socket&& x);

~socket ();

socket& operator= (socket const& x) = delete; socket& operator= (socket&& x);

// etc.

};

class socket {

C++0x

template <typename AddressType> requires SocketAddress<AddressType> void bind (AddressType const& address);

void listen (int backlog = SOMAXCONN);

socket accept ();

};

POSIX/C++ Sockets

O mesmo exemplo anterior, reescrito em C++0x

addrinfo hint = { AI_PASSIVE, AF_INET, SOCK_STREAM, 0, 0, 0, 0, 0 };

auto result = posix::getaddrinfo("", "echo", hint); addrinfo const& ai = *(result.begin());

sockaddr_storage addr; memcpy(&addr, ai.ai_addr, ai.ai_addrlen);

POSIX/C++ Sockets

sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(7); addr.sin_addr.s_addr = htonl(IPADDR_ANY);

POSIX/C++ Sockets

posix::socket listener(AF_INET, SOCK_STREAM);

listener.bind(addr);

listener.listen();

is_running = 1; while (is_running) {

posix::socket client = listener.accept();

echo_handler (std::move(client));

}

POSIX/C++ Sockets

O que ganhei com o Binding?

Exceções propagam erros automaticamente; o responsável que capture e trate

Notação mais elegante economiza argumentos em chamadas

Gerência de recursos evita vazamentos

Programação Genérica sugere reuso

agora com uma classe socket reusável, o que seria uma classe servidor reusável?

Servidor Genérico

Um template de classes é uma regra para geração mecânica de classes

Uma classe genérica é uma meta-classe, especializável por outras classes, que definem seu comportamento

Uma estratégia é reaplicável, assim como uma meta-classe

em

tempo de compilação, não de execução.

Servidor Genérico: Modelo

Servidor Genérico: Modelo

Servidor Genérico: Modelo

server encapsula o modo de uso de um mecanismo de concorrência qualquer

StrategyServer especifica a relação entre

server e StrategyHandlers

foo_handler implementa o protocolo de aplicação foo, obedecendo a StrategyHandler

server<foo_handler> gera mecanicamente

classes servidor-do-protocolo-foo

Servidor Genérico: Estratégia

Inicialmente, um loop: uma iteração, um cliente

Concorrência com threads ou processos:

iteração/cliente inicia novo

thread

processo

Concorrência com notificação de disponibilidade:

um “demultiplexador” mantém múltiplos clientes

select

poll

Servidor Genérico: Aplicação

typedef echo_threaded_handler handler; threaded_server<handler> server;

addrinfo hint = { AI_PASSIVE, AF_INET, SOCK_STREAM, 0, 0, 0, 0, 0 }; auto result = posix::getaddrinfo("", "echo", hint);

server.configure(*result.begin());

server.start();

server(); // main loop

Conclusão

POSIX/C possui mecanismos adequados para implementar a concorrência

C++0x possui mecanismos adequados para

tornar a implementação mais

confortável

É possível escrever estratégias de concorrência como meta-classes em C++0x

Trabalhos Futuros

Estratégia: concorrência com notificação de finalização de operação

Avaliação de Desempenho

Handlers para protocolos de aplicação mais complexos

Proposta formal no grupo de trabalho