Вы находитесь на странице: 1из 24

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
Roteiro
● Introdução

● Objetivos

● 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
C++0x
class socket {
public:

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.
};
C++0x

class socket {

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

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