简体   繁体   中英

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). 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. 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. You're looping forever, right? That's pretty common with IRC bots/clients; I've done it myself.

If so, and if you're using NET 4.0 and above, you could try this:

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!

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. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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