私は次のようにクライアントサーバーアプリケーションを作成します:client(c#)<-> server(twisted; ftp proxy and 追加機能)<-> ftp server
サーバーには2つのクラスがあります。LineReceieverプロトコルから継承された独自のクラスプロトコルと、twisted.protocols.ftpからのFTPClientです。
ただし、クライアントが大きなファイル(10 Gb〜20 Gb)を送信または取得すると、サーバーはMemoryErrorをキャッチします。コードでバッファを使用していません。これは、呼び出し後にtransport.write(data)データがreactorのライターの内部バッファーに追加されたときに発生します(間違っている場合は修正してください)。
この問題を回避するには何を使用すればよいですか?または、問題へのアプローチを変更する必要がありますか?
大きなストリームの場合は、IConsumerおよびIProducerインターフェイスを使用する必要があることがわかりました。しかし最後に、transfer.writeメソッドを呼び出し、効果は同じになります。それとも私は間違っていますか?
UPD:
ファイルのダウンロード/アップロードのロジックは次のとおりです(ftpからTwistedサーバーを経由してWindowsのクライアントに):
クライアントはいくつかのヘッダーをツイストサーバーに送信し、その後ファイルの送信を開始します。ツイストサーバーはヘッダーを受信し、その後(必要に応じて)呼び出しsetRawMode()
、ftp接続を開き、クライアントとの間でバイトを受信/送信し、すべての接続を閉じます。ファイルをアップロードするコードの一部は次のとおりです。
FTPManagerクラス
def _ftpCWDSuccees(self, protocol, fileName):
self._ftpClientAsync.retrieveFile(fileName, FileReceiver(protocol))
class FileReceiver(Protocol):
def __init__(self, proto):
self.__proto = proto
def dataReceived(self, data):
self.__proto.transport.write(data)
def connectionLost(self, why = connectionDone):
self.__proto.connectionLost(why)
メインプロキシサーバークラス:
class SSDMProtocol(LineReceiver)
...
SSDMProtocolオブジェクト(呼び出しobSSDMProtocol
)がヘッダーを解析した後、ftp接続(FTPClient
から twisted.protocols.ftp
)を開き、FTPManagerフィールド_ftpClientAsyncのオブジェクトを設定_ftpCWDSuccees(self, protocol, fileName)
しprotocol = obSSDMProtocol
、ファイルのバイトを受信したときdataReceived(self, data)
にFileReceiverオブジェクトを呼び出すメソッドを呼び出します。
また、self.__proto.transport.write(data)
呼び出されると、データはクライアントに送り返すよりも速く内部バッファに追加されるため、メモリが不足します。バッファが特定のサイズに達したときに読み取りを停止し、バッファがすべてクライアントに送信された後に読み取りを再開できますか?またはそのようなもの?