具有套接字的TCP客户端/服务器,服务器向客户端发送文件,客户端挂起,Python [英] TCP client/server with sockets, server sending files to clients, client hangs, Python

查看:494
本文介绍了具有套接字的TCP客户端/服务器,服务器向客户端发送文件,客户端挂起,Python的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想用Python中的套接字编写一个简单的TCP服务器。服务器应该发送图像到连接的客户端。客户应该收到图像。但是,现在,客户只收到图像的一部分,我甚至不能打开它。

服务器是使用select的多客户端,但是这里没有问题。我认为问题是发送图像。



我希望协议在这里变得非常简单。

 服务器客户端
GET
<----------------
图片
----------- ------>
通讯结束

所以客户端只能发送GET服务器在获得GET字符串后,应立即将整个图像发送给客户端。就这样,沟通结束了。
$ b

server.py

 #!/ usr / bin / env python 

import random
导入套接字,从时间选择
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)

而True:

read_sockets,write_sockets,error_sockets = select .select(connected_clients_sockets,[],[])

用于read_sockets中的sock:

如果sock == server_socket:

sockfd,client_address = server_socket.accept()
connected_clients_sockets.append(sockfd)

el se:
try:
data = sock.recv(4096)
bytes = open(image).read()

如果数据:
sock .send(字节)

除外:
sock.close()
connected_clients_sockets.remove(sock)
继续

server_socket.close ()

client.py

 #!/ usr / bin / env python 

导入套接字
导入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)

尝试:

sock.sendall(GET)

而真:

myfile = open('imagefromserv.png','w')

而真:
data = sock.recv(4096)
如果不是数据:
break
myfile.write(data)
myfile.close()

finally:
sock.close()

我在最新的Ubuntu上使用Python 2.7。

-------------------------------- -------------------------------------------------- --------------------------------------------------
编辑
--------------------------- -------------------------------------------------- --------------------------------------------------按照用户在评论中给出的建议,我试图实现一个简单的协议:

b

 客户端服务器
GET \r\ $
---------------- ------------------->
OK\r\\\

<--------------------------------- -
GET_SIZE \r\\\

--------------------------------- - >
SIZE 1024 \r\\\

<-------------------------------- ---
GET_IMG\r\\\

-------------------------------- --->
IMG_DATA \r\r
<--------------------------------- -

似乎一切正常,但在映像传输之后,我的CPU 100%忙 top 说。而且...

服务器的输出:

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

客户输出:

   -  OK-- 
--SIZE 24518--
--24518--
4096
8192
12288
16384
20480
24523
图片收到成功

表示客户端成功接收到映像。现在好吗?我的意思是,我从服务器上得到了映像,但是我不知道,如果我正确地实现了协议。也许在这里可以改进一些东西?



client.py:

  #!/ usr / bin / env python 

导入套接字
导入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 '

尝试:

sock.sendall(GET \r\\\

data = sock.recv(4096)

if data:
txt = data.strip()
print' - %s--'%txt

if txt =='OK':

sock.sendall(GET_SIZE \r\\\

data = sock.recv(4096)

如果数据:
txt =数据.strip()
print' - %s--'%txt

如果txt.startswith('SIZE'):

tmp = txt.split ()
size = int(tmp [1])$ ​​b
$ b print' - %s--'%size

sock.sendall(GET_IMG\r\\\

$ b $ myfile = open(fname,'wb')

amount_received = 0
while amount_received<大小:
data = sock.recv(4096)
如果不是数据:
break
amount_received + = len(data)
print amount_received
$ b如果str(txt)中的'EOF':
print'成功接收图像'


$ .write(data)
myfile.close()
else:
myfile.write(data)
finally:
sock.close()

server.py:

#!/ usr / bin / env python 

import random
导入套接字,从时间选择
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)

True:

read_sockets中的袜子的read_sockets,write_sockets,error_sockets = select.select(connected_clients_sockets,[],[])

如果sock,则为
$ b server_socket:
$ b $ s b






$ s
$ .recv(4096)

如果数据:

txt = data.strip()
print' - %s - '%txt

if txt =='GET':
sock.sendall('OK \r\\\
')

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\\\
'file_size)

elif txt =='GET_IMG':
打开(image,'rb')为fp:
image_data = fp.read()

msg ='%sEOF \r\r'%image_data
sock.sendall(msg)
print msg

除外:
sock.close()
connected_clients_sockets.remove(sock)
continue

server_socket.close()

或者我应该这样做:

  sock.sendall(image_data)
sock .sendall('EOF \r\\\
')

而不是:

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

在客户端?

解决方案

编辑部分下方的代码对我来说似乎很好。
我完全同意@David Schwartz。如果你想实现一个协议,你必须考虑到有关协议设计的很多事情。例如:
$ b


  • 如果您发送命令,服务器如何响应
  • 允许哪些命令

  • 实现服务器响应的错误代码等。



为此,您可以阅读TCP / IP和Linux协议实现这是一个伟大的书这样的事情。

另一方面,你可以坚持的基础,并继续使用TCP套接字,我谦卑的建议是你为客户端实现了一些机制来知道它是否有完整的信息,比如:
$ b


  • 发送数据散列,检查在客户端散列

  • 切分块中的信息并发送块数量,然后在客户端检查接收了多少块,并在出现故障时重新请求映像
  • >
  • 或以上全部


I want to write a simple TCP server using sockets in Python. The server should send the image to the connected client. The client should receive the image. But, for now on, the client receives only the portion of the image, and I can't even open it.

Server is multi-client using select, but its not the problem here. I think that the problem is with sending image.

I wanted "the protocol" to be very simple here.

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

So the client can only send the "GET" message to server, and the server, after getting the "GET" string, should immediately send the whole image to client. That's it, communication is over.

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()

client.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()

I'm using Python 2.7 on newest Ubuntu.

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

Following advices given by one of the users in comments, I TRIED to implement a simple protocol:

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

Everything seems to work, but after the image transfer, my CPU is 100% busy, as top says. And ....

Server's output:

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

Client's output:

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

Indicates that the client received the image successfully. Is it ok now? I mean, I got the image from server, but I do not know, if I implemented the protocol correctly. Maybe something can be improved here?

client.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()

Or maybe I should rather do:

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

instead of:

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

in client?

解决方案

The code below the EDIT section seems good to me. I completely agree with @David Schwartz. If you're looking to implement a protocol you have to take into consideration a whole lot of things regarding the protocol design. Ex:

  • if you send a command, how the server reacts
  • which commands are allowed
  • implement error codes for server responses, etc

For that you can read "TCP/IP and Linux Protocol Implementation" it is a great book for such matter.

In the other hand, you can stick with the basics and continue using TCP sockets,my humble suggestion is that you implement some mechanism for the client to know if it has the complete information, like:

  • send a hash of the data, check the hash in the client
  • cut the info in chunks and send the chunk quantity, then in the client check how many chunks were received, and re-request the image in case of failure
  • or all of the above

这篇关于具有套接字的TCP客户端/服务器,服务器向客户端发送文件,客户端挂起,Python的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆