Actualizado el 4 de Marzo del 2020 (Publicado el 14 de Enero del 2017)
929 visualizaciones desde el 14 de Enero del 2017
2,8 MB
26 paginas
Creado hace 19a (30/11/2005)
[Contenido] 1. Intro :: 2. TCP/UDP :: 3. Chat :: 4. Multijugador :: 5. Av.
Índice de Contenidos :.
Introducción General :: 1
TCP Vs UDP :: 2
Cliente/Servidor TCP :: 2.1
Cliente/Servidor UDP :: 2.2
Servidores Multicliente :: 3
Gestión de Sockets en Blender :: 3.1
Implementación de Persistencia :: 3.2
Cliente de Chat en Blender :: 3.3
Diseño Multijugador :: 4
Técnicas de Construcción :: 4.1
Gestión Avanzada :: 5
Sesión 7 :: Transp. 2
[Contenido] 1. Intro :: 2. TCP/UDP :: 3. Chat :: 4. Multijugador :: 5. Av.
Introducción General :.
● Multijugador: Es el área donde se preven más avances.
● Incremento de la adicción debido al componente humano.
● Cómo funciona Internet:
● Red orientada a paquetes; diferentes caminos.
● Tolerante a fallos; se adapta a las propiedades de la red en
cada momento.
● 2 operaciones fundamentales:
● División y Unión de paquetes: TCP.
● Enrutado de los paquetes: IP.
● Opciones:
● Protocolos orientados a la conexión. TCP.
● Protocolos sin conexión. UDP.
Sesión 7 :: Transp. 3
[Contenido] 1. Intro :: 2. TCP/UDP :: 3. Chat :: 4. Multijugador :: 5. Av.
¿Qué es un Socket? :.
● API para aislar la complejidad del trabajo
con redes.
● Similar a acceder a un fichero; "apertura",
"lectura", "escritura"...
● Socket: dispositivo de entrada/salida que
proporciona un canal de comunicación
entre dos computadores.
● Nos proporciona automáticamente el
mecanismo de partición y ensamblado de
los paquetes en el destino.
● Según quién proporcione el servicio a
quién, distinguimos dos tipos de máquinas:
clientes y servidores.
● Pueden utilizar el protocolo TCP o UDP.
Socket
Socket
Sesión 7 :: Transp. 4
[Contenido] 1. Intro :: 2. TCP/UDP :: 3. Chat :: 4. Multijugador :: 5. Av.
TCP
● Orientado a la conexión.
● Paquetes de tamaño variable.
● Garantiza la recepción.
● FIFO.
● Lento.
Aplicaciones
● Juegos con movimientos
esenciales; no se puede perder
datos.
● Estrategia.
● RPGs.
● Tablero
● Etc...
TCP Vs. UDP :.
UDP
● No mantiene la conexión.
● Paquetes de tamaño fijo.
● No garantiza nada.
● En cualquier orden.
● Rápido.
Aplicaciones
● Fundamentalmente juegos en
tiempo real, con alta tasa de
frames por segundo.
● Acción.
● Deportivos.
● Etc...
Sesión 7 :: Transp. 5
[Contenido] 1. Intro :: 2. TCP/UDP :: 3. Chat :: 4. Multijugador :: 5. Av.
Cliente Servidor UDP Mínimo :.
import socket
puerto = 40000
host = "localhost"
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.sendto ("Primer ejemplo del curso.", (host, puerto))
Ver ClienteUDP.py
Ver ServidorUDP.py
import socket
puerto = 40000
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(("", puerto))
print "Esperando tramas..."
while 1:
# Recibimos 1024 bytes en un datagrama
datos, direccion = s.recvfrom(1024)
print "Recibido: ", datos, " desde ", direccion
Sesión 7 :: Transp. 6
[Contenido] 1. Intro :: 2. TCP/UDP :: 3. Chat :: 4. Multijugador :: 5. Av.
Cliente Servidor TCP Mínimo :.
import socket
puerto = 40000
host = "localhost"
s = socket.socket
(socket.AF_INET,
socket.SOCK_STREAM)
# Conectamos con el servidor
# en el puerto indicado
s.connect((host, puerto))
# Enviamos peticion al host
s.send("Hola servidor!\n")
# Recibimos la respuesta del
# servidor (1024 bytes)
respuesta = s.recv(1024)
print respuesta
s.close()
Ver ClienteTCP.py
import socket
puerto = 40000
host = "localhost"
s = socket.socket(socket.AF_INET,
socket.SOCK_STREAM)
s.bind((host, puerto))
# Numero max. de clientes en espera
s.listen(5)
print "Esperando conexiones..."
try:
while 1:
nuevo_sock, dir = s.accept()
print "Conectado desde ", dir
# Bucle para servir a cada cliente
while 1:
datos = nuevo_sock.recv(1024)
if not datos: break
nuevo_sock.send(datos)
nuevo_sock.close()
finally:
s.close()
Ver ServidorTCP.py
Sesión 7 :: Transp. 7
[Contenido] 1. Intro :: 2. TCP/UDP :: 3. Chat :: 4. Multijugador :: 5. Av.
Servidores Multicliente :.
● En escenarios de trabajo reales, se
requieren servidores de, al menos 6-8
jugadores.
● Sin embargo, las primitivas de envío
y recepción por sockets son, por
defecto, bloqueantes.
● Debemos tener en cuenta la gestión
de la conexión únicamente cuando
haya datos que tratar (o no nos
importe quedarnos bloqueados). 2
alternativas:
● Servidores concurrentes.
● Servidores iterativos con primitivas
no bloqueantes.
Sesión 7 :: Transp. 8
[Contenido] 1. Intro :: 2. TCP/UDP :: 3. Chat :: 4. Multijugador :: 5. Av.
Servidores Concurrentes :.
● Lanzamos proceso hijo para cada
conexión aceptada.
● En sistemas UNIX, llamada a Fork, en
sistemas Windows CreateThread.
Pseudocódigo del Servidor
1. Crear el socket y enlazar con bind
el puerto y la dirección IP.
2. Llamada a listen: modo pasivo.
3. Esperamos nueva conexión con
accept.
4. Llegada de una nueva conexión:
Creación de un nuevo proceso/hilo.
4.1. Proceso padre: Volver al paso
3
4.2. Proceso hijo:
nueva conexión.
4.2.1. Bucle send-recv con la
4.2.2. Cuando termine, close()
Socket
Abierto
h3
h1
h2
Sesión 7 :: Transp. 9
[Contenido] 1. Intro :: 2. TCP/UDP :: 3. Chat :: 4. Multijugador :: 5. Av.
Servidores Iterativos :.
● Un único proceso. Nos aseguramos
que no hay bloqueo.
● Bloqueos:
● Pedimos leer antes de que lleguen
los datos.
● Leemos menos de lo esperado.
● Errores, buffers llenos...
Flags interesantes...
● MSG_OOB: Out-Of-Band. Marca especial
del cliente que envía como urgente. Se
extrae de forma individual.
● MSG_PEEK: Permite preguntar en el
socket sobre los datos que contiene sin
leer de él.
Socket
Abierto
Socket NO
Bloqueante
h1
Sesión 7 :: Transp. 10
[Contenido] 1. Intro :: 2. TCP/UDP :: 3. Chat :: 4. Multijugador :: 5. Av.
Un Ejemplo: Servidor de Chat :.
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 4000))
s.setblocking(0)
s.listen(1)
while not terminar: # Hasta que manden un "shutdown"
# Hay conexiones nuevas?
u = ProcesaNuevaConexion()
if u:
lista_usuarios.append(u)
print len(lista_usuarios)," conexion(es)"
for u in lista_usuarios: # Estan los usuarios vivos?
u.Autentificar()
try:
mensaje = u.conexion.recv(1024)
if mensaje:
print "Desde",u.nombre,': ['+mensaje+']'
u.ProcesaMensaje(mensaje)
if mensaje == "shutdown": terminar=1
except: pass
for u in lista_usuarios:
u.conexion.close()
Ver ServidorChat.py
(Fragmento de Código 1/3)
HOST = ''
PORT = 4000
FINLINEA = "\r\n"
lista_usuarios = []
terminar = 0
sPregNombre = 0
sEsperaNombre = 1
sConectado = 2
Sesión 7 :: Transp. 11
[Contenido] 1. Intro :: 2. TCP/UDP :: 3. Chat :: 4. Multijugador :: 5. Av.
Un Ejemplo: Servidor de Chat :.
class Usuario:
def __init__(self):
self.nombre = ""
self.direccion = ""
self.conexion = None
self.estado = sPregNombre
def Autentificar(self):
if self.estado == sPregNombre: self.PreguntaNombre()
def PreguntaNombre(self):
self.conexion.send("Nombre? ")
self.estado = sEsperaNombre
def ProcesaMensaje(self, msg):
print "Procesando mensaje: ",msg
global lista_usuarios
if self.estado == sEsperaNombre: # Estamos esperando el nombre? Lo guardamos
Ver ServidorChat.py
(Fragmento de Código 2/3)
if len(msg) < 2 or msg=="#": return # Quitamos ruido del telnet...
print "Cliente conectado: ",msg
self.nombre = msg
self.estado = sConectado
self.conexion.send("--> Hola, "+self.nombre+" bienvenido"+FINLINEA)
broadcast("--> "+self.nombre+" se ha conectado."+FINLINEA)
return
broadcast("<"+self.nombre+"> "+msg+FINLINEA)
Sesión 7 :: Transp. 12
[Contenido] 1. Intro :: 2. TCP/UDP :: 3. Chat :: 4. Multijugador :: 5. Av.
Un Ejemplo: Servidor de Chat :.
def ProcesaNuevaConexion():
conexion, direccion = s.accept()
return None
try:
except:
print "Conexion desde:", direccion
conexion.setblocking(0)
user = Usuario();
user.conexion = conexion
user.direccion = direccion
return user
Ver ServidorChat.py
(Fragmento de Código 3/3)
def broadcast(msg): # Enviar un mensaje a todos los usuarios conectados
for u in lista_usuarios:
u.conexion.send(msg)
● Implementar en el servidor dos comandos que puedan utilizar los usuarios
del chat; "list", que mostrará (al usuario que lanzó la orden) un listado de la
gente conectada en ese momento y "quit", que desconectará al usuario.
Ejercicio
Sesión 7 :: Transp. 13
[Contenido] 1. Intro :: 2. TCP/UDP :: 3. Chat :: 4. Multijugador :: 5. Av.
Ajustando Blender para usar Sockets :.
● Blender no posee soporte nativo para Sockets.
● En un subdirectorio "lib", dentro de nuestro proyecto, se pueden
incluir librerías de python 2.0 que se deseen utilizar.
● El ejecutable generado funcionará correctamente si incluimos las
DLLs fmod.dll y python20.dll (y se construye con dynamic runtime).
● Ejemplo, introducimos un plano en la escena y se añaden los
siguientes bloques lógicos.
● Importante: Los ficheros
contenidos en la carpeta lib
han sido modificados para
eliminar las dependencias
con otros módulos. No es la
distribución oficial de
sockets Python.
Nombre del script cliente de la
ventana de código
Ver carpeta lib,
client.py, server.py
Soporte de Sockets en Blender
Sesión 7 :: Transp. 14
[Contenido] 1. Intro :: 2. TCP/UDP :: 3. Chat :: 4. Multijugador :: 5. Av.
Problemas de Persistencia... :.
import socket
class miSocket:
class __miSocket:
def __init__(self):
instancia = None
def __init__(self):
self.sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
self.sock.connect(("localhost",4000))
if not miSocket.instancia:
miSocket.instancia = miSocket.__miSocket()
miSocket.instancia.sock.setblocking(0)
pass
else:
def enviar(self, msg):
def recibir(self):
return self.instancia.sock.send(msg)
try:
return self.instancia.sock.recv(1024)
except:
pass
def desconectar(self):
self.instancia.sock.close()
Ver misocket.py
Sesión 7 :: Transp. 15
[Contenido] 1. Intro :: 2. TCP/UDP :: 3. Chat :: 4. Multijugador :: 5. Av.
Cliente de Chat en Blender :.
● Añadimos dos planos a la escena, y
los colocamos pe
Comentarios de: sesión 7 - NetWorking - Sockets: Multijugador (0)
No hay comentarios