Transferindo dados entre threads

21 respostas
Baldao

Fala galera!

Tô desenvolvendo um messenger. Esse messenger vai ter um servidor que irá gerenciar as conexões dos clientes, pra cada conexão estabelecida é criada uma thread para gerenciá-la, logo, para cada cliente conectado haverá uma thread gerenciando sua conexão.
Problema: quando um cliente (a) enviar uma mensagem para um cliente (b), essa mensagem será enviada para o servidor que por sua vez a repassará para a thread do cliente (b), mas como o servidor vai saber qual é a thread (b) se vão existir várias outras thread rodando? E como vou acessá-la?
Ficou meio complicado de entender? :?

21 Respostas

ViniGodoy

Acho que você terá um mapa, contendo o identificador da pessoa e o objeto que representa a conversa dessa pessoa.

A thread principal, que recebe as mensagens, simplesmente consulta esse mapa e chama um método set nessa classe que representa a conversa. Essa classe está sendo usada por outra Thread (uma por conversa, como você falou).

Não confunda Thread com objetos. Threads são linhas de execução no seu programa. Existe uma variável que disponibiliza informações sobres as Threads rodando, mas ela não é a Thread em si.

xgucax

Uma outra dúvida que me surgiu:
Você está usando oq? Sockets?

Baldao

Sim, estou usando Sockets.

ViniGodoy

Dê uma olhada nesse tópico:
http://www.guj.com.br/posts/list/49965.java#262473

Embora não trate de sockets especificamente, você vai ver um exemplo onde a classe Calculadora informa a classe Reader o número de linhas que o Reader pode ler.

A idéia básica é a mesma expressada por lá. :wink:

Baldao

Valeu! Já tá anotado.
Mas então se eu tenho 20 segmentos rodando, a thread principal não conseguiria se comunicar com um específico? Teria que mandar uma mensagem pra todos?

ViniGodoy

No lugar de um set, como fiz ali, use um Map.

A Thread principal vai ter que ler qual segmento de algum lugar (do protocolo, provavelmente).

xgucax

Perae Vinicius, mas a conexão com cada cliente (socket) ele guardaria no Map?

Y

xgucax:
Perae Vinicius, mas a conexão com cada cliente (socket) ele guardaria no Map?

Não sei se entendi bem a idéia de ViniGodoy, mas pelo que percebi, seria mais ou menos o que você disse sim.

O gerenciador das Threads, ou seja, a Thread principal que controla as conexões, conteria um Map. Este Map armazenaria referências às conexões/conversas de cada cliente. Quando uma mensagem fosse enviada ao servidor, a Thread principal seria responsável por identificar “para quem” é a mensagem, em seguida pesquisar por este destinatário no Map, e então entregar a mensagem ao recipiente devido.

Creio que a lógica parta disso.

xgucax

Sim, mas isso é escalável?
E os TimeOuts?
teria que ter algum agente para verificar ociosidade de conexão, não?

ViniGodoy

A idéia é essa mesmo.

Afinal de contas, você já é obrigado a ter as conexões em algum lugar. Porque não criar um map para indexa-las?

ViniGodoy

Não entendi.
Qual o problema da escabilidade com o mapa?
O que os timeouts tem a ver com assunto?

Acho que a gerência de que conexões estão vivas e a quem se refere cada conexão é uma coisa.

O controle de uma conexão em si é outra.

O que você chama de escalabilidade num sistema parecido com messenger?

Baldao

Valeu pessoal!
Compreendi bem a idéia de armazenar cada socket em um map. Me “abriu a mente” hehe ^^

xgucax

Assim, imagine que vc crie conexões para todos os usuários certo?:
Armazenando-as num mapa, você terár que gerenciá-las para fechamento por ociosidade (timeout)
Imagine uma conexão que não está trocando mensagens por 10 minutos e você ainda está lá, gastando uma thread e uma conexão com ela.
E imagine não uma, mas 15 dessas conexões. Sua capacidade de processamento vai pro espaço.
Por isso não entendi guardar as conexões num mapa, pois é muito mais custoso ter uma conexão socket num mapa do que uma String com o endereço do cliente, por exemplo
Quanto a escalabilidade em um messenger: Porquê não? Ou você acha que não tem gente com 200 contatos?
[]'s

ViniGodoy

Não falei que um messenger não tem que ter escalabilidade. Mas estou perguntando o quão escalavel você quer esse messenger.

Para milhares de contatos falando ao mesmo tempo, só o fato de ter várias Threads rodando já vai matar a aplicação. Controlar isso, somente saindo do Socket e indo para o SocketChannel e usando os Selectors para reduzir o número de Threads.

Depois, estou falando para manter um mapa que identifique a quem pertence cada conexão aberta. Afinal, quando a aplicação identificar que a mensagem é para esse alguém, basta consultar o mapa e encaminhar para a conexão correta. Como mapear para Strings resolve esse problema?

Gerenciar se a conexão está ou não ociosa é um problema que deve ser resolvido por outro trecho da aplicação. Se a aplicação decidir que, por qualquer razão que seja, a conexão deve ser fechada, ela terá que ser retirada desse mapa.

Não entendi o que você dizer com “é muito mais custoso ter uma conexão socket num mapa do que uma String com o endereço do cliente”. O mapa relacionada objetos entre si e, para isso, o java acaba usando referências (ponteiros, de poucos bytes). Do ponto de vista do mapa, não interessa se no mapa está uma String, uma conexão Socket ou uma imagem de 100mb.

Conforme eu disse, o mapa vai atuar sobre as conexões que já existem (afinal é para isso que a aplicação serve), portanto, criar as tais Strings é que seriam um custo a mais.

xgucax

Creio que vc não entendeu e está usando argumentos genéricos
Eu fiz uma pergunta sobre os timeouts para isso. Uma pergunta querendo saber como resolveria, e não um afronte ao que você disse.
Com relação à String no Map, mesmo que sejam apenas refer~encias, uma conexão socket é maior (em bytes) que uma string de mais ou menos 12 caracteres, concorda? Quando perguntei sobre guardar a conexão num mapa estava querendo ver se, não seria melhor, guardar apenas o endereço do cliente junto com sua chave. Assim, toda vez que o servidor necessita-se enviar uma mg, poderia conectar com o cliente de msn (que teria um ServerSocket). Uma idéia, para saber qual seria menos custoso para a aplicação. Não estou nem sequer dizendo que isso seria o certo, estou apenas indagando.
Não sei se interpretei errado seu tom, mas me desculpe se pareceu em algum momento ir contra suas palavras
[]'s

Baldao

Eu acho que fazer a aplicação conectar com o cliente a cada mensagem enviada ficaria pesado, não?

xgucax

Eu não sei. Tipo, Se o cliente assim que conectar-se ao servidor, disparasse uma thread (uma inner class por exemplo) que fosse um Socket esperando as mensagens de volta (as conexões do servidor MSN para ele). Assim, ao invés de termos um objeto em uma única VM que ficasse controlando as conexões, nós separaríamos as conexões em várias VMs (pois cada cliente ficaria esperando a resposta) cabendo ao servidor simplesmente efetuar a conexão quando desejasse mandar a mensagem.

Sei lá, é uma ídeia. Não estou dizendo que está certo desse modo, ou é menos custoso. Só fez lógica para mim

[]'s

Baldao

Eu entendi e também gostei da idéia.
Agora é estudar essas possibilidades e ver qual se encaixa melhor. :thumbup:

ViniGodoy

A idéia é boa, mas infelizmente os sockets não funcionam assim.

A menos que o cliente use um ServerSocket, não tem como o cliente ficar com a conexão aberta, enquanto o servidor só abre quando quiser. Os sockets são canais bidirecionais e, funcionando em IP, mantém a conexão viva. Se um lado fecha, ambos fecham.

Então, sempre que o servidor quisesse, ele seria obrigado a fazer uma reconexão. É como funciona no protocolo HHTP. Cada requisição, uma conexão é feita, o HTML é baixado e a conexão é cortada. A aplicação dele poderia funcionar assim, mas como a fase de conexão pode depender de vários fatores um proxy mal configurado pode deixar as coisas lentas…

Sua idéia pode ser implementada se o cliente tiver um ServerSocket. Nesse caso, o servidor realmente poderia guardar o endereço de cada cliente e os cliente efetivamente ficariam “escutando”.

O servidor também teria um ServerSocket, para receber somente a conexão inicial do cliente, que simplesmente diria: “Eu sou fulano de tal, escuto no endereço tal e na porta tal”. Mas a aplicação ficaria mais sensível a um firewall implementado no lado do cliente e, assim como acontece no emule, talvez os usuários fossem obrigados a liberar certas portas no modem e no windows.

ViniGodoy

Oi… acho que você interpretou errado o meu tom mesmo. Até pq, não tem porque ficar bravo num forum… hehehehe. O duro de colocar texto, é que a gente sempre parece mais nervoso. :wink:

Mas relax, o assunto é técnico, não pessoal. :slight_smile:

As idéias estão interessantes… daqui a pouco a gente pode ir no sourceforge e começar um projeto open source para isso. :lol:

xgucax

Blz cara, tem problema não
quanto à discussão, a idéia seria realmente o cliente ter um ServerSocket. Mas seria muito chato ter que liberar portas na maquina local.
Abraços

Criado 15 de janeiro de 2007
Ultima resposta 18 de jan. de 2007
Respostas 21
Participantes 4