1

私はC#とクライアントサーバープログラミングの両方に不慣れです。現在、クラスでは、事前に確立されたFTPライブラリを使用せずにFTPクライアントを作成しようとしています。ほとんどの部分でプロジェクトがダウンしているように感じますが、データポート(list、retrなど)の使用を必要とする複数の呼び出しを行うと問題が発生します。コードのサンプルを次に示します。それは壊れています:

writer.WriteLine(portcmd);
writer.Flush();

GetServerMessage(stream);

writer.WriteLine("list ");
writer.Flush();


tmpserver = new TcpListener(IPAddress.Any, 3128);
tmpserver.Start(); 
tmpclient = tmpserver.AcceptTcpClient();
Console.WriteLine("gothere");

if (!tmpclient.Connected)
{
    tmpserver.Start();
}

StreamReader tmpreader = new StreamReader(tmpclient.GetStream());

GetServerMessage(stream);
while (tmpreader.Peek() != -1)
{
    Console.WriteLine(tmpreader.ReadLine());
}

tmpclient.Close();
tmpserver.Stop();

GetServerMessage(stream);

Getservermessageは、ネットワークストリームを取得し、0.5秒のタイムアウト内に利用可能なすべてのものを出力するメソッドです。ストリームは、FTPサーバーへの現在の接続用のNetworkStreamであり、ライターは、ASCIIの記述を容易にするためにStreamReaderでラップされた同じネットワークストリームです。サーバーへの文字。なぜストリームリーダーを使用してデータ接続から読み取るのか疑問に思われるかもしれませんが、サーバーがデータを送信した後に接続を閉じるため、eof通知を簡単に受け取ることができます。閉じたネットワークストリームを使用したときに、GetServerMessageメソッドが何らかの理由で壊れていました。

このコードは、ポートコマンドをFTPサーバーに送信して、データ接続が必要であることを通知します(最初の2行)。次に、listコマンドを送信し、サーバーへのデータ接続を確立し、必要な情報を取得してから、データ接続(残りのコード)。

このコードは、最初に実行したときに問題なく実行されますが、再試行すると、「tmpclient = tmpserver.AcceptTcpClient();」でハングします。ライン。「gothere」の印刷ステートメントに到達することはありません。これは、同じポートの同じマシンからクライアントを受信して​​いるためだと思いますが、よくわかりません。AcceptTcpClient()が1回だけ実行されるようにブール値を追加しようとしましたが、ランタイムエラーが発生し、Visual Studioから、「リソースを使用する前にリソースを解放した」可能性があると通知されました。これは問題になると予測しましたが、サーバーが一度接続を閉じた後に接続を再確立したかどうかを確認するにはどうすればよいですか?

与えられたコードの終わりに、私はtmpserverを停止し、tmpclientを閉じます。もともとこれを行ったのは、FTPサーバーが送信を終了したときに接続を閉じることを知っていて、それが適切なことだと思ったからです。これらの行をコメントアウトすると、コードは複数回実行されますが、ストリームは空のように見えます...この情報が役立つかどうかはわかりませんが、言及したいと思います。

不明な点がある場合はお詫び申し上げますが、主題に関する知識が不足しているため、問題を明確にすることが困難です。問題が何であるかについて混乱があれば、私はそれを解決しようと喜んで試みます。

4

3 に答える 3

3

別のクライアントを受け入れることができるようにするには、実行tmpclient = tmpserver.AcceptTcpClient();して最初のクライアントがその作業を完了するのを待つ(2番目のクライアントを受け入れる前に)のは良い考えではないかもしれません

これは、接続を待機し、各クライアントから送信された文字列をエコーするサンプルサーバーコードです。あなたはそれをテストすることができますtelnet localhost 3128

Thread t = new Thread(Server);
t.IsBackground = true;
t.Start();

-

void Server()
{
    TcpListener listener = new TcpListener(IPAddress.Any, 3128);
    listener.Start();
    while (true)
    {
        var client = listener.AcceptTcpClient();
        new Thread(() =>
        {
            using (client)
            {
                var reader = new StreamReader(client.GetStream());
                var writer = new StreamWriter(client.GetStream());
                while (true)
                {
                    string line = reader.ReadLine();
                    if (line == "QUIT") break;
                    writer.WriteLine("From Thread[" + Thread.CurrentThread.ManagedThreadId + "] > " + line);
                    writer.Flush();
                }
            }
        }).Start();
    }
}
于 2012-04-24T21:34:43.807 に答える
0

OK、こんな感じです。簡単な方法でサーバーを実行するには、クライアントソケットを処理するコードをスレッド化する必要があります。acceptが戻ったら、スレッドを作成して開始し、「tmpclient」を渡してから、accept呼び出しに再度ループして、新しいクライアントが接続できるようにします。新しく生成されたserver<>クライアントスレッドで、渡されたソケットに対してループで読み取りと書き込みを行い、クライアントと通信します。

于 2012-04-24T21:13:26.267 に答える
0

tcpクライアントストリームを閉じると、そこからプルしたストリームから読み取ることはできなくなります。

var stream = tcpClient.GetStream();
...
tcpclient.Close();
...
stream.Read .. fail

クライアントは別の接続を要求する必要がありますが、

また

TCPクライアントソケットを開いたままにしておく必要があります。

より複雑なサーバーは、クライアントに関する一部のメタデータ(状態)をキャッシュしておくため、ソケットが予期せず閉じた場合、クライアントがすぐに再接続を試みても、サーバーはスムーズに処理を続行できます。

于 2012-04-24T21:13:48.790 に答える