【问题标题】:C# TcpClient updating (for an IRC client)C# TcpClient 更新(用于 IRC 客户端)
【发布时间】:2014-12-02 09:23:11
【问题描述】:

我基本上是在尝试使用 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();
        }
    }
}

【问题讨论】:

  • 您是否尝试过调试您的程序以查看具体发生挂起的位置?
  • 抱歉,要修复的错误太多。最好先搜索一个简单的客户端/服务器代码示例。
  • @L.B 或 premade C# library 用于 IRC

标签: c# winforms tcp tcpclient irc


【解决方案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");
    }
}

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

【讨论】:

    【解决方案2】:

    它不是异步运行的,对吧?所以 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 及更高版本!

    【讨论】:

    • 现在我得到 System.Reflection.TargetInvocationException
    • 是的,.NET 4.0 及更高版本!
    • 您能否为您的 TargetInvocationException 和您的调用堆栈发布 InnerException?另外,发布您的新代码。你所做的改变……我想看看。回复为答案,或将其放在 pastebin.com 上
    • 这会在我激活 async listener() 函数时运行
    • sr.ReadLine() 在做什么?这是 StreamReader 吗?不管怎样,看起来你从来没有设置过这个。它永远不会被实例化。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-16
    • 1970-01-01
    • 2014-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多