【问题标题】:WPF server applicationWPF 服务器应用程序
【发布时间】:2013-01-30 08:02:17
【问题描述】:

我有一个 WPF 服务器和客户端应用程序。 当我启动服务器时,它开始收听传入的消息。但是,应用程序不能被触摸或关闭,它在监听中“卡住”了。我必须补充一点,它在处理消息等方面做了它应该做的事情。但我就是无法与表单交互。 它与异步服务器套接字有关吗?我不确定要寻找什么...

这是我的服务器代码:

    private void startServer()
    {
        sck = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        sck.Bind(new IPEndPoint(0, serverPort));
        sck.Listen(100);

        while (true)
        {
            Socket accepted = sck.Accept();

            Buffer = new byte[accepted.SendBufferSize];
            int bytesRead = accepted.Receive(Buffer);

            byte[] formatted = new byte[bytesRead];

            for (int i = 0; i < bytesRead; i++)
            {
                formatted[i] = Buffer[i];
            }
            string command = Encoding.ASCII.GetString(formatted);
            string[] splittedCommand = command.Split(' ');

            jobsHistory.Items.Add(Encoding.ASCII.GetString(formatted));
            jobsHistory.Refresh();

            Process processToRun = new Process();
            processToRun.StartInfo.FileName = splittedCommand[0];
            processToRun.StartInfo.WorkingDirectory = Path.GetDirectoryName(splittedCommand[0]);
            processToRun.StartInfo.Arguments = "";
            for (int i = 1; i < splittedCommand.Length; i++)
            {
                processToRun.StartInfo.Arguments += " " + splittedCommand[i];
            }

            processToRun.Start();
            accepted.Close();
        }
    }

【问题讨论】:

    标签: c# wpf sockets client-server


    【解决方案1】:

    如果这在 UI 线程上有效,那么您将其捆绑在循环中。它没有机会处理任何 UI 事件。除此之外,Socket.Receive 是一个阻塞调用。

    本网站和 Google 上都有很多关于 BackgroundWorker` 类的文章。我建议你调查一下。

    【讨论】:

      【解决方案2】:

      您应该使用BeginAccept 在后台接受连接,而不会阻塞 UI 线程。当客户被接受时,再次调用BeginAccept - 这会创建一个“循环”。然后,您可以删除 while 循环。

      startServer 方法可能如下所示:

      private void startServer()
      {
          sck = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
          sck.Bind(new IPEndPoint(0, serverPort));
          sck.Listen(100);
      
          sck.BeginAccept(Accepted, sck);
      }
      

      然后,在Accepted 方法中,执行以下操作:

      private void Accepted(IAsyncResult result)
      {
          Socket sck = result.AsyncState as Socket;
          Socket client = sck.EndAccept(result);
      
          sck.BeginAccept(Accepted, sck);
      }
      
      
              Socket accepted = sck.Accept();
      

      【讨论】:

        【解决方案3】:

        只需在单独的线程中执行监听,就像这样 -

            private void startServer()
            {
                sck = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                sck.Bind(new IPEndPoint(0, 8080));
        
                new Thread(() => StartListening(sck)).Start();
            }
        
            void StartListening(Socket socket)
            {
                socket.Listen(100);
        
                Accept(socket);
            }
        
            void Accept(Socket socket)
            {
                while (true)
                {
                    Socket accepted = socket.Accept();
        
                    Buffer = new byte[accepted.SendBufferSize];
                    int bytesRead = accepted.Receive(Buffer);
        
                    byte[] formatted = new byte[bytesRead];
        
                    for (int i = 0; i < bytesRead; i++)
                    {
                        formatted[i] = Buffer[i];
                    }
                    string command = Encoding.ASCII.GetString(formatted);
                    string[] splittedCommand = command.Split(' ');
        
                    jobsHistory.Items.Add(Encoding.ASCII.GetString(formatted));
                    jobsHistory.Refresh();
        
                    Process processToRun = new Process();
                    processToRun.StartInfo.FileName = splittedCommand[0];
                    processToRun.StartInfo.WorkingDirectory = Path.GetDirectoryName(splittedCommand[0]);
                    processToRun.StartInfo.Arguments = "";
                    for (int i = 1; i < splittedCommand.Length; i++)
                    {
                        processToRun.StartInfo.Arguments += " " + splittedCommand[i];
                    }
        
                    processToRun.Start();
                    accepted.Close();
                }
        
                // If you want to start listening again
                socket.Close();
                startServer();
            }
        

        【讨论】:

        • 首先,感谢您的回复。现在可以了。但是,如果我连接,然后断开,然后重新连接,则会抛出异常,说:“每个套接字地址(协议/网络地址/端口)通常只允许使用一次”。
        • @Idanis 这可能是因为您执行操作的速度太快,并且套接字实际上还没有被释放。
        • 尝试关闭socket,然后再次调用startServer...查看我对Accept 方法的更新...
        • 我修改了我的代码。只是想展示大局。我有一个“侦听”按钮,当套接字正在侦听时,它会变为“断开连接”,反之亦然。如您所见,我添加了更改,但现在我无法断开连接或重新连接......我在这里错过了什么?谢谢...
        • 我认为您应该针对连接/断开连接问题提出一个新问题,在那里获得答案的机会很大。同时如果这个答案解决了你原来的问题,请将其标记为答案,以便于其他搜索相同问题的人有所帮助。
        猜你喜欢
        • 2011-07-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-14
        • 2013-04-06
        相关资源
        最近更新 更多