GUI在c#socket中冻结

时间:2015-09-26 18:01:59

标签: c# sockets

我使用套接字编程在c#中创建了一个接收服务器的文件。我做了一个GUI。有一个名为' connect' 的按钮,它会在点击它时启动服务器,并且有一个文本框,当服务器启动时会显示一条消息。但是当我点击按钮时,GUI会冻结。

以下是我的示例代码:

using System;
using System.Drawing;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Collections.Generic;

class sampleserver : Form
{

    private TextBox newText;
    public TcpClient tcpClient;
    public TcpListener tcpListener;
    public sampleserver()
{
    Text = " TCP Server";
    Size = new Size(400, 380);        
    newText = new TextBox();
    newText.Parent = this;
    newText.Size = new Size(200, 2 * Font.Height);
    newText.Location = new Point(10, 55);

    Button connect = new Button();
    connect.Parent = this;
    connect.Text = "Connect";
    connect.Location = new Point(295, 20);
    connect.Size = new Size(6 * Font.Height, 2 * Font.Height);
    connect.Click += new EventHandler(ButtonConnectOnClick);        

}


void ButtonConnectOnClick(object obj, EventArgs ea)
{
    tcpListener = new TcpListener(IPAddress.Any, 1234);
    tcpListener.Start();
    newText.Text = "Server started"; //**This line is not working**

    //Infinite loop to connect to new clients      
    while (true)
    {
        // Accept a TcpClient      
        TcpClient tcpClient = tcpListener.AcceptTcpClient();
        string address = ((IPEndPoint)tcpClient.Client.RemoteEndPoint).Address.ToString();

                   byte[] data = new byte[1024];
        NetworkStream ns = tcpClient.GetStream();
        int recv = ns.Read(data, 0, data.Length);
                    StreamReader reader = new StreamReader(tcpClient.GetStream());

        // The first message from the client is the file size      
        string cmdFileSize = reader.ReadLine();


        int length = Convert.ToInt32(cmdFileSize);
        byte[] buffer = new byte[length];
        int received = 0;
        int read = 0;
        int size = 1024;
        int remaining = 0;

        // Read bytes from the client using the length sent from the client      
        while (received < length)
        {
            remaining = length - received;
            if (remaining < size)
            {
                size = remaining;
            }

            read = tcpClient.GetStream().Read(buffer, received, size);
            received += read;
        }

    }

}
public static void Main()
{
    Application.Run(new sampleserver());
}
}

我需要做哪些更改才能正常运行?

2 个答案:

答案 0 :(得分:1)

我建议您使用异步套接字,但您也可以只使用按钮点击方法异步,就像这样。

async void ButtonConnectOnClick(object obj, EventArgs ea)
{
tcpListener = new TcpListener(IPAddress.Any, 1234);
tcpListener.Start();
newText.Text = "Server started"; //**This line is not working**
  await Task.Run(() =>
   {
//Infinite loop to connect to new clients      
while (true)
{
    // Accept a TcpClient      
    TcpClient tcpClient = tcpListener.AcceptTcpClient();
    string address = ((IPEndPoint)tcpClient.Client.RemoteEndPoint).Address.ToString();

               byte[] data = new byte[1024];
    NetworkStream ns = tcpClient.GetStream();
    int recv = ns.Read(data, 0, data.Length);
                StreamReader reader = new StreamReader(tcpClient.GetStream());

    // The first message from the client is the file size      
    string cmdFileSize = reader.ReadLine();


    int length = Convert.ToInt32(cmdFileSize);
    byte[] buffer = new byte[length];
    int received = 0;
    int read = 0;
    int size = 1024;
    int remaining = 0;

    // Read bytes from the client using the length sent from the client      
    while (received < length)
    {
        remaining = length - received;
        if (remaining < size)
        {
            size = remaining;
        }

        read = tcpClient.GetStream().Read(buffer, received, size);
        received += read;
    }

     }

 });
}

这会使整个方法异步,现在您可以从套接字读取而不冻结主UI。

古德勒克。

答案 1 :(得分:0)

UI事件通常意味着运行然后返回。您的程序正在启动应该在线程中启动的代码 - 通过按钮代码 - 然后在应用程序退出时正确停止。

正如Ron Beyer所说,你有一个while(true),但我更感兴趣的是读取是否超时以及按下按钮后如何返回主UI线程。看起来你永远不会回到主UI线程。正如我的评论所述,我测试网络代码,包括控制台应用程序中的while循环,然后添加UI的复杂性。

顺便说一下,正如其他评论所指出的那样,当您设置此代码以便网络设置(启动)成功时,您无法再次单击启动按钮。您必须禁用(灰显)按钮,因此无法双击,并且仅在网络启动(启动)失败时才启用。第二个按钮,不是灰色的,可以让你关闭所有东西。

线程和用户界面并不是你相信的简单。他们需要做很多工作。