primero que nada quisiera aclarar que este post vendría a ser la "segunda parte" de este
protocolo_binario_tcCB.html
este explicaba como enviar un paquete desde el servidor al cliente a un index(usuario, cliente) específico, yo ahora les voy a explicar como enviar un paquete desde el cliente al servidor, de distintas formas, voy a tratar de ser lo más explicativo posible
primero que nada tenemos que saber 2 cosas
1º : Hay un enum donde se guardan todos los ID(Identificadores) de los paquetes que se envian desde el cliente al servidor, el mismo está en ambos lados(cliente-servidor) llamado "Private Enum ClienTpacketid".
2º : La información que enviamos desde el cliente al servidor, se envia por funciones que están dentro de una clase (clsByteQueue) y el cliente la usa como "outgoingdata" para enviar paquetes y "incomingdata" para recibirlos.
vamos a ejemplificar esto, lo primero que debemos hacer es en el enum que aclaré anteriormente agregar un nuevo identificador , para hacer esto nos vamos al cliente y buscaremos
- Private Enum ClientPacketID
y ahí dentro ubicaremos un nuevo paquete , al cual le pondremos
tiene que ser obviamente antes del "End Enum"
ahora que ya tenemos declarado el identificador, vamos a crear una rutina que envie al servidor datos.
al final del módulo protocol.bas pondremos esto
- Public Sub Prueba()
- call outgoingdata.writebyte(clientpacketid.Prueba)
- call outgoingdata.writeasciistring("Esto es una prueba!")
- end sub
NOTA: Por cuestiones de prolijidad se le pone un "Write" adelante del nombre de la rutina y seguido el nombre del paquete, pero podemos usar el que nos guste.
aquí les explicaré más o menos que hicimos en esta rutina(sub)
- call outgoingdata.writebyte(clientpacketid.Prueba)
con esto le enviamos al servidor(mediante outgoingdata) el packetID , que el servidor recibirá y hará lo que nosotros le indiquemos.
- call outgoingdata.writeasciistring("Esto es una prueba!")
con esto le enviamos una cadena de carácteres (string) al servidor, en este caso sería "Esto es una prueba!"
con esto listo, nos posicionamos en el servidor, y haremos lo siguente.
Buscaremos el enum "Private Enum ClientPacketID", y agregaremos antes del end enum , y presten atención : SIEMPRE TIENE QUE TENER EL MISMO ORDEN TANTO EN CLIENTE-SERVIDOR NUESTRO PAQUETE IDENTIFICADOR, por cuestiones que explicaré más abajo.
bueno, agregamos en el mismo orden que en el cliente
ahora el servidor ya sabrá que hay un nuevo packetID, pero... si ya lo sabe, tiene que realizar una acción cuando lo recibe.. y para lograr esto necesitamos dirigirnos al :
- Private Sub HandleIncomingdata(byval userindex as integer)
ahí es donde se "maneja"(handle) , la "información"(data) , "entrante"(incoming), buscaremos donde está el ..
- Select Case PacketID
ahí tenemos donde el servidor al recibir 1 "Identificador" realizará lo que nosotros le indiquemos, abajo de el select case agregaremos
- case clientpacketid.Prueba
- call prueba(userindex)
NOTA: acá es lo mismo que el cliente , frecuentemente para la comprensión y prolijidad del código se le suele agregar un "Handle" y seguido el nombre del paquete, aunque también podemos usar el nombre que nos guste.
bueno, ahí ya el servidor sabe que al recibir X identificador, tiene que llamar a x rutina, y ahora, nos falta hacer esta rutina(sub) y hacer lo que nos guste, al final del módulo protocol.bas, agregaremos
ATENCIÓN: En los paquetes que tengan "cadenas de carácteres, texto" (strings) se recomienda usar el "buffer auxiliar", para manejar estos datos, pero no se podrá cerrar la rutina sin realizar el copiado del buffer, más información encontraran en este aporte(gracias ArzenaTh)
por_que_nunca_usar_exit_sub_en_paquetes_que_contengan_datos_adicionales_tcJF.html
bueno siguendo con lo que estabamos haciendo , al final del módulo protocol pondremos
acá les dejaré 2 formas de manejar nuestra data.
primera forma y más recomendada en paquetes qe contienen strings
- Private Sub Prueba(byval Indice as integer)
- Dim Bufer as new clsbytequeue 'declaramos el buffer auxiliar que usaremos
- call bufer.copybuffer(userlist(indice).incomingdata) 'acá hacemos un copiado de nuestros datos
- call bufer.readbyte 'acá borraremos de la memoria el byte identificador.
- dim MiCadena as string 'en esta variable guardaremos el string que nos mandó el cliente.
- micadena = bufer.readasciistring 'borramos de la memoria el string que envió el cliente, y lo guardamos en una variable para utilizarlo.
- 'LISTO, Ya tenemos la memoria del bufer vacia, a partir de acá haremos lo que quisieramos con nuestro string recibido
- '******************* esto tiene que estar antes del end sub
- call userlist(indice).incomingdata.copybuffer(bufer) 'si llegó el paquete entero, y no hubo error alguno, destruiremos el bufer.
- end sub
de esa forma(la más recomendada) lograremos recibir nuestros datos, ahora la segunda opción
- Private Sub Prueba(byval userIndex as integer)
- call userlist(userindex).incomingdata.readbyte 'borraremos de la memoria el byte identificador.
- dim cadena as string 'en esa variable nos guardamos lo que nos envió el cliente.
- cadena = userlist(userindex).incomingdata.readasciistring 'guardamos en la variable, y removemos de la memoria el string
- ' APARTIR DE ACA HASTA EL END SUB, HAREMOS LO QUE NOS GUSTE.
- end sub
con las 2 formas lograremos lo mismo, pero la primera se recomienda más por que si hay un error(no llegan completos los datos , etc) no revienta todo, cosa que sí pasaría con la segunda(opción).
listo, tan simple como eso ya tenemos una comunicación entre un cliente y el servidor
ahora voy a aclarar diversas cosas :
1 : para enviar datos de diferente tipo, byte/integer/long/double/single, en el cliente usaremos
call outgoingdata.writeTIPODEDATO(valor)
cambiando tipodedato por byte/integer/long/double/single y "valor" por lo que queremos enviarle al servidor.
2 : Esto es muy importante, jamás , de ninguna forma podemos tener siquiera 1 PAQUETE que no esté en la misma posición(en el enum) tanto en cliente-servidor, por esto que voy a explicar.
calculemos que tenemos esto así
En el clientpacketid del cliente tenemos
abajo de este paquete
- LoginNewChar 'NLOGIN
tenemos el nuestro
y en el servidor en el enum clientpacketid
tenemos arriba de este paquete
- LoginNewChar 'NLOGIN
el nuestro
entonces, que pasaría si hacemos esto?, fácil, el enum clientpacketid(como todos los ENUMs que no inician desde un valor) , el primer paquete es 0, el segundo es 1 el tercero 2 y así.
entonces tenemos en el cliente
- Private Enum ClientPacketID
- LoginExistingChar 'OLOGIN
- ThrowDices 'TIRDAD
- LoginNewChar 'NLOGIN
- Prueba
y en el servidor
- Private Enum ClientPacketID
- LoginExistingChar 'OLOGIN
- ThrowDices 'TIRDAD
- Prueba
- LoginNewChar 'NLOGIN
entonces quedaria así
cliente :
loginexistingchar = identificador 0
throwdices = identificador 1
loginnewchar = identificador 2
prueba(nuestro paquete id) = identificador 3
servidor:
loginexistingchar = identificador 0
throwdices = identificador 1
prueba(nuestro paquete id) = identificador 2
loginnewchar = identificador 3
ahora cuando nosotros hacemos esto
- call outgoingdata.writebyte(clientpacketid.prueba)
le estamos enviando al servidor un identificador(numero) que sería un 3, hasta acá todo bárbaro, el problema radica cuando...
el servidor recibe ese "3" y lo maneja como si fuera el "loginexistingchar"(que es el 3 para el servidor), osea , esto ocurre cuando hay un desorden y el cliente al enviar un 3 y el server recibirlo y manejarlo como un paquete que no es el que se espera, el protocolo revienta(si se escriben más/menos datos de los que el servidor espera) o simplemente si no enviamos datos adicionales, hará lo inverso, calculemos que tenemos invertido en el cliente y servidor el paquete de meditar, al enviar nuestro paquete "prueba", el servidor nos expulsará , dado a que el servidor no está esperando un "string"
bueno, espero que les halla gustado
cualquier crítica/comentario/correción que sea productivo para el tema es totalmente aceptado!




801 ![Dragon Ancestral [1] Dragon Ancestral [1]](./images/ranks/Rango30.gif)
![Aprendiz [2] Aprendiz [2]](./images/ranks/Rango7.gif)



![Dragon Ancestral [2] Dragon Ancestral [2]](./images/ranks/Rango31.gif)

![Destructor de Mentes [3] Destructor de Mentes [3]](./images/ranks/Rango15.gif)

![Destructor de Mentes [12] Destructor de Mentes [12]](./images/ranks/Rango24.gif)


![Oraculo [5] Oraculo [5]](./images/ranks/Rango29.gif)



![Destructor de Mentes [6] Destructor de Mentes [6]](./images/ranks/Rango18.gif)


![Dragon Ancestral [6] Dragon Ancestral [6]](./images/ranks/Rango35.gif)




![Oraculo [2] Oraculo [2]](./images/ranks/Rango26.gif)
![Newbie [5] Newbie [5]](./images/ranks/Rango4.gif)
![Newbie [1] Newbie [1]](./images/ranks/Rango0.gif)
