C#套接字发送/接收问题和疑问

时间:2013-11-13 10:31:05

标签: c# sockets tcp

早上好,

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

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

大部分项目已经完成。逻辑基本上是完整的,它是多线程的,所有类都准备就绪,大多数测试都有效。

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

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

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

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

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

    如果有人能对此有所了解,或者告诉我应该改变什么......或者基本上任何可以让我再次前进的事情,我将非常感激!

1 个答案:

答案 0 :(得分:0)

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

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