socket servidor redes programacion para hilos con cliente python file sockets tcp

servidor - socket python



Cliente/servidor TCP con sockets, servidor que envĂ­a archivos a clientes, bloqueos de clientes, Python (5)

Accidentalmente olvidaste solo usar HTTP y Twisted.

Servidor:

from twisted.web.static import File from twisted.web.resource import Resource def resource(): resource = Resource() resource.putChild(b"", File(u"xkcd/sandwich.png")) return resource

Cliente:

from filepath import FilePath from twisted.internet.task import react from treq import get, content def main(reactor): d = get(b"http://localhost:8080/") d.addCallback(content) d.addCallback(FilePath(u"image.png").setContent) return d react(main, [])

Demostración del servidor:

(everything) exarkun@baryon:/tmp/demo$ twist web --class server.resource 2017-02-23T21:32:14-0500 [-] Site starting on 8080 2017-02-23T21:32:14-0500 [twisted.web.server.Site#info] Starting factory <twisted.web.server.Site instance at 0x7fd1ef81a8c0> 2017-02-23T21:32:14-0500 [twisted.application.runner._runner.Runner#info] Starting reactor... 2017-02-23T21:33:01-0500 [twisted.python.log#info] "127.0.0.1" - - [24/Feb/2017:02:33:01 +0000] "GET / HTTP/1.1" 200 21489 "-" "-" ^C 2017-02-23T21:33:05-0500 [-] Received SIGINT, shutting down. 2017-02-23T21:33:05-0500 [-] (TCP Port 8080 Closed) 2017-02-23T21:33:05-0500 [twisted.web.server.Site#info] Stopping factory <twisted.web.server.Site instance at 0x7fd1ef81a8c0> 2017-02-23T21:33:05-0500 [-] Main loop terminated. (everything) exarkun@baryon:/tmp/demo$

Demostración del cliente:

(everything) exarkun@baryon:/tmp/demo$ ls -l image.png ls: cannot access ''image.png'': No such file or directory (everything) exarkun@baryon:/tmp/demo$ python client.py (everything) exarkun@baryon:/tmp/demo$ ls -l image.png -rwxr-xr-x 1 exarkun exarkun 21489 Feb 23 21:33 image.png (everything) exarkun@baryon:/tmp/demo$

Si desea obtener más información sobre cómo se realiza la red basada en bucle de selección, puede leer detenidamente la implementación de Twisted .

Quiero escribir un servidor TCP simple usando sockets en Python. El servidor debe enviar la imagen al cliente conectado. El cliente debe recibir la imagen. Pero, de ahora en adelante, el cliente recibe solo la parte de la imagen y ni siquiera puedo abrirla.

El servidor es multi-cliente utilizando select, pero no es el problema aquí. Creo que el problema es con el envío de la imagen.

Quería que "el protocolo" fuera muy simple aquí.

SERVER CLIENT GET <---------------- IMAGE -----------------> END OF COMMUNICATION

Por lo tanto, el cliente solo puede enviar el mensaje "GET" al servidor, y el servidor, después de obtener la cadena "GET", debe enviar inmediatamente la imagen completa al cliente. Eso es todo, la comunicación ha terminado.

server.py

#!/usr/bin/env python import random import socket, select from time import gmtime, strftime image = ''image.png'' HOST = ''127.0.0.1'' PORT = 6666 connected_clients_sockets = [] server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server_socket.bind((HOST, PORT)) server_socket.listen(10) connected_clients_sockets.append(server_socket) while True: read_sockets, write_sockets, error_sockets = select.select(connected_clients_sockets, [], []) for sock in read_sockets: if sock == server_socket: sockfd, client_address = server_socket.accept() connected_clients_sockets.append(sockfd) else: try: data = sock.recv(4096) bytes = open(image).read() if data: sock.send(bytes) except: sock.close() connected_clients_sockets.remove(sock) continue server_socket.close()

cliente.py

#!/usr/bin/env python import socket import sys HOST = ''127.0.0.1'' PORT = 6666 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_address = (HOST, PORT) sock.connect(server_address) try: sock.sendall("GET") while True: myfile = open(''imagefromserv.png'', ''w'') while True: data = sock.recv(4096) if not data: break myfile.write(data) myfile.close() finally: sock.close()

Estoy usando Python 2.7 en el Ubuntu más nuevo.

-------------------------------------------------- -------------------------------------------------- -------------------------------- EDIT ----------------- -------------------------------------------------- -------------------------------------------------- ---------------

Siguiendo los consejos dados por uno de los usuarios en los comentarios, TRATÉ de implementar un protocolo simple:

CLIENT SERVER GET/r/n -----------------------------------> OK/r/n <----------------------------------- GET_SIZE/r/n -----------------------------------> SIZE 1024/r/n <----------------------------------- GET_IMG/r/n -----------------------------------> IMG_DATA/r/r <-----------------------------------

Todo parece funcionar, pero después de la transferencia de imágenes, mi CPU está 100% ocupada, como dice top . Y ....

Salida del servidor:

--GET-- --GET_SIZE-- --24518-- --GET_IMG--

Salida del cliente:

--OK-- --SIZE 24518-- --24518-- 4096 8192 12288 16384 20480 24523 Image received successfully

Indica que el cliente recibió la imagen con éxito. ¿Está bien ahora? Quiero decir, obtuve la imagen del servidor, pero no sé si implementé el protocolo correctamente. Tal vez algo se puede mejorar aquí?

cliente.py:

#!/usr/bin/env python import socket import sys HOST = ''127.0.0.1'' PORT = 6666 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_address = (HOST, PORT) sock.connect(server_address) fname = ''fromserver.png'' try: sock.sendall("GET/r/n") data = sock.recv(4096) if data: txt = data.strip() print ''--%s--'' % txt if txt == ''OK'': sock.sendall("GET_SIZE/r/n") data = sock.recv(4096) if data: txt = data.strip() print ''--%s--'' % txt if txt.startswith(''SIZE''): tmp = txt.split() size = int(tmp[1]) print ''--%s--'' % size sock.sendall("GET_IMG/r/n") myfile = open(fname, ''wb'') amount_received = 0 while amount_received < size: data = sock.recv(4096) if not data : break amount_received += len(data) print amount_received txt = data.strip(''/r/n'') if ''EOF'' in str(txt) : print ''Image received successfully'' myfile.write(data) myfile.close() else : myfile.write(data) finally: sock.close()

server.py:

#!/usr/bin/env python import random import socket, select from time import gmtime, strftime image = ''tux.png'' HOST = ''127.0.0.1'' PORT = 6666 connected_clients_sockets = [] server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server_socket.bind((HOST, PORT)) server_socket.listen(10) connected_clients_sockets.append(server_socket) while True: read_sockets, write_sockets, error_sockets = select.select(connected_clients_sockets, [], []) for sock in read_sockets: if sock == server_socket: sockfd, client_address = server_socket.accept() connected_clients_sockets.append(sockfd) else: try: data = sock.recv(4096) if data : txt = data.strip() print ''--%s--''%txt if txt == ''GET'' : sock.sendall(''OK/r/n'') elif txt == ''GET_SIZE'' : with open (''tux.png'',''rb'') as f1: file_size = len(f1.read()) f1.seek(0) print ''--%s--''%file_size file_size = ''%s'' % file_size sock.sendall(''SIZE %s/r/n'' % file_size) elif txt == ''GET_IMG'' : with open(image, ''rb'') as fp: image_data = fp.read() msg = ''%sEOF/r/r'' % image_data sock.sendall(msg) print msg except: sock.close() connected_clients_sockets.remove(sock) continue server_socket.close()

O tal vez debería hacer:

sock.sendall(image_data) sock.sendall(''EOF/r/n'')

en lugar de:

msg = ''%sEOF/r/n'' % image_data sock.sendall(msg)

en cliente?


El código debajo de la sección EDITAR me parece bueno. Estoy completamente de acuerdo con @David Schwartz. Si está buscando implementar un protocolo, debe tener en cuenta muchas cosas con respecto al diseño del protocolo. Ex:

  • Si envías un comando, cómo reacciona el servidor.
  • que comandos son permitidos
  • implementar códigos de error para las respuestas del servidor, etc.

Para eso, puede leer "Implementación de TCP / IP y Protocolo de Linux", es un gran libro para este tema.

Por otro lado, puedes seguir con lo básico y continuar usando sockets TCP. Mi humilde sugerencia es que implementes algún mecanismo para que el cliente sepa si tiene la información completa, como:

  • envíe un hash de los datos, verifique el hash en el cliente
  • corte la información en fragmentos y envíe la cantidad de fragmentos, luego, en el cliente, compruebe cuántos fragmentos se recibieron y vuelva a solicitar la imagen en caso de fallo
  • O todo lo anterior

Esto es realmente extraño. Probé dos imágenes diferentes, y el código funcionó. El problema estaba entonces con la imagen.



Su cliente envía la cadena "GET". Solo desea enviar y recibir datos de imagen y "GET" no son datos de imagen.

Es posible que tenga otros errores, es difícil saberlo sin entender su protocolo. Por ejemplo, ¿cómo sabe un lado qué ha obtenido todos los datos de la imagen?