2011-11-13 13 views
1

私はクライアント - サーバーアプリケーションを記述します。クライアントはプレーンなJava上でアンドロイドとサーバー上で動作します。私はクライアントからサーバーへ、そしてサーバーからクライアントへデータを交換する必要があります。私は、クライアントからサーバーにファイルを送信するときに、サーバーがソケットからデータを受け取っていることを知っています。ここに私のコードは次のとおりです。ライン、サーバー側のアンドロイドのJavaとソケット

while((bytesReceived = input.read(buffer))>0) { 
     out.write(buffer,0,bytesReceived); 
    } 

に貼り付け

System.out.println("I get data"); 
    File file=null; 

    InputStream input = sk.getInputStream(); 

    file = new File("C://protocolFIle/" + "temp.xml"); 
    FileOutputStream out = new FileOutputStream(file); 

    byte[] buffer = new byte[sk.getReceiveBufferSize()]; 

    int bytesReceived = 0; 

    while((bytesReceived = input.read(buffer))>0) { 
     out.write(buffer,0,bytesReceived); 
    } 

    return file; 

がサーバ:

Log.i("======", "sendToServer=============="); 
    OutputStream output = sk.getOutputStream();  

    String pathToOurFile = directory + File.separator + file; 

    FileInputStream fileInputStream = new FileInputStream(pathToOurFile); 
    byte[] buffer = new byte[sk.getSendBufferSize()]; 
    int bytesRead = 0; 

    while((bytesRead = fileInputStream.read(buffer))>0) 
    { 
     output.write(buffer,0,bytesRead); 
    } 

    fileInputStream.close(); 

サーバーがデータを取得する:

クライアントがファイルを送信します。私はデータを送信し終えたら何とかクライアント側で信号を送る必要があると思う。私はクライアント側で "output.close()"を書くことができると知っているし、サーバはファイルを取得しwhileループを中断しますが、将来この出力が必要になります。誰も知っているどのように私はこのファイルを送信することはできませんサーバーは固執しない?多分私は別の方法でこのファイルを送る必要があります。助けてくれてありがとう。

答えて

2

close()をクライアント側で使用すると、実際には役に立ちません。close()などのTCP/IP APIメソッドは、アプリケーション層でのメッセージの終了を通知する手段として非常に役に立たないためです。その理由は、クライアント側でTCPストリームを閉じると、直ちに反対側のクライアントにTCP接続全体が閉じられるわけではないからです。これはすべて、TCPの基礎となるアーキテクチャと関係します。

あなたがしなければならないことは、メッセージの長さを識別するアプリケーションプロトコルレベルの手段、またはその他のメッセージ「フレーミング」の手段を実装することです。あなたがするのが最も簡単なのは、メッセージの先頭に基本的なヘッダーを実装することです。メッセージの長さはU32メッセージの長さ(たとえばちょうど)を表す4バイトを超えるものではありません。

私がTCPに関してもう一度重視することは、TCPプロトコルそのもの、特にclose()のようなものが、TCP経由で送信しているアプリケーションメッセージの開始/停止を確実に通知する手段を提供していないことです。 TCPはストリームプロトコルと考える必要があります。そのため、長さフィールド、フレーミング文字、または受信側が完全なメッセージを持つように.read()コールから十分に読み込んだときを示すいくつかの他の手段を持つ特別なヘッダーもそのストリームに配置する必要があります。

私は最近、TCPソケットを使用してサーバーC#アプリケーションと通信するAndroidアプリケーションを作成しました。ストリーム上でシンプルで比較的短いメッセージしか送信していませんが、非常に基本的なメッセージフレームとメッセージヘッダーの実装は絶対に欠かせない。

メッセージの長さまたは終端のシグナリングは、アプリケーションプロトコルレベルで行う必要があります。

また、TCP接続を両端で閉じるべきであることのシグナリングも、アプリケーションプロトコルレベルで行う必要があります。 StackOverflowを検索すると、多くの人がTCP接続が閉じられているかどうかの検出に問題が発生することがよくあります。問題は、これが本質的に物事について間違った方法であるということです。どの言語のTCPソケットAPIも、ストリームが閉じられたことを確実に伝えることはできません。

TCPソケットを使用する一般的なプロトコルの例であるHTTPを見ると、このプロトコルでは、長さを示すヘッダーと、接続が終了することを示すフラグと、メッセージが断片化されているなどです。

あなたの特定の問題に戻って、Android側の最初のwrite()で行うべきことは、長さフィールドを含む簡単なメッセージヘッダーを作成して作成することです。サーバー側では、最初のread()は、ファイルペイロードの開始前にこのヘッダーを参照する必要があります。そのヘッダーに指定されている長さを使用して、ファイルがすべてread()のときを判別します。

後でヘッダーを展開して、CRC値などを含めることができます。