Hola a todos! Me animo a poner un programa que he hecho estando en prácticas de una FP y bueno, quiero que me digan la porquería que sobra, y, también, mejores formas de hacer lo que yo hice.
Sólo lo he probado en local, no se si funcionaría fuera. Ya lo probaré. De momento con que me digan que mejorar y que sobra, me vale.
Clase Cliente:
Clase servidor:
Sólo lo he probado en local, no se si funcionaría fuera. Ya lo probaré. De momento con que me digan que mejorar y que sobra, me vale.
Clase Cliente:
Código (vbnet) [Seleccionar]
'Chat V1.0.
'Formulario cliente.
'Creado por Alejandro Cuenca.
'El código se puede usar, reutilizar o lo que consideren, aunque es el primero
'que hago y valdrá de poco. Recuerden agradecer, sólo eso.
Imports System.IO
Imports System.Net.Sockets
Imports System.Threading
Imports System.Text
Public Class Cliente
#Region "VARIABLES"
Dim TCPCli As TcpClient 'Puerto e IP de conexion al servidor.
Dim thread As Thread 'Para recibir mensajes del servidor.
Dim stm As NetworkStream 'Datos que recibo del servidor.
Dim bufferLectura() As Byte 'Donde guardare los mensajes recibidos del servidor.
#End Region
#Region "BOTONES"
Private Sub btnConectar_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnConectar.Click
'Me conecto al servidor.
TCPCli = New TcpClient
'Envio un mensaje con el nick.
'Dim bufferEscritura() As Byte
Try
'Me conecto al servidor con IP y Puerto.
TCPCli.Connect(txtIP.Text, CType(txtPort.Text, Integer))
'Inicializo el array.
'bufferEscritura = New Byte(100) {}
'Si se ha conectado lo muestro, y si no, tambien.
If TCPCli.Connected = True Then
'Con getStream obtengo la red en la que estoy.
stm = TCPCli.GetStream
'Escribo en el RichTextBox.
rtbConversacion.Text = rtbConversacion.Text & "Conexion realizada. Conectado a " & txtIP.Text & "." & vbCrLf
'Mando el nick.
Dim outStream As Byte() = System.Text.Encoding.ASCII.GetBytes(txtNick.Text + "$")
stm.Write(outStream, 0, outStream.Length)
stm.Flush()
'Inicio un thread llamando al metodo recibirMensaje para escuchar lo que llega del servidor y mostrarlo.
thread = New Thread(AddressOf recibirMensaje)
thread.Start()
'Activo los controles para enviar mensajes.
txtTexto.Enabled = True
btnEnviar.Enabled = True
rtbConversacion.Enabled = True
Else
rtbConversacion.Text = rtbConversacion.Text & "Conexion fallida." & vbCrLf
End If
Catch ex As Exception
rtbConversacion.Text = rtbConversacion.Text & "Error en la conexion" & vbCrLf
End Try
End Sub
Private Sub btnEnviar_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnEnviar.Click
'Defino el array de bytes para enviar el mensaje al servidor.
Dim bufferEscritura() As Byte
Dim aux As Boolean = True
While aux
Try
bufferEscritura = New Byte(10000) {}
'Si el texto empieza por '.', salgo del programa.
If txtTexto.Text = "." Then
terminarConexion()
Else
'Lo codifico para enviarlo.
bufferEscritura = Encoding.ASCII.GetBytes(txtTexto.Text)
'Escribo en el RichTextBox el mensaje que acabo de enviar.
rtbConversacion.Text = rtbConversacion.Text & Chr(13) & "Usted dice: " & Encoding.ASCII.GetString(bufferEscritura) & Chr(13)
stm.Write(bufferEscritura, 0, bufferEscritura.Length)
'Me situo al final del RichTextBox
rtbConversacion.SelectionStart = rtbConversacion.TextLength
rtbConversacion.ScrollToCaret()
txtTexto.Text = ""
txtTexto.Focus()
End If
Catch ex As Exception
rtbConversacion.Text = rtbConversacion.Text & "Error al enviar datos" & vbCrLf
End Try
aux = False
End While
End Sub
#End Region
#Region "METODOS"
Private Sub recibirMensaje()
While True
Try
bufferLectura = New Byte(10000) {}
stm = TCPCli.GetStream
'Me quedo esperando a que llegue algun mensaje, y lo leo.
stm.Read(bufferLectura, 0, bufferLectura.Length)
escribir()
Catch ex As Exception
Exit Sub
End Try
End While
End Sub
Private Sub terminarConexion()
Me.Close()
End Sub
Private Sub txtTexto_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles txtTexto.KeyPress
If e.KeyChar = Chr(13) Then
e.Handled = True
Else
e.Handled = False
End If
End Sub
Private Sub escribir()
'Variables para dividir el mensaje entre el nick y el mensaje.
Dim men As String
Dim nom As String
Dim todo As String
If Me.InvokeRequired Then
Me.Invoke(New MethodInvoker(AddressOf escribir))
Else
Try
'Obtengo el mensaje enviado con todos los datos.
todo = Encoding.ASCII.GetString(bufferLectura)
'Si es un '.', es que el nick ya se ha elegido.
If todo.Substring(0, todo.LastIndexOf(Chr(46)) + 1) = "." Then
txtNick.Text = ""
rtbConversacion.Text = rtbConversacion.Text & Chr(13) & "El nick ya existe, elija otro." & Chr(13)
Else
'Si no es un punto, divido el mensaje en texto y remitente.
men = todo.Substring(todo.IndexOf(Chr(93)) + 1, todo.LastIndexOf(Chr(91)) + 1)
nom = todo.Substring(0, todo.IndexOf(Chr(93)))
'Escribo en el RichTextBox el mensaje reenviado del servidor.
rtbConversacion.Text = rtbConversacion.Text & Chr(13) & nom & " dice: " & men & Chr(13)
End If
Catch ex As Exception
'Si no puede asignar nom a nada, es porque el mensaje es del servidor.
rtbConversacion.Text = rtbConversacion.Text & Chr(13) & "Servidor dice: " & todo & Chr(13)
End Try
End If
End Sub
Private Sub Cliente_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
'Declare an array of processes
Dim myProcesses() As Process
'single process variable
Dim myProcess As Process
'Get the list of processes
myProcesses = Process.GetProcesses()
'Iterate through the process array
For Each myProcess In myProcesses
If myProcess.ProcessName = "TCPCient" Then
myProcess.Kill()
End If
Next
End Sub
#End Region
End Class
Clase servidor:
Código (vbnet) [Seleccionar]
'Chat V1.0.
'Formulario servidor.
'Creado por Alejandro Cuenca.
'El código se puede usar, reutilizar o lo que consideren, aunque es el primero
'que hago y valdrá de poco. Recuerden agradecer, sólo eso.
Imports System.IO
Imports System.Net.Sockets
Imports System.Threading
Imports System.Text
Public Class Servidor
#Region "VARIABLES"
Dim clientSocket As TcpClient
Dim tcpLis As TcpListener 'Creamos el listener para oir un puerto determinado.
Dim clientes As New Hashtable 'Creamos una coleccion con los clientes que se conectan.
Dim thread As Thread 'Creamos un thread para recibir mensajes de los clientes.
Dim clienteActual As Net.IPEndPoint 'Guardamos la informacion de un cliente para abrir o cerrar la conexion.
Dim cli As infoCliente 'Guardamos el cliente actual.
#End Region
#Region "ESTRUCTURAS"
Private Structure infoCliente
Public sock As Socket 'Socket utilizado para mantener la conexion con el cliente
Public thre As Thread 'Thread utilizado para escuchar al cliente
Public ultimosDatos As String 'Ultimos datos enviados por el cliente
Public nombre As String 'Nombre utilizado en el server.
End Structure
#End Region
#Region "METODOS"
Private Sub esperarCliente()
Dim infoClienteActual As infoCliente = Nothing
Dim bufferLectura() As Byte
With infoClienteActual
While True
clientSocket = tcpLis.AcceptTcpClient
'Cuando se recibe la conexion, guardo la informacion del cliente.
bufferLectura = New Byte(10000) {}
'El socket.
.sock = clientSocket.Client
clienteActual = .sock.RemoteEndPoint 'Aqui guardamos su EndPoint, que sera la clave del hashtable.
'Obtenemos el nick.
Dim networkStream As NetworkStream = clientSocket.GetStream()
networkStream.Read(bufferLectura, 0, CInt(clientSocket.ReceiveBufferSize))
.nombre = System.Text.Encoding.ASCII.GetString(bufferLectura)
.nombre = .nombre.Substring(0, .nombre.IndexOf("$"))
'Luego el thread.
.thre = New Thread(AddressOf leerCliente) 'Este thread escucha los mensajes del cliente.
'Asignamos al cliente que acaba de entrar a la variable global cli.
cli = infoClienteActual
'Guardamos en el hashtable los datos del cliente. Usamos synclock para que se ejecute solo eso.
SyncLock Me
'Compruebo si ya exite el nick.
comprobarNick()
'Si no existe el nick, lo guardo en el hashtable.
If cli.nombre <> Nothing Then
clientes.Add(clienteActual, infoClienteActual)
'Iniciamos la escucha.
.thre.Start()
'Lleno el listbox con los clientes.
llenarlistbox()
'Muestro un mensaje de conexion en el servidor.
joined()
End If
End SyncLock
End While
End With
End Sub
Private Sub leerCliente()
Dim IDReal As Net.IPEndPoint 'ID del cliente que envia algo para leer.
Dim bufferLectura() As Byte 'Aqui se guardara el mensaje que llega.
Dim infoClienteActual As infoCliente 'Aqui se guardara la informacion del cliente.
Dim ret As Integer 'Aqui se guarda la longitud del mensaje.
IDReal = clienteActual 'Guardamos el cliente actual.
infoClienteActual = clientes(IDReal) 'Obtenemos los datos de la coleccion que corresponden a ese cliente.
'Con el cliente seleccionado de la coleccion, obtenemos el mensaje.
With infoClienteActual
While True
'Si el socket esta conectado, leo el mensaje.
If .sock.Connected Then
bufferLectura = New Byte(100) {}
Try
'Me quedo esperando a que llegue un mensaje desde el cliente
ret = .sock.Receive(bufferLectura, bufferLectura.Length, SocketFlags.None)
If ret > 0 Then
'Guardo el mensaje recibido
.ultimosDatos = Encoding.ASCII.GetString(bufferLectura)
clientes(IDReal) = infoClienteActual
'Guardo el cliente actual para usar el nick y el mensaje.
cli = infoClienteActual
'Se recibe el mensaje y se muestra en el RichTextBox.
escribirMensaje()
'Reenvio el mensaje a los usuarios para que reciban lo que dicen los demas usuarios.
reenviarMensaje()
Else
'Genero el evento de la finalizacion de la conexion
'RaiseEvent ConexionTerminada(IDReal)
Exit While
End If
Catch ex As Exception
If Not .sock.Connected Then
'Genero el evento de la finalizacion de la conexion
cerrarThread(infoClienteActual.sock)
Exit While
End If
End Try
End If
End While
End With
End Sub
Private Sub llenarlistbox()
Dim cliente As infoCliente
'Si el metodo no puede controlar el listbox, se hace el invoke y luego va al else.
If Me.InvokeRequired Then
Me.Invoke(New MethodInvoker(AddressOf llenarlistbox))
Else
lstUsuarios.Items.Clear()
lstUsuarios.Items.Add("USUARIOS")
For Each cliente In clientes.Values
lstUsuarios.Items.Add(cliente.nombre)
Next
End If
End Sub
Private Sub escribirMensaje()
'Si el metodo no puede controlar el richtextbox, se hace el invoke y luego va al else.
If Me.InvokeRequired Then
Me.Invoke(New MethodInvoker(AddressOf escribirMensaje))
Else
rtbConversacion.Text = rtbConversacion.Text & Chr(13) & cli.nombre & " dice: " & cli.ultimosDatos
End If
End Sub
Private Sub joined()
'Si el metodo no puede controlar el richtextbox, se hace el invoke y luego va al else.
If Me.InvokeRequired Then
Me.Invoke(New MethodInvoker(AddressOf joined))
Else
rtbConversacion.Text = rtbConversacion.Text & cli.nombre & " se ha unido a la sala." & Chr(13)
End If
End Sub
Private Sub reenviarMensaje()
'Creamos un cliente para recorrer la coleccion.
Dim cliente As infoCliente
Dim men As String
If Me.InvokeRequired Then
Me.Invoke(New MethodInvoker(AddressOf reenviarMensaje))
Else
'Men sera el mensaje a enviar.
men = cli.nombre & Chr(93) & cli.ultimosDatos.Trim() & Chr(91)
For Each cliente In clientes.Values
If cliente.nombre <> cli.nombre AndAlso cliente.sock.RemoteEndPoint.ToString <> cli.sock.RemoteEndPoint.ToString Then
cliente.sock.Send(Encoding.ASCII.GetBytes(men))
End If
Next
End If
End Sub
Private Sub comprobarNick()
'Creo un cliente para recorrer la coleccion.
Dim cliente As infoCliente
Dim men As String
'If Me.InvokeRequired Then
' Me.Invoke(New MethodInvoker(AddressOf comprobarNick))
'Else
'Men es el mensaje a enviar.
men = Chr(46) & Chr(1)
For Each cliente In clientes.Values
If cliente.nombre = cli.nombre Then
cli.sock.Send(Encoding.ASCII.GetBytes(men))
'Si se ha encontrado el nombre del cliente en la coleccion, mando un mensaje determinado y pongo cli a nothing
'para no guardar nada en el hashtable.
cli.nombre = Nothing
Exit Sub
End If
Next
'End If
End Sub
Private Sub cerrarThread()
Dim cliente As infoCliente
'Cierro el thread que se encargaba de escuchar a cada cliente.
Try
For Each cliente In clientes.Values
cliente.thre.Abort()
Next
Catch ex As Exception
Exit Sub
End Try
End Sub
Private Sub cerrarThread(ByVal socket As Socket)
'Cierro el thread que le corresponde al cliente que abandona la sala.
Dim cliente As infoCliente
Try
For Each cliente In clientes
If cliente.sock.ToString = socket.ToString Then
cliente.thre.Abort()
'Lo borro de la coleccion.
clientes.Remove(socket.RemoteEndPoint)
End If
Next
Catch ex As Exception
Exit Sub
End Try
End Sub
#End Region
#Region "BOTONES"
Private Sub Servidor_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
cerrarThread()
'Declare an array of processes
Dim myProcesses() As Process
'single process variable
Dim myProcess As Process
'Get the list of processes
myProcesses = Process.GetProcesses()
'Iterate through the process array
For Each myProcess In myProcesses
If myProcess.ProcessName = "TCPServer" Then
myProcess.Kill()
End If
Next
End Sub
Private Sub Servidor_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'En el load, asignamos el puerto de escucha.
tcpLis = New TcpListener(6666)
'Iniciamos la escucha.
tcpLis.Start()
'Creo un thread para que se quede escuchando la llegada de un cliente.
thread = New Thread(AddressOf esperarCliente)
thread.Start()
rtbConversacion.Text = rtbConversacion.Text & "CHAT" & Chr(13)
End Sub
Private Sub btnEnviar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnEnviar.Click
Dim cliente As infoCliente
'Mando el mensaje a cada cliente de la coleccion.
For Each cliente In clientes.Values
cliente.sock.Send(Encoding.ASCII.GetBytes(txtTexto.Text))
Next
txtTexto.Text = ""
End Sub
#End Region
End Class