0

大家早上好,

首先为有点笼统的标题道歉。如果在这个消息的过程中我能想出一些更详细的东西,我一定会改变它。

我正在开发一个包含 3 个程序的项目。目的是能够向所有连接的客户端发送通知。为此,有一个服务器、客户端和控制台程序。消息本身将是一个 RTF 文件,但通知还需要一个发送部门(字符串)和一个显示计时器(TimeSpan)。

大部分项目已经完成。逻辑大部分是完整的,它是多线程的,所有的类都准备好了,并且大多数测试都可以工作。

我遇到的问题是服务器似乎没有以正确的顺序从控制台接收数据。从而引发各种问题。

从控制台到服务器的过程如下:

  1. 控制台首先选择通知的所有相关信息:

    • 用户(列表,从 LDAP 收集)
    • 到期日期和时间 (DateTime)
    • 允许关闭前的时间(长,刻度数)
    • 部门(字符串)
    • RTF 文件
  2. 服务器已经处于活动状态,并且有一个单独的线程用于控制台连接

  3. 控制台连接到服务器
  4. 服务器创建一个单独的线程来处理控制台连接
  5. 控制台将登录用户的用户名发送到服务器
  6. 服务器检查是否允许用户创建通知(现在它总是返回 true)
  7. 控制台按以下顺序发送所有相关信息:
    • 消息 ID(字符串)
    • RecipientCount(用户数,用于从服务器端适当循环)
    • 收件人(列表的 foreach 循环)
    • 部门(字符串)
    • 可见时间(长)
    • 到期(日期时间)
    • 最后是 RTF 文件

我使用 System.Diagnostics.Trace 来检查所有信息是否以正确的顺序正确发送。这一切都检查出来了。但问题是,大约 75% 的时间服务器端似乎在接收 RTF 文件时应该接收到 visibleTime。

代码如下:

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

您的问题可能源于您使用 aStreamReader从连接中读取数据的事实。在内部StreamReader缓冲它从底层读取的数据Stream。每次尝试从连接中读取时,您都会创建一个新StreamReader的,然后在读取一行后将其丢弃。这样做时,您还将丢弃从连接中读取的任何数据,这些数据由 缓冲StreamReader(可能构成以下字段的全部或部分)。

您可能应该尝试在网络流上创建一个StreamReader,并为所有读取使用相同的实例。

于 2013-11-13T11:27:08.427 回答