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

时间:2014-12-01 23:35:27

标签: c# winforms tcp tcpclient irc

我基本上试图使用C#,WinForms和TcpClient创建一个准系统IRC客户端,它将从irc服务器显示原始数据到文本区域(textbox1)。但是我正在努力更新代码(从服务器读取流)。现在我有一个运行一个函数(listener)的计时器,它每100毫秒从TCP流中读取一次。然而,我的应用程序冻结,光标消失,应用程序挂起试图获取更多数据。那么什么是更好的更新功能?

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();
        }
    }
}

2 个答案:

答案 0 :(得分:1)

它没有运行异步,对吧?因此UI将锁定直到循环完成。你永远在循环,对吧?这对于IRC机器人/客户来说非常普遍;我自己做过。

如果是这样,如果你使用的是.NET 4.0及以上版本,你可以试试这个:

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

让我试着更好地解释一下。让我们举个例子说你有这样的函数:

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

你可以通过点击按钮来调用它,如下所示:

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

您只需将该按钮代码更改为:

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

希望这有帮助!

更新:.NET 4.0及更高版本!

答案 1 :(得分:1)

当你的计时器事件被引发时会发生延迟,但没有数据需要读取。它会坐下来等到有。解决该问题的最佳方法是使用异步操作来处理I / O.例如:

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");
    }
}

上面的例子省略了一些错误检查和其他细节,但这是你想要做的基本想法。