Cómo crear un servidor de socket en Python
Los servidores de socket se pueden subdividir en varios tipos, tcp, udp, websocket, todos llaman al módulo de socket, pero existen ligeras diferencias en la implementación específica
Vamos a darle primero una ejemplo de una sala de chat implementada por tcp y udp a través del protocolo socket
Sala de chat de Python (versión python2.7):
Ambos ejecutan server.py y client.py respectivamente. ahora es posible.
Versión TCP: socket-tcp-server.py (servidor):
#-*-?encoding:utf-8?-*-
# socket.getaddrinfo(host,?port,?family=0,?socktype=0,?proto=0,?flags=0)
#Según el parámetro host/puerto dado, la conversión correspondiente a cinco tuplas que contienen una tupla de cinco utilizadas para crear un objeto de socket,
#El parámetro host es el nombre de dominio, proporcionado en forma de cadena para representar una dirección IPV4/IPV6 o Ninguna.
#Parameter Si el puerto está en forma de cadena, representa un nombre de servicio, como "http", "ftp", "email", etc., o es un número, o Ninguno
#La familia de parámetros es la familia del propietario, que puede ser AF_INET?, AF_INET6?, AF_UNIX.
#El parámetro socktype puede ser SOCK_STREAM (TCP) o SOCK_DGRAM (UDP)
# El parámetro proto suele ser 0 y se puede ignorar directamente
#Los indicadores de parámetro son una combinación de AI_*, como AI_NUMERICHOST, que afectará el valor de retorno de la función
#Nota : Pasar Ninguno a los parámetros host y puerto se basa en C, pasando NULL.
#Esta función devuelve una tupla de cinco (familia,?socktype,?proto,?canonname,?sockaddr), y el quinto parámetro sockaddr también es una tupla (dirección,?puerto) p>
#Para obtener más métodos y enlaces, visite
#?Echo?server?program
from?socket?import?*
import ?sys
¿importar?threading
desde?time?import?ctime
desde?time?import?localtime
importar?traceback p>
¿importar?tiempo
importar?subproceso
recargar(sys)
sys.setdefaultencoding("utf8")
HOST='127.0.0.1'
PORT=8555?#Establecer puerto de escucha
BUFSIZ=1024
clase?TcpServer():
def?__init__(self):
self.ADDR=(HOST,?PORT)
prueba:
self.sock= socket(AF_INET ,?SOCK_STREAM)
imprimir?'%d?is?open'?%?PORT
self.sock.bind(self.ADDR)
self .sock.listen(5)
#Establecer condiciones de salida
self.STOP_CHAT=False
#?Todos los clientes que escuchan
self .clients?=?{}
self.thrs?=?{}
self.stops?=?[]
excepto ?Exception,e:
imprimir?"%d?is?down"?%?PORT
return?False
def?IsOpen(ip,? puerto): p>
s?=?socket(AF_INET,?SOCK_STREAM)
prueba:
s.connect((ip,?int(puerto)) )
#?s.shutdown(2)
#?Utilice la función Shutdown() para cambiar la transmisión de datos bidireccional del socket a una transmisión de datos unidireccional. Shutdown() requiere un parámetro separado,
#? Este parámetro indica cómo cerrar el socket. Específicamente: 0 significa prohibir la lectura futura; 1 significa prohibir la escritura futura; 2 significa prohibir la lectura y escritura futuras.
imprimir?'%d?is?open'?%?port
retorno?Verdadero
excepto:
imprimir?' %d?is?down'?%?port
return?False
def?listen_client(self):
mientras?not?self.STOP_CHAT:
print(estás esperando acceso, puerto de escucha:%d'?%?(PORT))
self.tcpClientSock,?self.addr=self.sock.accept ( )
print(u' acepta conexión, dirección del cliente: ', self.addr)
dirección?=?self.addr
# se establecerá Put el enlace client?socket en la lista self.clients
self.clients[address]?=?self.tcpClientSock
#Coloque cada enlace establecido en el proceso respectivamente, reciba y distribuya mensajes
self.thrs[dirección]?=?threading.Thread(target=self.readmsg,?args=[dirección])
self.thrs[dirección ].start( )
time.sleep(0.5)
def?readmsg(self,address):
#Si la dirección no existe, devuelve False
if?address?not?in?self.clients:
return?False
#Obtener el socket del cliente que envió el mensaje
client?=?self.clients[dirección]
mientras?True:
intenta:
#Obtener los datos del contenido del mensaje
data=client.recv(BUFSIZ)
excepto:
print(e)
self.close_client(dirección)
romper
if?not?data:
break
#python3 usa bytes, por lo que debe codificarse
#s='% s La información que me enviaron es: [%s]?%s'?%(addr[0],ctime(),?data.decode('utf8'))
#Formatear la fecha
ISOTIMEFORMAT='%Y-%m-%d?%X'
stime=time.strftime(ISOTIMEFORMAT,?localtime())
El la información que me envió s=u'%s es: %s'?%(str(address),data.decode('utf8'))
#¿Distribuir el mensaje obtenido al cliente de enlace? socket
para?k?in?self.clients:
self.clients[k].send(s.encode('utf8'))
self.clients[k].sendall('sendall:'+s.encode('utf8'))
print?str(k)
print([stime] ,? ':',?data.decode('utf8'))
#Si ingresa quit (ignorando mayúsculas y minúsculas), el programa saldrá
<p>STOP_CHAT=(data.decode('utf8').upper()=="SALIR")
if?STOP_CHAT:
imprimir?"salir"
self.close_client(dirección)
imprimir?"ya?salir"
romper
def?close_client(self,dirección):
pruebe:
client?=?self.clients.pop(dirección)
self.stops.append(dirección)
client.close ()
para?k?in?self.clients:
self.clients[k].send(str(dirección)?+?u"Ya se fue") p>
excepto:
pasar
print(str(dirección)+u'Salido')
if?__name__?== '__main__ ':
tserver?=?TcpServer()
tserver.listen_client() ——————————Hermosa línea divisoria—————— ——— — socket-tcp-client.py? (cliente):
#-*-?encoding:utf-8?-*-
from?socket?import ?* p>
importar?sys
importar?threading
importar?tiempo
recargar(sys)
sys.setdefaultencoding( "utf8")
#Prueba, conéctate a esta máquina
HOST='127.0.0.1'
#Establecer puerto de escucha
PUERTO=8555
BUFSIZ=1024
clase?TcpClient:
ADDR=(HOST,?PORT)
def?__init__( self):
self.HOST?=?HOST
self.PORT?=?PORT
self.BUFSIZ?=?BUFSIZ
#Crear conexión de socket
self.client?=?socket(AF_INET,?SOCK_STREAM)
self.client.connect(self.ADDR)
#Iniciar un hilo y monitorear la información recibida
self.trecv?=?threading.Thread(target=self.recvmsg)
self.trecv.start()
def?sendmsg(self):
# Enviar mensajes de chat en un bucle Si la conexión de socket existe, se repetirá para siempre. Al enviar, cierre el enlace.
while?self .client.connect_ex(self.ADDR):
data=raw_input('>:')
if?not?data:
romper
self.client.send(data.encode('utf8'))
print(u'Enviar información a %s: %s'?%(self.HOST,data ))
si
?data.upper()=="SALIR":
self.client.close()
imprimir?u"Cerrar"
romper
romper
p>
def?recvmsg(self):
#Recibir mensajes Si el enlace siempre existe, continúa escuchando para recibir mensajes.
intenta:
mientras ?self.client.connect_ex(self.ADDR):
data=self.client.recv(self.BUFSIZ)
print(recibiste información de %s: % s'?%(self.HOST,data.decode('utf8')))
except?Exception,e:
print?str(e)
if?__name__?==?'__main__':
client=TcpClient()
client.sendmsg()
Versión UDP: socket-udp -server.py
#?-*-?coding:utf8?-*-
import?sys
¿importar?tiempo
importar?traceback
importar?threading
recargar(sys)
sys.setdefaultencoding(' utf-8')
¿importar?socket
importar?traceback
HOST?=?"127.0.0.1"
PUERTO? =?9555
CHECK_PERIOD?= ?20
CHECK_TIMEOUT?=?15
clase?UdpServer(objeto):
def? __init__(self):
self .clients?=?[]
self.beats?=?{}
self.ADDR?=?(HOST ,PORT)
prueba:
self.sock?=?socket.socket(socket.AF_INET,?socket.SOCK_DGRAM)
self.sock.bind (self.ADDR)#?Vincular al mismo nombre de dominio Todas las máquinas
self.beattrs?=?threading.Thread(target=self.checkheartbeat)
self.beattrs.start ()
excepto?Excepción,e:
traceback.print_exc()
return?False
def?listen_client(self) :
¿mientras? Verdadero:
time.sleep(0.5)
imprimir?"hohohohohoo"
prueba:
recvData,dirección?=?self.sock .recvfrom(2048)
si?not?recvData:
self.close_client(dirección)
break
if?address? in?self.clients:
senddata?=?u"La información que %s me envió es: %s"?%(str(address)
,recvData.decode('utf8'))
if?recvData.upper()?==?"QUIT":
self.close_client(dirección)
if?recvData?==?"HEARTBEAT":
self.heartbeat(dirección)
continuar
si no:
self.clients.append(dirección)
senddata?=?u"El mensaje que %s me envió es: %s"?%(str(dirección),u'ingresó a la sala de chat') p>
para?c?in?self.clients:
pruebe:
self.sock.sendto(senddata,c)
excepto? Excepción,e:
print?str(e)
self.close_client(c)
¿excepto?Excepción,e:
#?traceback.print_exc()
print?str(e)
pasar
def?heartbeat(self,dirección):
self.beats[dirección]?=?time.time()
def?checkheartbeat(self):
mientras?True:
imprimir? checkheartbeat"
imprimir?self.beats
prueba:
para?c?in?self.clients:
imprimir? tiempo .time()
imprimir?self.beats[c]
if?self.beats[c]?+?CHECK_TIMEOUT? print?u"%s latido se agotó y la conexión se desconectó"?%str(c) self.close_client(c) else: print?u"checkp%s, sin desconexión"?%str(c) excepto?Exception,e: traceback.print_exc() imprimir?str(e) pasar tiempo.sleep(CHECK_PERIOD) def?close_client(self,dirección): pruebe: if?address?in?self.clients: self.clients.remove(dirección) if?self.beats. has_key(dirección): del?self.beats[dirección] imprimir?self.clients para?c?in?self.clients: self.sock.sendto(u'%s se ha ido'?%?str(dirección),c) print(str(dirección)+u'ha salido') excepto?Excepción,e: print?str(e) raise if?__name__?==?"__main__ " : ud pServer?=?UdpServer() udpServer.listen_client() ——————————Hermosa línea divisoria—————————— socket-udp-client.py: #?-*-?coding:utf8?-*- import?sys importar?threading importar?time recargar(sys) sys.setdefaultencoding('utf-8') importar ?socket HOST?=?"127.0.0.1" PORT?=?9555 #BEAT_PORT?=?43278 BEAT_PERIOD?=?5 clase?UdpClient(objeto): def?__init__(self): self.clientsock?=?socket.socket ( socket.AF_INET,socket.SOCK_DGRAM) self.HOST?=?HOST self.ADDR?=?(HOST,PORT) self. .sendto(u'Solicitud para establecer un enlace',self.ADDR) self.recvtrs?=?threading.Thread(target=self.recvmsg) self.recvtrs. start () self.hearttrs?=?threading.Thread(target=self.heartbeat) self.hearttrs.start() def?sendmsg ( self): mientras?True: datos?=?raw_input(">:") si?no?datos: romper self.clientsock.sendto(data.encode('utf-8'),self.ADDR) if?data.upper()?==? ' SALIR': self.clientsock.close() romper def?heartbeat(self): mientras?True : self.clientsock.sendto('HEARTBEAT',self.ADDR) time.sleep(BEAT_PERIOD) def?recvmsg(self): p> mientras?True: recvData,addr?=?self.clientsock.recvfrom(1024) si?no?recvData: break print(u' recibió información de %s: %s'?%(self.HOST,recvData.decode('utf8'))) si?__nombre__? ==?"__main__": udpClient?=?UdpClient() udpClient.sendmsg()