使用TCP和套接字将文件从客户端并发发送到服务器

时间:2018-11-18 15:34:46

标签: sockets tcp concurrency client-server

我正在尝试实现一个程序,该程序使用TCP套接字同时从客户端向服务器发送文件。我有一个客户端和服务器代码,当并发数为1时可以正常工作,但是当并发数为2或更高时无法正确传输。

buffer.py

class Buffer:
    def __init__(self,s):
        '''Buffer a pre-created socket.
        '''
        self.sock = s
        self.buffer = b''

    def get_bytes(self,n):
        '''Read exactly n bytes from the buffered socket.
           Return remaining buffer if <n bytes remain and socket closes.
        '''
        while len(self.buffer) < n:
            data = self.sock.recv(1024)
            if not data:
                data = self.buffer
                self.buffer = b''
                return data
            self.buffer += data
        # split off the message bytes from the buffer.
        data,self.buffer = self.buffer[:n],self.buffer[n:]
        return data

    def put_bytes(self,data):
        self.sock.sendall(data)

    def get_utf8(self):
        '''Read a null-terminated UTF8 data string and decode it.
           Return an empty string if the socket closes before receiving a null.
        '''
        while b'\x00' not in self.buffer:
            data = self.sock.recv(1024)
            if not data:
                return ''
            self.buffer += data
        # split off the string from the buffer.
        data,_,self.buffer = self.buffer.partition(b'\x00')
        return data.decode()

    def put_utf8(self,s):
        if '\x00' in s:
            raise ValueError('string contains delimiter(null)')
        self.sock.sendall(s.encode() + b'\x00')

client.py

import socket
import threading
import os
from concurrent.futures import ThreadPoolExecutor, as_completed

import buffer

HOST = '127.0.0.1'
PORT = 2345


def main():
  s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  s.connect((HOST, PORT))

  sbuf = buffer.Buffer(s)
  files_to_send = ['text.txt', 'some.txt']

  with ThreadPoolExecutor(max_workers=1) as executor:
      futures = [executor.submit(_send_file, sbuf, file_name) for file_name in files_to_send]
      for future in as_completed(futures):
          result = future.result()
          print result

def _send_file(sbuf, file_name):
  print(file_name)
  sbuf.put_utf8(file_name)

  file_size = os.path.getsize(file_name)
  sbuf.put_utf8(str(file_size))

  with open(file_name, 'rb') as f:
      sbuf.put_bytes(f.read())
  print('File Sent')


if __name__ == '__main__':
  main()

server.py

import socket
import os

import buffer

HOST = ''
PORT = 2345

try:
    os.mkdir('uploads')
except:
    pass

s = socket.socket()
s.bind((HOST, PORT))
s.listen(10)
print("Waiting for a connection.....")

while True:
    conn, addr = s.accept()
    print("Got a connection from ", addr)
    connbuf = buffer.Buffer(conn)

    while True:

        file_name = connbuf.get_utf8()
        if not file_name:
            break
        file_name = os.path.join('uploads',file_name)
        print('file name: ', file_name)

        file_size = int(connbuf.get_utf8())
        print('file size: ', file_size )

        with open(file_name, 'wb') as f:
            remaining = file_size
            while remaining:
                chunk_size = 4096 if remaining >= 4096 else remaining
                chunk = connbuf.get_bytes(chunk_size)
                if not chunk: break
                f.write(chunk)
                remaining -= len(chunk)
            if remaining:
                print('File incomplete.  Missing',remaining,'bytes.')
            else:
                print('File received successfully.')
    print('Connection closed.')
    conn.close()

以上代码在并发max_workers为1时有效,但在增加worker数时失败。我猜想这与服务器端的并发有关,但是我不知道在何处确切地并发。要实现并发文件传输,该代码需要做什么/更改?

0 个答案:

没有答案