1

私はソケットプログラミングとpythonの初心者です。サーバーからクライアントに大きなテキスト ファイル (例: > 5MB) を送信する方法を知りたいです。というエラーが表示され続けます

Traceback (most recent call last):
  File "fserver.py", line 50, in <module>
    reply = f.read()
ValueError: Mixing iteration and read methods would lose data

以下は私のコードの一部です。誰かが見て、この問題を解決する方法についてのヒントを教えてもらえますか? お時間をいただきありがとうございます。

myserver.py

#validate filename
        if os.path.exists(filename):
            with open(filename) as f:
                for line in f:
                    reply = f.read()
                    client.send(reply)
            #f = open(filename, 'r')
            #reply = f.read()
            #client.send(piece)
        else:
            reply = 'File not found'
            client.send(reply)

myclient.py

while True:
    print 'Enter a command: list or get <filename>'
    command = raw_input()
    if command.strip() == 'quit':
        break
    client_socket.send(command)

    data = client_socket.recv(socksize)
    print data
4

2 に答える 2

4

ここでの問題は、ソケットやファイルの大きさとは関係ありません。これを行う場合:

for line in f:
    reply = f.read()

for line in f一度にファイルの 1 行を読み取ろうとし、次に各行に対してファイル全体を読み取ろうとしています。それはうまくいきません。

このエラーが発生しなかった場合 (多くの場合発生することはありません)、初めてループを通過するときに、最初の行を読み取って無視し、最初の行以外のすべて (または、場合によってはすべて) を読み取って送信します。しかし、最初の、たとえば 4KB) を 1 つの巨大な応答として送信すると、ループが実行されます。

あなたが望むのは、どちらかです:

for line in f:
    reply = line

…または…</p>

# no for loop
reply = f.read()

一方、クライアント側では、1 つだけを実行していますrecv。それは最初の 4K (または何でもsocksize) 以下を取得し、それ以外は何も取得しません。

必要なのはループです。このような:

while True:
    data = client_socket.recv(socksize)
    print data

しかし今、あなたは新たな問題を抱えています。ファイルが完了すると、クライアントはそこに座って、次のデータのチャンクを永遠に待ちます。したがって、クライアントはそれがいつ完了したかを知る必要があります。それを知る唯一の方法は、サーバーがその情報をデータ ストリームに入れるかどうかです。

これを行う 1 つの方法は、ファイルの前に長さを送信することです。これを行う標準化された方法の 1 つは、netstringプロトコルを使用することです。これを行うライブラリを見つけることができますが、手動で行うのは簡単です。または、ヘッダーが改行で区切られ、本文から空白行で区切られている HTTP のようなものを実行することもできます。socket.makefileその後、プロトコルの実装として使用できます。または、長さを 4 バイトとして送信するバイナリ プロトコルですらあります。

ここにいる間に解決した方がよい問題がもう 1 つあります。send(reply)必ずしも返信全体を送信するとは限りません。1 バイトから全体までの任意の場所に送信し、何が送信されたかを示す数値を返します。それに対する簡単な修正はsendall(reply)、すべてを送信することを保証する を使用することです。

そして最後に: サーバーは、それぞれrecvが から送信された 1 つのコマンドを受け取ることを期待していますsend。しかし、ソケットはそのようには機能しません。ソケットはバイト ストリームであり、メッセージ ストリームではありませんrecvたとえば、コマンドの半分だけを取得することを妨げるものは何もありません。その後、サーバーが壊れます。したがって、その方向にも何らかのプロトコルが必要です。繰り返しますが、ネット文字列、改行で区切られたメッセージ、またはバイナリ長のプレフィックスを使用できますが、何かをする必要があります.

(上記のリンクのブログ投稿には、バイナリ長プレフィックスをプロトコルとして使用するための非常に単純なコード例があります。)

于 2013-11-15T00:06:03.387 に答える
0

できるよfor line in file.readlines()

于 2013-11-15T00:37:09.920 に答える