服务器(GUI)在启动后冻结。在控制台中工作正常

Posted

技术标签:

【中文标题】服务器(GUI)在启动后冻结。在控制台中工作正常【英文标题】:Server(GUI) freezes after starting. Works fine in Console 【发布时间】:2021-03-06 08:44:01 【问题描述】:

Server(GUI).png

服务器(图形用户界面)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;

namespace Server_ProfiChat

    public partial class Form1 : Form
    
        public Form1()
        
            InitializeComponent();
        

        static readonly object _lock = new object();
        static readonly Dictionary<int, TcpClient> list_clients = new Dictionary<int, TcpClient>();


        public static void handle_clients(object o)
        
            int id = (int)o;
            TcpClient client;

            lock (_lock) client = list_clients[id];

            while (true)
            
                NetworkStream stream = client.GetStream();
                byte[] buffer = new byte[1024];
                int byte_count = stream.Read(buffer, 0, buffer.Length);

                if (byte_count == 0)
                
                    break;
                

                string data = Encoding.ASCII.GetString(buffer, 0, byte_count);
                broadcast(data);
                Console.WriteLine(data);
                //var chatline = txtChat.Text;
                Form1 formObj = new Form1();
                formObj.txtChat.Text += data;
            

            lock (_lock) list_clients.Remove(id);
            client.Client.Shutdown(SocketShutdown.Both);
            client.Close();
        

        public static void broadcast(string data)
        
            byte[] buffer = Encoding.ASCII.GetBytes(data + Environment.NewLine);

            lock (_lock)
            
                foreach (TcpClient c in list_clients.Values)
                
                    NetworkStream stream = c.GetStream();

                    stream.Write(buffer, 0, buffer.Length);
                
            
        








        private void btnConnect_Click(object sender, EventArgs e)
        
            int count = 1;

            string serverIP = txtServerIP.Text;
            int serverPort = Int32.Parse(txtServerPort.Text);

            TcpListener ServerSocket = new TcpListener(IPAddress.Parse(serverIP), serverPort);
            ServerSocket.Start();

            while (true)
            
                TcpClient client = ServerSocket.AcceptTcpClient();
                lock (_lock) list_clients.Add(count, client);
                Console.WriteLine("Someone connected!!");

                Thread t = new Thread(handle_clients);
                t.Start(count);
                count++;
            
        
    

服务器(控制台)

using System;
using System.Threading;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;


namespace testServ

    class Program
    
        static readonly object _lock = new object();
        static readonly Dictionary<int, TcpClient> list_clients = new Dictionary<int, TcpClient>();

        static void Main(string[] args)
        
            int count = 1;

            TcpListener ServerSocket = new TcpListener(IPAddress.Parse("192.168.0.169"), 123);
            ServerSocket.Start();

            while (true)
            
                TcpClient client = ServerSocket.AcceptTcpClient();
                lock (_lock) list_clients.Add(count, client);
                Console.WriteLine("Someone connected!!");

                Thread t = new Thread(handle_clients);
                t.Start(count);
                count++;
            
        

        public static void handle_clients(object o)
        
            int id = (int)o;
            TcpClient client;

            lock (_lock) client = list_clients[id];

            while (true)
            
                NetworkStream stream = client.GetStream();
                byte[] buffer = new byte[1024];
                int byte_count = stream.Read(buffer, 0, buffer.Length);

                if (byte_count == 0)
                
                    break;
                

                string data = Encoding.ASCII.GetString(buffer, 0, byte_count);
                broadcast(data);
                Console.WriteLine(data);
            

            lock (_lock) list_clients.Remove(id);
            client.Client.Shutdown(SocketShutdown.Both);
            client.Close();
        

        public static void broadcast(string data)
        
            byte[] buffer = Encoding.ASCII.GetBytes(data + Environment.NewLine);

            lock (_lock)
            
                foreach (TcpClient c in list_clients.Values)
                
                    NetworkStream stream = c.GetStream();

                    stream.Write(buffer, 0, buffer.Length);
                
            
        
    


客户端(控制台)

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;


namespace test_Clie

    class Program
    
        static void Main(string[] args)
        
            IPAddress ip = IPAddress.Parse("192.168.0.166");
            int port = 123;
            TcpClient client = new TcpClient();
            client.Connect(ip, port);
            Console.WriteLine("client connected!!");
            NetworkStream ns = client.GetStream();
            Thread thread = new Thread(o => ReceiveData((TcpClient)o));

            thread.Start(client);

            string s;
            while (!string.IsNullOrEmpty((s = Console.ReadLine())))
            
                byte[] buffer = Encoding.ASCII.GetBytes(s);
                ns.Write(buffer, 0, buffer.Length);
            

            client.Client.Shutdown(SocketShutdown.Send);
            thread.Join();
            ns.Close();
            client.Close();
            Console.WriteLine("disconnect from server!!");
            Console.ReadKey();
        

        static void ReceiveData(TcpClient client)
        
            NetworkStream ns = client.GetStream();
            byte[] receivedBytes = new byte[1024];
            int byte_count;

            while ((byte_count = ns.Read(receivedBytes, 0, receivedBytes.Length)) > 0)
            
                Console.Write(Encoding.ASCII.GetString(receivedBytes, 0, byte_count));
                Console.Write(ns);
            
        
    


我是初学者,但对我来说这似乎与线程有关? 也因为它冻结了我看不到其余的是否正常工作,关于如何改进工作流程的任何想法,如寻找错误的确切点?我浪费了很多时间搜索任何东西,因为我不知道如何正确测试、调试和查明我犯的错误。

感谢任何帮助 =))

【问题讨论】:

控制台运行需要多长时间?表格将被锁定相同的时间。为了防止在表单应用程序中锁定,您必须在 BackGroundWorker 中运行代码。 (或异步任务)。 我是初学者,但对我来说似乎与线程有关?回答:是的。特别是您正在使用 UI 线程。它正在等待连接。 而不是lock/Dictionary,使用ConcurrentDictionary,它会做你想做的事,但更好。 【参考方案1】:

流通常完全按照您的要求执行。如果您要求 10 个字节,那么 Read 将不会返回,直到有 10 个字节要返回。 stream.Read 不会做的就是返回更少的字节,因为那是接收到的字节数。

此代码将阻塞,直到读取了 1024 个字节。

byte[] buffer = new byte[1024];
int byte_count = stream.Read(buffer, 0, buffer.Length);
if (byte_count == 0)

     break;

这是你所期待的吗?

通常,基于字节的协议有一个标头,其中包含有效负载中的字节数。

想象一下下面的协议:

&lt;stx&gt;&lt;soh&gt;&lt;len&gt;&lt;eoh&gt;&lt;payload&gt;&lt;etx&gt;

stx = 传输开始 soh = 标题开始 len = 有效载荷的长度 eoh = 标题结束 etx = 传输结束

要读取一个完整的数据包,您必须读取 4 个字节,然后您必须读取足够的字节来完成有效负载,那么最后一个字节应该是 ETX。

byte[5] header;
stream.Read(buffer, 0, 4);

int payloadLength = header[2];
byte[] payload = new byte[payloadLength];
stream.Read(payload, 0, payloadLength);
stream.Read() == ETX;

【讨论】:

【参考方案2】:

TcpListener.AcceptTcpClient 方法正在阻塞。您可以尝试使用它的异步对应物,并结合async/await:

private async void btnConnect_Click(object sender, EventArgs e)

    /* ... */
    TcpClient client = await ServerSocket.AcceptTcpClientAsync();
    /* ... */

【讨论】:

以上是关于服务器(GUI)在启动后冻结。在控制台中工作正常的主要内容,如果未能解决你的问题,请参考以下文章

SAP HANA DB 连接在控制台应用程序中工作正常,但同样的事情在服务中不起作用

请求在CURL中工作但不在Ajax中工作

尝试使用信号将 QTcpServer 连接到 GUI

从 GUI 启动服务器端操作并在操作完成后更新 GUI

反应原生应用程序在启动时在设备中崩溃。在模拟器中工作正常

启动 Laravel Artisan 命令队列的最佳方式:在共享主机中工作