0

みんなおはよう、

まず、やや一般的なタイトルでお詫び申し上げます。このメッセージの過程で、もう少し詳細な情報を思いつくことができれば、間違いなく変更します。

私は 3 つのプログラムを含むプロジェクトに取り組んでいます。目的は、接続されているすべてのクライアントに通知を送信できるようにすることです。このために、サーバー、クライアント、およびコンソール プログラムがあります。メッセージ自体は RTF ファイルになりますが、通知には送信部門 (文字列) と表示タイマー (TimeSpan) も必要です。

プロジェクトのほとんどが完了しました。ロジックはほぼ完成しており、マルチスレッド化されており、すべてのクラスの準備が整っており、ほとんどのテストが機能しています。

私が抱えている問題は、サーバーがコンソールから正しい順序でデータを受信して​​いないように見えることです。それによってあらゆる種類の問題を引き起こします。

コンソールからサーバーへのプロセスは次のとおりです。

  1. コンソールは、最初に通知に関連するすべての情報を選択します。

    • ユーザー (リスト、LDAP から収集)
    • 有効期限の日時 (DateTime)
    • クローズまでの時間 (ロング、ティック数)
    • 部門 (文字列)
    • RTF ファイル
  2. サーバーはすでにアクティブであり、コンソール接続用に別のスレッドがあります

  3. コンソールがサーバーに接続
  4. サーバーは、コンソール接続を処理するために別のスレッドを作成します
  5. コンソールは、ログオンしているユーザーのユーザー名をサーバーに送信します
  6. サーバーは、ユーザーが通知の作成を許可されているかどうかを確認します (今のところ、常に true を返します)
  7. コンソールは、すべての関連情報を次の順序で送信します。
    • メッセージ ID (文字列)
    • RecipientCount (サーバー側から適切にループするために使用されるユーザー数)
    • 受信者 (リストの foreach ループ)
    • 部門 (文字列)
    • VisibleTime (長い)
    • 有効期限 (日時)
    • 最後にRTFファイル

System.Diagnostics.Trace を使用して、すべての情報が正しい順序で正しく送信されているかどうかを確認しました。これはすべてチェックアウトします。しかし問題は、およそ 75% の時間でサーバー側が RTF ファイルを受信して​​いるように見えるということです。

コードは次のとおりです。

private void SendMessage()
{
    SendToServer(Environment.UserName);
    if (bool.Parse(ReadFromServer()))
    {
        // User is allowed, continue
        string messageID = DateTime.Now.ToUniversalTime().Ticks.ToString();
        SendToServer(messageID); // MessageID

        string recipientCount = lvRecipients.Items.Count.ToString();              
        SendToServer(lvRecipients.Items.Count.ToString()); // Amount of recipients

        foreach (string item in lvRecipients.Items) // Loop to send each recipient
        {
            SendToServer(item);
        }

        string department = TB_Department.Text;
        SendToServer(department); // Send department string

        string visibleTime = TimeSpan.FromSeconds(SLIDER_VisibleTime.Value).Ticks.ToString();
        SendToServer(visibleTime); // Send message visibility time

        string expiration = DateTime.Now.ToUniversalTime().AddMinutes(2).ToString();
        SendToServer(expiration); //TODO add UI control for this

        SendRTFToServer(); // Send RTF file

        MessageBox.Show(
            "Your designated MessageID is: " + messageID + Environment.NewLine +
            "Message upload is succesful.",
            "Complete",
            MessageBoxButton.OK);
    }
    else
    {
        // User is not allowed. Report to user. Disconnect (will be managed by the finally block)
        MessageBox.Show(
                "You are not allowed to upload messages to the server.",
                "Access denied",
                MessageBoxButton.OK,
                MessageBoxImage.Stop);
        return;
    }

}


private void SendToServer(string toSend)
{
    StreamWriter writer = new StreamWriter(server.GetStream());
    writer.WriteLine(toSend);
    writer.Flush();
}


private void SendRTFToServer()
{
    StreamReader rtfFile = new StreamReader(File.Open(RTFLocation, FileMode.Open, FileAccess.Read));
    StreamWriter sw = new StreamWriter(server.GetStream());
    sw.Write(rtfFile.ReadToEnd());
    sw.Flush();
    server.GetStream().Flush();
}

private string ReadFromServer()
{
    server.GetStream().Flush();
    StreamReader reader = new StreamReader(server.GetStream());
    return reader.ReadLine();
}

そしてサーバーから:

private void Connect()
{
    string username = ReadFromConsole();

    if (IsUserAllowed(username)) // Receive username
        SendToConsole(bool.TrueString); // Send confirmation
    else
    {
        SendToConsole(bool.FalseString); // Send denial
        console.Close();
        return;
    }

    string messageID = ReadFromConsole(); // Receive MessageID

    string recipientCount = ReadFromConsole();

    int numOfRecipients = int.Parse(recipientCount); // Receive and parse number of recipients

    List<string> recipients = new List<string>();
    for (int i = 0; i < numOfRecipients; i++)
    {
        string recipient = ReadFromConsole();
        recipients.Add(recipient); // Receive recipient, add to list (required for Message)
    }

    string department = ReadFromConsole(); // Receive department string

    string visibleTime = ReadFromConsole();

    string expiration = ReadFromConsole();

    StoreRTF(messageID); // Receive and store RTF file

    console.Close(); // Connection is done, close

    Message message = new Message(messageID, department, recipients, visibleTime, expiration);
}

private void SendToConsole(string toSend)
{
    // Open client stream, and write information to it.
    StreamWriter writer = new StreamWriter(console.GetStream());
    writer.WriteLine(toSend);
    writer.Flush();
}

private string ReadFromConsole()
{    
    // Read information from client stream
    StreamReader reader = new StreamReader(console.GetStream());
    return reader.ReadLine();
}

private void StoreRTF(string messageID)
{
    // Check/create folder for Message storage
    string messageFolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\BMNotify\";
    if (!Directory.Exists(messageFolder))
        Directory.CreateDirectory(messageFolder);

    // Create file to store message in
    Stream rtfFile = File.Create(messageFolder + messageID + ".rtf");

    // Store information from stream, and close resources
    console.GetStream().CopyTo(rtfFile);
    rtfFile.Close();
    rtfFile.Dispose();

}

そしてメッセージクラス:

public class Message
{
    internal string messageID;
    internal string department;
    internal List<string> recipients;
    internal TimeSpan visibleAtLeast;
    internal DateTime messageExpiration;

    private static List<Message> allMessages; // Will hold te collection of Message's

    public Message(string _messageID, string _department, List<string> _recipients, string visibleTime, string expiration)
    {
        messageID = _messageID;
        recipients = _recipients;
        department = _department;

        visibleAtLeast = TimeSpan.FromTicks(long.Parse(visibleTime));
        messageExpiration = DateTime.Parse(expiration);

        if (allMessages == null)
            allMessages = new List<Message>(); // Initialize if required

        allMessages.Add(this);
    }

    internal Stream GetRTF()
    {
        return File.Open
            (Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\BMNotify\" + messageID + ".rtf",
            FileMode.Open, 
            FileAccess.Read, 
            FileShare.Read);
    }

    static public List<Message> AllMessages()
    {
        if (allMessages == null)
            allMessages = new List<Message>(); // Initialize if required

        return allMessages;
    }

    static public void RemoveMessage(Message message)
    {
        allMessages.Remove(message);
    }
}

誰かがこれに光を当てたり、私が何を変えるべきかを教えてくれたら.. または基本的に私を再び動かすことができるものなら何でも、私はとても感謝しています!

4

1 に答える 1

0

問題はStreamReader、接続からデータを読み取るために を使用していることが原因である可能性があります。StreamReader基になる から読み取ったデータを内部的にバッファリングしますStream。接続から読み取ろうとするたびに新しいものを作成しStreamReader、1行読み取ったら破棄します。そうすることで、StreamReader(次のフィールドのすべてまたは一部を構成している可能性がある) によってバッファリングされた接続から読み取られたデータも破棄されます。

StreamReaderネットワーク ストリーム上に1 つのインスタンスを作成し、すべての読み取りに同じインスタンスを使用するようにしてください。

于 2013-11-13T11:27:08.427 に答える