4

我在 python 中创建了一个测试服务器,它通过套接字接收连接并保存 png 文件。但是,我想将一些其他数据传递给服务器,例如文件名、发送它的用户等。但我不能这样做,因为要接收数据,您必须告知您正在缓冲区中读取的字节数。

我研究了很多,一些例子说使用结构并打包所有数据,但是一个图像的大小与另一个图像的大小不同,我不能简单地制作一个结构格式,因为我收到的每个文件都会有所不同。

这是我到目前为止所做的工作:

服务器

import socket
import os
import sys

FilePath = os.path.realpath(os.path.dirname(sys.argv[0]))

s = socket.socket()
s.bind(("localhost",8000))
s.listen(5) #Tipo, 5 conexoes no maximo {ao mesmo tempo}

i=0
name = 'file_'
while (True):
    sc, address = s.accept()
    name = 'file_%s' % i
    f = open(os.path.join(FilePath,'server_received/%s.png'% name) ,'wb') #open as binary data
    i=i+1
    # receives and writes the file
    l = sc.recv(1024)
    while (l):
        f.write(l)
        l = sc.recv(1024)
f.close()


sc.close()
s.close()

客户

class SendToServer(Thread):
    def __init__(self, queue, *args, **kwargs):
        Thread.__init__(self)
        self.queue = queue
        self.args = args
        self.kwargs = kwargs

    def run(self):
        try:
            while not self.queue.empty():
                s = socket.socket()
                s.connect((HOST,PORT))
                file_path = self.queue.get()
                file = open(file_path,'rb')
                s.send(file_path)
                l = file.read(1024)
                while l:
                    s.send(l)
                    l = file.read(1024)
                self.queue.task_done()
                s.close()
                print u"Enviado"
        except:
            print u"Sem conexao"

        #This i Use when I call the Thread:
        sync= SendToServer(queue)
        sync.run()

上面的代码运行良好,但我怎样才能发送比文件更多的数据呢?(二进制数据)

4

3 回答 3

4

你看过“泡菜”吗?使用pickle,您可以序列化一个对象,例如创建一个对象,例如字典:

    imageDict = {'imageFile': image, 'user': userName, 'fileName': file}

    pickleData = pickle.dumps(imageDict)

    s.send(pickleData)

现在在您的服务器上,您可以解开数据:

l = sc.recv(1024)

imageDict = pickle.dumps(l)

现在,只要您等到所有数据都收到,您就应该拥有一个字典,就像您在客户端创建的字典一样。

解释器中的示例:

>>> import pickle
>>> data = {'mac':4, 'mid':5}
>>> data
{'mac': 4, 'mid': 5}
>>> dataPickle = pickle.dumps(data)
>>> dataPickle
"(dp0\nS'mac'\np1\nI4\nsS'mid'\np2\nI5\ns."
>>> unpick = pickle.loads(dataPickle)
>>> unpick
{'mac': 4, 'mid': 5}
>>>
于 2013-10-23T23:23:49.613 回答
0

我已经使用 marshal(http://docs.python.org/2/library/marshal.html#module-marshal)。

所以,我创建了一个包含所有数据的字典(用户名、文件名、二进制文件)我将它保存在一个文件中(元帅这样做),然后我将所有二进制文件传输到服务器。

客户:

    while not self.queue.empty():
        try:
            s = socket.socket()
            s.connect((HOST,PORT))
        except:
            print "connection error"
            break
        file_path = self.queue.get()
        file = open(file_path,'rb')
        dados = ['User',
                'someothertext',
                file_path,
                file.read()
                ]
        temp = open(os.path.join(SaveDirectory,'temp'),'wb')
        marshal.dump(dados,temp)
        temp.close()
        file = open(os.path.join(SaveDirectory,'temp'),'rb')
        l = file.read(1024)
        while l:
            try:
                s.send(l)
                l = file.read(1024)
            except:
                print "error while sending"
                break


        temp.close()
        file.close()

        os.remove(os.path.join(SaveDirectory,'temp'))

        self.queue.task_done()

        s.close()
        print u"OK"

服务器:

#coding: utf-8
import socket
import os
import sys
import marshal
FilePath = os.path.realpath(os.path.dirname(sys.argv[0]))

s = socket.socket()
s.bind(("localhost",8000))
s.listen(5) #Tipo, 5 conexoes no maximo {ao mesmo tempo}

i=0
nome = 'file_'
while (True):
    sc, address = s.accept()
    nome = 'file_%s' % i
    temp = open(os.path.join(FilePath,'server_received/%s'% nome) ,'wb')
    i=i+1
    l = sc.recv(1024)
    while (l):
        temp.write(l)
        l = sc.recv(1024)
    temp.close()
    temp = open(os.path.join(FilePath,'server_received/%s'% nome) ,'rb') #abrir como binario
    #Here I can unpack my dictionary.
    dados = marshal.load(temp)
    temp.close()
    #removing the file I received
    os.remove(os.path.join(FilePath,'server_received/%s'% nome))
    print dados[0], dados[1], dados[2]
    arq  = open(os.path.join(FilePath,'server_received/%s'% dados[2].split('\\')[-1]),'wb')
    arq.write(dados[3])
    arq.close()


sc.close()
s.close()
于 2013-10-25T00:51:58.967 回答
0

我不知道你的协议怎么样,你想不想写,但我有一个很好的经验:

使用多个端口:

注意:使用 UDP 以获得更快的速度。

  1. 用于发送协议命令的端口号 xxx
  2. 用于发送数据传输的端口号 yyy
  3. 用于接收数据传输的端口号 zzz
  4. 用于确认您的协议命令的端口号 uuu

1号和4号是连在一起的,3号和2号是连在一起的。

你可以为你的命令实现一个发送/确认系统,而不是使用TCP协议,因为你有大数据(图片),另一方面,你应该想使用安全,所以你可以在UDP这项工作上实现一组命令/确认喜欢TCP但很轻。

您应该将您的系统应用于 1 号和 4 号,不要申请 2 号和 3 号。

于 2013-10-25T01:12:47.207 回答