Multiplas Conexões Tcp - .NET - Fórum Script Brasil
Multiplas Conexões Tcp
gente, eu estou aprendendo agora vb.net e estou tentando fazer um servidor que aceite multiplas conexões. Bom eu consegui fazer o servidor conectar a um cliente, mas não consegui de jeito nenhum fazer multiplos clientes conectarem.
Eu até dei uma pesquisada no forum e achei algumas referencias sobre esse assunto, mas como ainda estou aprendendo, elas geraram mais duvidas que soluções.
Aqui está o codigo que utilizei para conectar o cliente e o servidor...
Listener = New TcpListener(addr, port)
'aceita conexão e configura
Connection = Listener.AcceptSocket()
StreamOut = New BinaryWriter(socketStream)
StreamIn = New BinaryReader(socketStream)
StreamOut.Write("Conexão Sucedida")
como faço para o servidor aceitar multiplas conexões e saber diferencia-las uma da outra?
Ao fazer...
... você está aceitando a conexão e jogando a mesma para o objeto Connection. Se você fizer isso uma segunda vez, estará gerando *outra* conexão e assim por diante. Ou seja, cada objeto refere-se a uma conexão. Ou seja, fazendo um loop, você poderia aceitar múltiplas conexões. É interessante também usar o parâmetro backlog do método Start do seu objeto Listener para definir a quantidade de conexões pendentes (aguardando para serem aceitas).
aí gray,
vlw pela resposta, mas ainda to com problema..
o servidor está ate aceitando multiplas conexões... mas como eu faço para pode comunicar com os clientes conectados. porque quando uma pessoa conecta, o servidor envia msg atraves do objeto streamout... só que quando uma outra conecta, as duas conexão param de receber as msg enviadas pelo streamout...
eu pensei então que talvez se eu fizesse um array com o streamout para cada conexão desse, mas também não funcionou não :(
Você está realmente utilizando objetos diferentes ou você está reaproveitando o mesmo objeto? Porque se for o segundo o caso, você vai estar perdendo a conexão anterior. E sim, a idéia é justamente usar uma estrutura de lista (como uma ArrayList) para guardar as conexões a fim de que depois você possa se comunicar com os clientes.
bom, o objeto para enviar já esta em um array e funciona.. o problema é para receber...
IncomeMessage = StreamIn.ReadString()
Explode = Split(IncomeMessage, "|")
Select Case (Explode(0))
For X = 1 To (iUsers - 1)
StreamOut(X).Write(IncomeMessage)
StreamOut(X).Flush()
ai desse jeito, enquanto apenas 1 usuario estivesse enviando, estava tudo bem, mas quando um outro enviava uma mensagem também, então a conexão era perdida. ai você falo pra coloca num array, e fiz isso, mas do jeito que eu fiz só "quase" funcionou... coloquei o "streamin" num array também, e para receber substitui
for y = 1 to (iusers -1)
IncomeMessage = StreamIn(y).ReadString()
bom, desse jeito, as vezes funcionava, as vezes não.. tinha mensagens que não chagavam, ai quando mandava uma outra, era a antiga que chegava...
bom, se não da pra usar o for pra verificar cada campo do array, como eu faço para verificar se um cliente mandou uma msg?
No caso, uma das maneiras seria iniciar vários processos (threads), sendo um para cada cliente e no qual haveria o loop para o recebimento dos dados. Eu comecei a escrever um P2P (peer-to-peer, tipo eMule, KaZaA, etc.), em VB2005, no qual utilizei justamente essa técnica.
bom, to quase lá :D
eu tentei fazer o que você falou, mas surgiu um ultimo problema (pelo menos espero que seja)... eu criei uma thread para cada usuario que conectar.
só que na hora de receber, eu criei uma variavel que a cada thread vai aumentando em 1, para ir acompanhando as novas threads e ser o "numero" do usuario para receber... o problema é que quando eu aumento essa variavel, aumenta ela em todas as threads e acaba dando na mesma :P
como eu faço então pra fazer uma variavel, num array de threads, que vai aumentando, mas não aumenta em todas as threads, só na que ele foi "aumentado"?
Você pode declará-la como estática (Static) a fim de que seu valor seja lembrado para aquela rotina específica. Ou melhor ainda, crie uma classe representando o usuário conectado (ao qual você pode atribuir um número, se quiser).
esta funcionando agora :D
bom, com a ajuda do Graymalking, eu consegui resolver meu problema de multiplas conexoes e ficou otimo... só ficou um problema... toda vez que uma pessoa nova conecta cria um usuario novo ela ao invés de reutilizar uma conexão livre, ela cria uma nova... ai o nº total de usuarios só vai aumentando infinitamente...
ai eu fiz um codigo que procura pelo numero de uma conexão fechada e utiliza ela para a proxima conexão... o problema é que não estou conseguindo passar esse numero para dentro das threads das conexões... antes eu tinha feito como o gray falou, declarei ela static e tava funcionando.. mas só estava funcionando porque como a cada conexao nova, simplesmente aumentava o valor de conexões +1, era só aumentar +1 ao "numero da conexao"... agora esse numero pode variar e como já disse, não to conseguindo pegar ele...
bom, vo posta aqui como tentei...
codigo para receber conexoes
Connection(SocketLivre) = Listener.AcceptSocket()
socketStream(SocketLivre) = New NetworkStream(Connection(SocketLivre))
StreamOut(SocketLivre) = New BinaryWriter(socketStream(SocketLivre))
StreamIn(SocketLivre) = New BinaryReader(socketStream(SocketLivre))
SetText(iUsers)
'inicia threads para comunicação
ConThread(SocketLivre) = New Thread(AddressOf PlayersIO)
ConThread(SocketLivre).Start()
Dim AchouLivre As Boolean = False
'acha socket livre
If (iUsers > 1) Then
For Z = 1 To iUsers
If (Connection(Z).Connected = False) Then
SocketLivre = Z
AchouLivre = True
'não faz nada...
'se não achar, adiciona novo usuario
If (AchouLivre = False) Then
iUsers += 1
SocketLivre = iUsers
codigo das threads
Public Sub PlayersIO()
Dim InnerThread As Short
InnerThread = SocketLivre - 1
alguém sabe me ajuda?? vlw :D
Você não deveria procurar o socket livre *antes* de aceitar a conexão (para poder justamente usá-lo para tal fim)?
com certeza... mas o que eu reparei era o seguinte: no loop para aceitar conexões, se eu colocava uma msgbox antes da linha "Connection(SocketLivre) = Listener.AcceptSocket()" a msg aparecia na hora de carregar o programa.. se eu colocava depois, a msg só aparecia na hora que recebia uma conexão..
então eu conclui que no loop, ao chegar em "Connection(SocketLivre) = Listener.AcceptSocket()", ele parava o loop e ficava esperando ate receber uma conexão para continuar...
ai acabo que deu na mesma se eu coloco para procurar antes ou depois, porque mesmo eu colocando antes, depois que receber a 1 conexão, ele já vai preparar a 2 segunda conexão como não tendo ninguém... eu só coloquei pra procurar a conexao depois de aceitar porque tava fazendo testes e fico assim minha ultima tentativa (que o resultado deu exatamente o mesmo quando coloquei pra procurar antes)
Entendi mais ou menos. Sendo que num contexto de múltiplas conexões, existe diferença entre procurar antes ou depois de aceitar a conexão.
aew... bom, acho que to quase la :blink:
agora eu só não to sabendo fechar as conexões para que elas sejam reutilizadas por outros usuarios..
SocketLivre = CShort(Z)
iUsers = CShort(iUsers + 1)
ConThread(SocketLivre).Start(SocketLivre)
e para fechar a conexão
Connection(QualThread).Close()
socketStream(QualThread).Close()
StreamOut(QualThread).Close()
StreamIn(QualThread).Close()
ConThread(QualThread).Abort()
eu na verdade não tinha muito ideia de como fazer para fechar as conexões então tentei desse jeito ai em cima.. mas assim não funciona.. qual o jeito correto de fazer isso?