简体   繁体   English

C#TcpClient更新(对于IRC客户端)

[英]C# TcpClient updating (for an IRC client)

I am bascially trying to make a barebones IRC client with C#, WinForms, and TcpClient that will display raw data from the irc server onto the the text area (textbox1). 我基本上是在尝试使用C#,WinForms和TcpClient创建一个准系统的IRC客户端,该客户端将把来自irc服务器的原始数据显示到文本区域(textbox1)。 However I am struggling on the updating code (reading the stream from the server). 但是,我正在努力更新代码(从服务器读取流)。 Right now I have a timer that runs a function ( listener ) that reads from the TCP stream every 100ms. 现在,我有一个计时器,它运行一个函数( listener ),每100ms从TCP流中读取一次。 However my application freezes and the cursor disapeears, and the application hangs trying to grab more data. 但是,我的应用程序冻结,并且光标消失了,并且该应用程序挂起,试图获取更多数据。 So what would be a better updating function? 那么,什么是更好的更新功能呢?

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

namespace LogernIRC
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        //Variables
        TcpClient client;
        StreamReader sr;
        StreamWriter sw;
        //Functions
        public void connect(string host)
        {
            client = new TcpClient(host, 6667);
            sr = new StreamReader(client.GetStream());
            sw = new StreamWriter(client.GetStream());
        }
        public void write(string str)
        {
            textBox1.Text += str;
        }
        public void sendData(string str)
        {
            sw.WriteLine(str);
            sw.Flush();
        }
        public void listener()
        {
                string data = sr.ReadLine();
                write(data);
        }
        //End Functions
        private void Form1_Load(object sender, EventArgs e)
        {
            //Initialize
            write("Welcome to LogernIRC. Type \"/help\" for help with commands.\r\n");
        }

        private void button1_Click(object sender, EventArgs e) //Submit button clicked
        {
            //TextBox 1 is the text area , textbox 2 is the message/command area
            //Command Area
            if (textBox2.Text == "/help")
            {
                write("Help:\r\n/connect Connect to IRC server\r\n/help Display this help menu\r\n/join Join channel");
            }
            if (textBox2.Text.StartsWith("/connect"))
            {
                write("\r\nConnecting to " + textBox2.Text.Split(' ')[1] + " on port 6667...");
                connect(textBox2.Text.Split(' ')[1]);
            }
            if (textBox2.Text.StartsWith("/join"))
            {
                write("\r\nJoining channel " + textBox2.Text.Split(' ')[1]);
            }
            if (textBox2.Text == "/test")
            {
                timer1.Start();
                connect("irc.freenode.net");
                write("\r\nActivating test function...");
                sendData("NICK Logern");
                sendData("USER Logern 0 * :LOGERN");
                listener();
            }
        }

        private void timer1_Tick(object sender, EventArgs e) 
        {
            //Read Data
            listener();
        }
    }
}

It's not running async, right? 它没有异步运行,对吗? So the UI will lock up until the loop is done. 因此,UI将锁定,直到循环完成。 You're looping forever, right? 你永远循环,对不对? That's pretty common with IRC bots/clients; 这在IRC漫游器/客户端中很常见。 I've done it myself. 我自己做的

If so, and if you're using NET 4.0 and above, you could try this: 如果是这样,并且如果您使用的是NET 4.0及更高版本,则可以尝试以下操作:

await Task.Run(()=> { CodeThatLoopsForever(); });

Let me try to explain it better. 让我尝试更好地解释它。 Let's say for example you have a function like this: 例如,假设您有一个类似的功能:

private void Connect()
{
    while (true)
    {
        // Do socket listening 
    }
}

And you call it from clicking a button, like this: 您可以通过单击按钮来调用它,如下所示:

private void btn_Connect_Click(object sender, EventArgs e)
{
    Connect();
}

You could just change that button code to this: 您可以将按钮代码更改为此:

private async void btn_Connect_Click(object sender, EventArgs e)
{
    await Task.Run(()=> { Connect(); });
}

Hope this helps! 希望这可以帮助!

UPDATE : .NET 4.0 and above! 更新 :.NET 4.0及更高版本!

The delay happens when your timer event is raised, but there's no data to read. 当引发您的计时器事件时,会发生延迟,但是没有要读取的数据。 It will just sit and wait until there is. 它只会坐着等到那里。 The best way to address the issue is to use asynchronous operations to handle the I/O. 解决此问题的最佳方法是使用异步操作来处理I / O。 For example: 例如:

public Form1()
{
    InitializeComponent();
}
//Variables
TcpClient client;
StreamReader sr;
StreamWriter sw;
//Functions
public void connect(string host)
{
    client = new TcpClient(host, 6667);
    sr = new StreamReader(client.GetStream());
    sw = new StreamWriter(client.GetStream());
}
public void write(string str)
{
    textBox1.Text += str;
}
public void sendData(string str)
{
    sw.WriteLine(str);
    sw.Flush();
}
public async Task listener()
{
    try
    {
        string data

        while ((data = await sr.ReadLineAsync()) != null)
        {
            write(data);
        }
    }
    catch (ObjectDisposedException)
    {
        // socket was closed forcefully
    }
}
//End Functions
private void Form1_Load(object sender, EventArgs e)
{
    //Initialize
    write("Welcome to LogernIRC. Type \"/help\" for help with commands.\r\n");
}

private void button1_Click(object sender, EventArgs e) //Submit button clicked
{
    //TextBox 1 is the text area , textbox 2 is the message/command area
    //Command Area
    if (textBox2.Text == "/help")
    {
        write("Help:\r\n/connect Connect to IRC server\r\n/help Display this help menu\r\n/join Join channel");
    }
    if (textBox2.Text.StartsWith("/connect"))
    {
        write("\r\nConnecting to " + textBox2.Text.Split(' ')[1] + " on port 6667...");
        connect(textBox2.Text.Split(' ')[1]);
    }
    if (textBox2.Text.StartsWith("/join"))
    {
        write("\r\nJoining channel " + textBox2.Text.Split(' ')[1]);
    }
    if (textBox2.Text == "/test")
    {
        connect("irc.freenode.net");

        // initiate async reading (storing the returned Task in a variable
        // prevents the compiler from complaining that we don't await the
        // call).
        var _ = listener();

        write("\r\nActivating test function...");
        sendData("NICK Logern");
        sendData("USER Logern 0 * :LOGERN");
    }
}

The above example leaves out some error-checking and other niceties, but it's the basic idea of what you want to do. 上面的示例省略了一些错误检查和其他细节,但这是您想要做什么的基本思想。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM