4

Python と AES を使用して安全な転送ファイル プログラムを作成しようとしていますが、完全には理解できない問題があります。ファイルを 1024 バイトのチャンクで解析して送信することでファイルを送信しましたが、データを受信するサーバー側がクラッシュし (AES CBC を使用しているため、データの長さは 16 バイトの倍数である必要があります)、エラーが表示されます。いいえ。

クライアント側でクライアントから送信されたデータの長さとサーバーで受信したデータの長さを出力しようとしましたが、クライアントが想定どおりに毎回正確に 1024 バイトを送信していることを示していますが、サーバー側では次のように表示されます。ある時点で、受信したパケットが 1024 バイト未満 (たとえば 743 バイト) ではないことを確認します。

クライアント側の各ソケット送信の間に time.sleep(0.5) を入れようとしましたが、うまくいくようです。サーバー側で何らかのソケットバッファ障害が発生している可能性はありますか? クライアントがあまりにも多くのデータを送信する速度が速すぎて、サーバー側のソケット バッファが壊れてデータが破損または消滅し、recv(1024) が壊れたチャンクしか受信しないということですか? それが私が考えることができる唯一のことですが、これも完全に間違っている可能性があります。これが適切に機能しない理由を誰かが知っているなら、それは素晴らしいことです;)

私の考えに従って、私は試しました:

    self.s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 32768000)
    print socket.SO_RCVBUF

サーバー側に 32mbytes のバッファを配置しようとしましたが、Windows XP ではプリントに 4098 が表示され、Linux では 8 しか表示されません。これをどのように解釈する必要があるのか​​ わかりません。 32 メガバイトのバッファがないため、コードは機能しません。

かなり長い投稿になってしまいましたが、勇気を出してここまで読んでくださった方がいらっしゃれば幸いです。私はそこで完全に迷っているので、誰かがこれについて何か考えを持っているなら、それを共有してください:D

Faisal のおかげで、私のコードは次のとおりです。

サーバー側: (カウントは私のファイルサイズ/1024 です)

while 1:
    txt=self.s.recv(1024)
    if txt == " ":
        break       
    txt = self.cipher.decrypt(txt)
    if countbis == count:
        txt = txt.rstrip()
    tfile.write(txt)
    countbis+=1

クライアント側 :

while 1:
    txt= tfile.read(1024)
    if not txt:
        self.s.send(" ")
        break
    txt += ' ' * (-len(txt) % 16)
    txt = self.cipher.encrypt(txt)
    self.s.send(txt)

前もって感謝します、

ノリアン

4

8 に答える 8

8

ネットワークプログラミングへようこそ!あなたは、クライアントの送信とサーバーの受信が対称であると仮定して、誰もが最初に行うのと同じ誤った仮定に陥りました。残念ながら、そうではありません。OS では、任意のサイズのチャンクで受信を行うことができます。ただし、回避するのはかなり簡単です。読み込んだ量が受け取りたい量と等しくなるまでデータをバッファするだけです。これに沿った何かがトリックを行います:

buff=''
while len(buff) < 1024:
    buff += s.recv( 1024 - len(buff) )
于 2010-07-06T20:24:51.627 に答える
3

TCP はストリーム プロトコルであり、今発見したように、メッセージ境界を保持しません。

于 2010-07-06T20:19:43.033 に答える
2

他の人が指摘しているように、おそらく不完全なメッセージを処理しています。完全なメッセージがいつ受信されたかがわかるように、固定サイズのメッセージまたは区切り文字 (データをエスケープすることを忘れないでください!) のいずれかが必要です。

于 2010-07-06T20:32:57.327 に答える
1

TCP とは関係ありませんが (すでに回答されているため)、多くの受信が予想される場合、文字列に繰り返し追加することはかなり非効率的です。を使って受信し終わったら、リストに追加してからリストを文字列に変換した方がよい場合があります''.join(list)

于 2011-11-08T15:14:00.097 に答える
1

TCP が保証できるのは、すべてのデータが正しい順序で、ある時点で到着することです。(不測の事態が発生して到着しない場合を除きます。) しかし、送信したデータがチャンクで到着する可能性は非常に高くなります。その多くは、送信バッファと受信バッファが限られているためです。すべきことはrecv、処理するのに十分なデータが得られるまで呼び出しを続けることです。send複数回呼び出す必要がある場合があります。その戻り値を使用して、これまでに送信/バッファリングされたデータの量を追跡します。

を実行するとprint socket.SO_RCVBUF、実際にはシンボリックな SO_RCVBUF定数が出力されます(ただし、Python には実際には定数がありません)。何を変更したいかを伝えるために使用されるsetsockoptもの。現在の値を取得するには、代わりに を呼び出す必要がありますgetsockopt

于 2010-07-06T20:27:03.750 に答える
0

多くのアプリケーションでは、TCPの複雑さはPythonのasynchatモジュールによってきちんと抽象化されています。

于 2010-07-06T21:41:30.910 に答える
0

これは、私が以前に書いたコードのスニペットです。最適ではないかもしれませんが、ローカル ネットワークを介した大きなファイル転送の良い例になる可能性があります。http://setahost.com/sending-files-in-local-network-with-python/

于 2011-10-31T20:30:23.913 に答える
0

上記のように

TCP はストリーム プロトコルです。

このコードを試すことができます。データは元のデータであり、ファイルまたはユーザー入力から読み取ることができます

送信者

import socket as s
sock = s.socket(s.AF_INET, s.SOCK_STREAM)
sock.connect((addr,5000))
sock.sendall(data)
finish = t.time()

レシーバー

import socket as s
sock = s.socket(s.AF_INET, s.SOCK_STREAM)
sock.setsockopt(s.SOL_SOCKET, s.SO_REUSEADDR, 1)
sock.bind(("", 5000))
sock.listen(1)
conn, _ = sock.accept()
pack = []
while True:
    piece = conn.recv(8192)
    if not piece:
        break
    pack.append(piece.decode())
于 2015-12-18T15:16:38.387 に答える