簡體   English   中英

使用 python 套接字編程發送多個數據包

[英]send multiple packets of data using python socket programming

所以現在我有一個服務器和客戶端腳本。 我正在嘗試將文件從客戶端上傳到服務器。 但是,客戶端中文件的數據將被 HEADER 大小剪切掉。 如何在同一個發送命令下將多個數據包發送到服務器?

服務器.py:

import socket
import threading
HEADER=2048
PORT=5050
SERVER=socket.gethostbyname(socket.gethostname())
ADDR=(SERVER,PORT)
FORMAT='utf-8'
DISCONNECT_MESSAGE='!DISCONNECT'
SEPARATOR='<SEPERATE>'
server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind(ADDR)
def handle_client(conn,addr):
    print(f'[NEW CONNECTION] {addr} connected.')
    connected=True
    while connected:
        data=conn.recv(HEADER).decode(FORMAT)
        if data==DISCONNECT_MESSAGE:
            connected=False
        else:
            data=data.split(SEPARATOR)
            file=open(data[0],'w')
            file.write(data[1])
            print('file received')
            conn.send('file received'.encode(FORMAT))         
    conn.close()
    print(f'[DISCONNECT] {addr} disconnected')

def start():
    server.listen()
    print(f'[LISTENING] Server is listening on {SERVER}')
    while True:
        conn,addr=server.accept()
        thread=threading.Thread(target=handle_client,args=(conn,addr))
        thread.start()
        print(f'[ACTIVE CONNECTIONS] {threading.activeCount()-1}')
print("[STARTING] server is starting...")
start()

客戶端.py:

import socket
HEADER=2048
PORT=5050
FORMAT='utf-8'
DISCONNECT_MESSAGE='!DISCONNECT'
SEPARATOR='<SEPERATE>'
SERVER=socket.gethostbyname(socket.gethostname())
ADDR=(SERVER,PORT)
client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect(ADDR)
def send(msg):
    message=msg.encode(FORMAT)
    client.send(message)
    print(client.recv(HEADER).decode(FORMAT))
file=open('question_pool.csv','r')
data=file.read()
send(f'question_pool.csv{SEPARATOR}{data}')
file.close()
send(DISCONNECT_MESSAGE)

簡而言之,您想要發送大於HEADER大小的任何文件的多個塊。 將文件拆分為小於HEADER大小的塊,並單獨發送每個塊。 然后,當所有塊都設置好后,發送一條消息,說明整個文件已發送,以便服務器可以保存它。

這是我用於上述解決方案的代碼:
server.py

import socket
import threading


HEADER = 2048
PORT = 5050
SERVER = socket.gethostbyname(socket.gethostname())
ADDR = (SERVER, PORT)
FORMAT = 'utf-8'
DISCONNECT_MESSAGE = '!DISCONNECT'
SEPARATOR = '<SEPERATE>'
FILE_FINISHED_SENDING = '<!FILE_SENT!>'

server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind(ADDR)


def handle_client(conn, addr):
    print(f'[NEW CONNECTION] {addr} connected.')
    connected = True
    current_file = None

    while connected:
        data = conn.recv(HEADER).decode(FORMAT)
        if data == DISCONNECT_MESSAGE:
            connected = False
        elif data == FILE_FINISHED_SENDING:
            current_file.close()
            current_file = None
            conn.send(b'file received.')
        else:
            data = data.split(SEPARATOR)
            if len(data) == 2 and data[1] == '':
                # The name of the file was sent, more will follow.
                current_file = open(data[0], 'w')
                conn.send(b'filename recieved')
            else:
                # File data was send, so write it to the current file
                current_file.write(data[1])
                print('chunk of file recv''d')
                conn.send(b'chunk received')
    conn.close()
    print(f'[DISCONNECT] {addr} disconnected')



def start():
    server.listen()
    print(f'[LISTENING] Server is listening on {SERVER}')
    while True:
        conn, addr = server.accept()
        thread = threading.Thread(target=handle_client, args=(conn,addr))
        thread.start()
        print(f'[ACTIVE CONNECTIONS] {threading.activeCount()-1}')


print("[STARTING] server is starting...")
start()

client.py

import socket
from pathlib import Path

HEADER = 2048
PORT = 5050
FORMAT = 'utf-8'
DISCONNECT_MESSAGE = '!DISCONNECT'
SEPARATOR = '<SEPERATE>'
FILE_FINISHED_SENDING = '<!FILE_SENT!>'
SERVER = socket.gethostbyname(socket.gethostname())
ADDR = (SERVER, PORT)

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(ADDR)


def chunker(string: str, size: int):
    return (string[pos:pos + size] for pos in range(0, len(string), size))


def send(msg):
    message = msg.encode(FORMAT)
    client.send(message)
    print(client.recv(HEADER).decode(FORMAT))


def send_file(filepath: str):
    with open(filepath, 'r', encoding=FORMAT) as f:
        data = f.read()

    first_bits = f'{Path(filepath).name}{SEPARATOR}'  # Easy way of getting just a file's name from its path
    send(first_bits)  # Send the filename to the server
    for chunk in chunker(data, HEADER-48):  # Leave a safe buffer
        # Send each chunk of the file
        send(f"{SEPARATOR}{chunk}")

    # Tell the server that's all for this file.
    # Now it can close the file object.
    send(FILE_FINISHED_SENDING)


send_file("/path/to/file.html")
send(DISCONNECT_MESSAGE)

提示:

  • 確保您的特殊消息,如SEPARATORFILE_FINISHED_SENDINGDISCONNECT_MESSAGE不會出現在您發送的文件中。 否則事情可能會變得不穩定。
  • 當您通過套接字發送文件時,您可能希望將文件作為原始字節讀取,而不是作為字符串讀取、編碼、解碼等。這樣您就可以發送二進制文件,例如.mp3

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM