8

C#アプリは、同じネットワーク上にある別のコンピューターに存在するそれ自体のインスタンスと簡単に通信し、ファイルとデータを転送するにはどうすればよいですか?

ネットワーク上のコンピューターが固定ローカルIPアドレスを持ち、それぞれがお互いのIPを知っていると仮定します。IPが不明な場合に通信する方法もありますか?いくつかの発見プロトコルに基づいていますか?

Appleの「Bonjour」サービスは良いプロトコルだと聞きました。Windowsアプリから通信できますか?または、「ソケット」を使用する必要がありますか。私は主に、自分のニーズを簡単に満たすことができるライブラリまたはサンプルコードを探しています。独自のTCPベースのプロトコルやハードコアなものを開発したくありません。

4

4 に答える 4

5

You can use System.Net.Sockets class to communicate and it have a method for sending file Socket.SendFile.

Update:
this is a good example for file sharing and sending file from C# help

于 2009-08-09T09:55:37.173 に答える
3

C#のファイルとソケットの優れている点は、両方がストリームとして公開されていることです。あるストリームから別のストリームに大きなファイルをコピーするのは非常に簡単です。

byte[] data = new byte[1024];
while(true) {
int bytesRead = filestream.read(data,0,data.Length);
if (bytesRead==0) break;
netstream.write(data,0,bytesRead);
}

完了したら、ソケットを閉じます。

メタデータ(ファイル名、サイズ)を送信する場合、または接続を閉じたくない場合は、これを処理するための何らかのプロトコルが必要です。FTPは、2つの別個のソケットを使用します(1つはメタデータ用、もう1つはデータ用。これは帯域外通信と呼ばれます)。ファイアウォールのないLANを使用している場合は、それで十分です。一方、インターネット転送を行う場合は、1つのポートを開くのは困難で十分な作業であり、2つは耐えられません。パフォーマンスをあまり気にしない場合は、base64エンコーディングでバイトをエンコードできます。これにより、バイトが特定のバイト範囲内にあることが確認されます。base64を使用すると、メッセージを改行またはその他の英数字以外の文字で区切ることができます。次に、最初のメッセージにファイル名やサイズなどを含め、データを2番目のメッセージとして送信してから、「that」を送信します。

メッセージのもう1つの戦術は、エスケープシーケンスを使用することです。たとえば、バイトストリームを取得し、「\0」の各インスタンスを「\0\0」に置き換えます。次に、「\ 0 \ 1」を使用してメッセージの終わりを通知します。これは、データメッセージに含まれないことが保証されています。'\ 0\0'をデコードして受信側の'\0'に戻します。これはCで十分に機能しますが、実際には、各バイトのループはC#でバッファー全体を読み取るよりも遅くなる可能性があることがわかりました。

最良の方法は、ある種の適応長プロトコルを採用することです。たとえば、特定のサイズ(512バイトなど)のチャンクでデータを送信します。各チャンクの前に、System.BitConverterを介してチャンクのサイズを表す32ビット整数を送信します。したがって、メッセージは次のようになります(英語):

Here's 512 bytes:
[data]
Here's 512 bytes:
[data]
Here's 32 bytes:
[data]
Here's 4 bytes:
That was the whole file

ここでの利点は、コピー/読み取りバッファーを機能させることができることです(一度に512バイトを読み取る)。つまり、スループットはC#コードではなくネットワークスタックによって制限されます。クライアントは、固定長の32ビットintを読み取り、次の[data]セグメントに使用する必要があるバッファーのサイズを通知します。

このようなメッセージを書くためのコードは次のとおりです。

        logger.logger.debug("Sending message of length " + length);
        byte[] clength = System.BitConverter.GetBytes(buffer.Length);
        plaintextStream.Write(clength,0,clength.Length);
        plaintextStream.Write(buffer,0,buffer.Length);
        plaintextStream.Flush();

そして、それらを読むためのいくつかのコードがあります:

               byte[] intbuf = new byte[int_32_size];
        int offset = 0;
        while (offset < int_32_size)
        {
            int read = 0;

            read = d.plaintextStream.Read(intbuf,offset,int_32_size - offset);
            offset += read;

        }
        int msg_size = System.BitConverter.ToInt32(intbuf,0);
        //allocate a new buffer to fill the message
        byte[] msg_buffer = new byte[msg_size];
        offset = 0;
        while (offset < msg_size)
        {
            int read = 0;

            read = d.plaintextStream.Read(msg_buffer,offset,msg_size - offset);
            offset += read;
        }


        return msg_buffer;
于 2009-08-09T10:13:23.877 に答える
2

For transferring the files / data, you can use the TcpClient/TcpListener classes, which is nice abstractions over the grittier socket functionality. Or, you could simply have the application as a HTTP server using the HttpListener class, if that is easier/more appropiate for your application.

For discovery, if you are able to have a central server; then you could have each client connect to the server at startup, to register itself and retrieve a list of other online clients and their IP's. Subsequent communication can then take place directly between the clients.

A variation of this scheme, is to let the central server act as a proxy, which all traffic between the clients flow through. This would be mostly helpful to overcome firewall or routing issues if the clients is not on the same network (so it's propably not needed for your scenario).

于 2009-08-09T09:46:46.273 に答える
1

ファイルをコピーするには、MicrosoftSyncFrameworkの一部であるファイル同期プロバイダーも確認することをお勧めします。http://msdn.microsoft.com/en-us/sync/bb887623

于 2012-02-08T07:18:56.957 に答える