Search code examples
c#winformssocketstcpclientnetworkstream

How to send other data when connected socket TcpClient in WindowsForms using NetworkStream?


I have a connection that using tcpclient, to send and receive data between server and client . The application is written on the basis of Window Form, I have used BackgroundWorker to handle parallel running tasks. The program runs normally when i clicked Start button, it receives data handshake from the client side and sends the data back to the client. I want to add a function to send new content from textbox, like sample fill up data to Textbox1 and click Send button, it will be sent to the client from server in parallel during the connection between server and client. But when I add this, I get an error returning "Cannot access a disposed object. Object name: System.Net.Sockets.NetworkStream" at this line "stream.Write(msg_byte, 0, msg_byte.Length);" and data is not sent. What did I do wrong, can you point it out to me. This is my snipped code below

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml.Linq;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;

namespace Server
{
    public partial class Form1 : Form
    {
        BackgroundWorker bw;
        static NetworkStream stream = null;

        public Form1()
        {
            InitializeComponent();

            bw = new BackgroundWorker();
            bw.WorkerReportsProgress = true;
            bw.WorkerSupportsCancellation = true;
            bw.DoWork += bw_DoWork;
            bw.ProgressChanged += bw_ProgressChanged;
            bw.RunWorkerCompleted += bw_RunWorkerCompleted;
        }

        private void _startServer(string _ip, int _port)
        {
            TcpListener server = null;
            try
            {
                server = new TcpListener(IPAddress.Parse(_ip), _port);
                server.Start();
                Byte[] bytes = new Byte[1024];
                String data = null;
                while (true)
                {
                    TcpClient client = server.AcceptTcpClient();
                    txt_log.Invoke((Action)(() =>
                    {
                        txt_log.AppendText(DateTime.Now.ToString() + " Connnected " + client.Client.RemoteEndPoint.ToString() + "\r\n");
                    }));
                    data = null;
                    NetworkStream stream = client.GetStream();
                    int i;
                    while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
                    {
                        data = Encoding.ASCII.GetString(bytes, 0, i);
                        txt_log.Invoke((Action)(() =>
                        {
                            txt_log.AppendText(DateTime.Now.ToString() + " Received: " + data + "\r\n");
                        }));
                     
                        data = data.ToUpper();
                        byte[] msg = Encoding.ASCII.GetBytes(data);
                        stream.Write(msg, 0, msg.Length);
                        txt_log.Invoke((Action)(() =>
                        {
                            txt_log.AppendText(DateTime.Now.ToString() + " Sent: " + data + "\r\n");
                        }));                
                    }
                }
            }
            catch (SocketException ex)
            {
                MessageBox.Show("_startServer: " + ex.Message);
            }
        }

        void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            MessageBox.Show("completed");
        }

        void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            if (!bw.CancellationPending)
            {
                MessageBox.Show("processing");
            }
        }

        void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            _startServer("192.168.10.15", 4444);
            bw.ReportProgress(100);
        }

        private void bt_start_Click(object sender, EventArgs e)
        {
            if (bw.IsBusy)
            {
                bw.CancelAsync();
            }
            else
            {
                txt_log.Clear();
                bw.RunWorkerAsync();
            }
        }

        private void bt_stop_Click(object sender, EventArgs e)
        {
            bw.CancelAsync();
            if (stream != null)
            {
                stream.Dispose();
            }
        }

        private void bt_send_Click(object sender, EventArgs e)
        {
            string msg_send = txt_msg.Text;
            byte[] msg_byte = Encoding.ASCII.GetBytes(msg_send);
            
            while (true)
            {
                stream.Write(msg_byte, 0, msg_byte.Length);
                txt_log.Invoke((Action)(() =>
                {
                    txt_log.AppendText(DateTime.Now.ToString() + " Sent new data: " + msg_send + "\r\n");
                })); 
                
                string msg_receive = null;
                byte[] temp_byte = new byte[1024];
                stream.Read(temp_byte, 0, temp_byte.Length);
                msg_receive = Encoding.ASCII.GetString(temp_byte);
                txt_log.Invoke((Action)(() =>
                {
                    txt_log.AppendText(DateTime.Now.ToString() + " Received new data: " + msg_receive + "\r\n");
                }));
            }   
        }


    }
}

The situation is open connection to server from the client, on the one hand, always keep the connection from the server to the client by sending temporary data continuously, like the client side always sending "are you there?" , the server always replied "ok, here I am" when get signal data temp from client, this way is working good for me, no issue. On the other hand, I would like to have other signals sent from the server to the client according to what the user enters into the Textbox component, i just try and thinking the best way to do it.

After some change, make code is easier to look

private string IsRealData(byte[] data)
{
    string txt = "";
    if (data[10] == 100)
        txt = "are you there?";
    else
        txt = "NOTHING";
    return txt;
}

private void _startServer(string _ip, int _port)
{
    TcpListener server = null;
    try
    {
        server = new TcpListener(IPAddress.Parse(_ip), _port);
        server.Start();
        byte[] bytes = new Byte[1024];
        while (true)
        {
            TcpClient client = server.AcceptTcpClient();
            String data = null;
            NetworkStream stream = client.GetStream();
            int i;
            while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
            {
                data = Encoding.ASCII.GetString(bytes, 0, i);
                byte[] bytes_real = new byte[i];
                Buffer.BlockCopy(bytes, 0, bytes_real, 0, i);
                if (IsRealData(bytes_real) == "are you there?") 
                {        
                    string _msg_reply = "ok, here I am";
                    byte[] reply = Encoding.ASCII.GetBytes(_msg_reply);         
                    stream.Write(reply, 0, reply.Length);  ///sent real data to client
                    txt_log.Invoke((Action)(() =>
                    {
                        txt_log.AppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff tt") + " Sent: " + _msg_reply + "\r\n");
                    }));
                }
                else
                {
                    data = data.ToUpper();
                    byte[] msg = Encoding.ASCII.GetBytes(data);
                    stream.Write(msg, 0, msg.Length); ///sent temporary data to client
                }
            }
        }
    }
    catch (SocketException ex)
    {
        MessageBox.Show("_startServer: " + ex.Message);
    }
}

private async Task Start_Server()
{
    await Task.Run(() =>
    {
        _startServer("192.168.10.15", 4444);
    });
}

private void bt_start_Click(object sender, EventArgs e)
{
    Start_Server();
}

private void bt_send_Click(object sender, EventArgs e)
{
    string text = txt_msg.Text;
    ////how to send content parallel when user input from Textbox component
}

Thanks you all.


Solution

  • After some debug and enhancement, now it' working for me. Notify that, i just quite change in lasted code, based on the connection socket between server and client is established, give this socket object and using send/receive. That's it.

    private TcpClient client;
     
     private async void _startServer(string _ip, int _port)
    {
        //code in here
        client = server.AcceptTcpClient();
        //code in here
    }
    
    private async Task Start_Server()
    {
            //code in here
            Task.Delay(1000).Wait();
    }
    
    private async void bt_start_Click(object sender, EventArgs e)
    {
        await Start_Server();
    }
    
    private async Task SendMsg(string msg)
    {
        //code in here using SendAsync & ReceiveAsync
        return;
    }
    
    private async void bt_send_Click(object sender, EventArgs e)
    {
        //code in here
        await SendMsg(txt_msg.Text);
    }
    

    Thank you all for advice.