Отправка изображения через сокеты (ТОЛЬКО) в Python, изображение не может быть открыто

Я хочу загрузить изображение с клиента на сервер, используя ТОЛЬКО сокеты в Python. Я разработал очень простой поток протокола, как я хотел бы сделать это:

CLIENT                                       SERVER
               SIZE 512 (send image size)
         ---------------------------------->
                      GOT SIZE   
         <---------------------------------- 
                 send image itself
         ---------------------------------->
                      GOT IMAGE
         <----------------------------------
                      BYE BYE 
         ---------------------------------->
                server closes socket

Вот мой код клиента:

#!/usr/bin/env python

import random
import socket, select
from time import gmtime, strftime
from random import randint

image = "tux.png"

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:

    # open image
    myfile = open(image, 'rb')
    bytes = myfile.read()
    size = len(bytes)

    # send image size to server
    sock.sendall("SIZE %s" % size)
    answer = sock.recv(4096)

    print 'answer = %s' % answer

    # send image to server
    if answer == 'GOT SIZE':
        sock.sendall(bytes)

        # check what server send
        answer = sock.recv(4096)
        print 'answer = %s' % answer

        if answer == 'GOT IMAGE' :
            sock.sendall("BYE BYE ")
            print 'Image successfully send to server'

    myfile.close()

finally:
    sock.close()

И мой сервер, который получает изображения от клиентов:

#!/usr/bin/env python

import random
import socket, select
from time import gmtime, strftime
from random import randint

imgcounter = 1
basename = "image%s.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)
                txt = str(data)

                if txt.startswith('SIZE'):
                    tmp = txt.split()
                    size = int(tmp[1])

                    print 'got size'

                    sock.send("GOT SIZE")

                elif txt.startswith('BYE'):
                    sock.shutdown()

                elif data:

                    myfile = open(basename % imgcounter, 'wb')

                    data = sock.recv(40960000)
                    if not data:
                        myfile.close()
                        break
                    myfile.write(data)
                    myfile.close()

                    sock.send("GOT IMAGE")
                    sock.shutdown()
            except:
                sock.close()
                connected_clients_sockets.remove(sock)
                continue
        imgcounter += 1
server_socket.close()

Для примера изображения:

Клиент распечатывает сообщения, которые предполагают, что он успешно отправил изображение на сервер:

answer = GOT SIZE
answer = GOT IMAGE
Image successfully send to server

Изображение создается на стороне сервера, но я не могу его открыть. И да, я пробовал разные образы. Без успеха. Я не могу открыть их на стороне сервера, хотя они доступны там.

Благодаря @BorrajaX мне удалось заставить его работать! Спасибо!:)

#!/usr/bin/env python

import random
import socket, select
from time import gmtime, strftime
from random import randint

imgcounter = 1
basename = "image%s.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)
                txt = str(data)

                if data:

                    if data.startswith('SIZE'):
                        tmp = txt.split()
                        size = int(tmp[1])

                        print 'got size'

                        sock.sendall("GOT SIZE")

                    elif data.startswith('BYE'):
                        sock.shutdown()

                    else :

                        myfile = open(basename % imgcounter, 'wb')
                        myfile.write(data)

                        data = sock.recv(40960000)
                        if not data:
                            myfile.close()
                            break
                        myfile.write(data)
                        myfile.close()

                        sock.sendall("GOT IMAGE")
                        sock.shutdown()
            except:
                sock.close()
                connected_clients_sockets.remove(sock)
                continue
        imgcounter += 1
server_socket.close()

1 ответ

Решение

Хорошо, ваша проблема в том, что в случае получения реального изображения вы читаете сокет два раза и игнорируете данные в первом чтении и просто записываете данные, полученные во втором чтении. Таким образом, ваш файл изображения является неполным. Смотрите мое исправление ниже, вы можете оптимизировать его, взяв его за отправную точку. Это работает как таковое.

#!/usr/bin/env python

import random
import socket, select
from time import gmtime, strftime
from random import randint

imgcounter = 1
basename = "image%s.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)
buffer_size = 4096

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:
                print ' Buffer size is %s' % buffer_size
                data = sock.recv(buffer_size)
                txt = str(data)

                if txt.startswith('SIZE'):
                    tmp = txt.split()
                    size = int(tmp[1])

                    print 'got size'
                    print 'size is %s' % size

                    sock.send("GOT SIZE")
                    # Now set the buffer size for the image 
                    buffer_size = 40960000

                elif txt.startswith('BYE'):
                    sock.shutdown()

                elif data:

                    myfile = open(basename % imgcounter, 'wb')

                    # data = sock.recv(buffer_size)
                    if not data:
                        myfile.close()
                        break
                    myfile.write(data)
                    myfile.close()

                    sock.send("GOT IMAGE")
                    buffer_size = 4096
                    sock.shutdown()
            except:
                sock.close()
                connected_clients_sockets.remove(sock)
                continue
        imgcounter += 1
server_socket.close() 
Другие вопросы по тегам