Search code examples
c#.nettcpclienttcplistener

Can't read/write data (TcpClient/Server)


I'm actually able to connect my TcpClient to my TcpServer, but I can't make them communicate. I tried client.GetStream() and BinaryReader/Writer.

Here is my code:

-Client:

public partial class Client : Window
{
    #region Constructeurs
    public Client() : this(string.Empty, 12221) { }

    public Client(string ipDefaut, int portDefaut)
    {
        InitializeComponent();

        numIp.FromString("192.168.2.168");
        numPort.Value = portDefaut;

        Serveur serveur = new Serveur();
        serveur.Show();
    }
    #endregion

    public void Start()
    {
        if (Ip == null)
            return;

        if (client == null || client.Client == null)
            client = new TcpClient();

        if (client.Connected == true)
        {
            ShowMessage("Déjà connecté.");
            return;
        }

        client = new TcpClient();

        try
        {
            client.ConnectAsync(Ip, Port).Wait(10);
        }
        catch (SocketException) { }
    }

    public void Stop()
    {
        if (client != null && client.Client != null)
            if (client.Connected)
            {
                client.Client.Shutdown(SocketShutdown.Both);
                client.Close();
            }
    }

    public string Read()
    {
        if (client != null && client.GetStream() != null)
            if (client.Connected && client.GetStream().DataAvailable)
            {
                BinaryReader reader = new BinaryReader(client.GetStream());
                return reader.ReadString();
            }

        return string.Empty;
    }

    public void Send(string info)
    {
        if (client != null && client.GetStream() != null)
            if (client.Connected)
            {
                BinaryWriter writer = new BinaryWriter(client.GetStream());
                writer.Write(info);
                writer.Flush();
            }
    }

    private void ShowMessage(string message)
    {
        labelInfo.Content = message;
        Storyboard sb = Resources["sbLabelInfo"] as Storyboard;
        sb.Begin(labelInfo);
    }

    private void Connecter(object sender, RoutedEventArgs e)
    {
        foreach (string num in numIp.ToStringArray())
            if (num == string.Empty)
            {
                ShowMessage("L'adresse ip doit être complète.");
                return;
            }

        Start();

        if (client.Connected)
        {
            ShowMessage("Connecté");
            boutonConnecter.IsEnabled = false;
            numIp.IsEnabled = false;
            numPort.IsEnabled = false;
            boutonAnnuler.Content = "Déconnecter";
        }

        else
            ShowMessage("Impossible de se connecter.");
    }

    private void Annuler(object sender, RoutedEventArgs e)
    {
        if ((string)boutonAnnuler.Content == "Annuler")
            Close();

        else if ((string)boutonAnnuler.Content == "Déconnecter")
        {
            Stop();
            boutonConnecter.IsEnabled = true;
            numIp.IsEnabled = true;
            numPort.IsEnabled = true;
            boutonAnnuler.Content = "Annuler";
        }
    }


    #region Propriétés
    public string Ip { get { return numIp.ToString(); } }

    public int Port { get { return (int)numPort.Value; } }
    #endregion

    #region Membres
    private TcpClient client = new TcpClient();
    #endregion
}

-Server:

public partial class Serveur : Window
{
    #region Constructeurs
    public Serveur() : this(12221) { }

    public Serveur(int numPortDefaut)
    {
        InitializeComponent();

        foreach (IPAddress addr in Dns.GetHostAddresses(Dns.GetHostName()))
            if (addr.AddressFamily == AddressFamily.InterNetwork)
                numIp.FromString(addr.ToString());

        numPort.Value = numPortDefaut;
        serveur = new TcpListener(IPAddress.Parse(Ip), Port);
        thread = new Thread(Accept);
        serveur.Stop();

        if (!System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable())
        {
            boutonDemarrer.IsEnabled = false;
            MessageBox.Show(this, "Connection impossible - Tic Tac Toe", "Impossible de se connecter à internet. Vérifiez votre connection et réessayez.", MessageBoxButton.OK, MessageBoxImage.Warning);
            Close();
        }
    }
    #endregion

    public void Start()
    {
        if (serveur != null)
        {
            try
            {
                serveur.Start();
            }
            catch (SocketException) { }

            IsConnected = false;
            StartThread();
        }

        else
        {
            serveur = new TcpListener(IPAddress.Parse(Ip), Port);
            Start();
        }
    }

    public void Stop()
    {
        if (serveur != null)
        {
            IsConnected = false;
            serveur.Stop();
            StopThread();
        }
    }

    public void StartThread()
    {
        if (thread.ThreadState == ThreadState.Stopped)
            thread.Start();
    }

    public void StopThread()
    {
        if (!IsConnected)
        {
            IsConnected = true;
            while (thread.IsAlive) { }
            IsConnected = false;
        }
    }

    private void Accept()
    {
        while (!IsConnected && serveur != null)
            if (serveur.Pending())
            {
                client = serveur.AcceptTcpClient();
                IsConnected = true;
            }
    }

    public string Read()
    {
        if (client != null && client.GetStream() != null)
            if (client.Connected && client.GetStream().DataAvailable)
            {
                BinaryReader reader = new BinaryReader(client.GetStream());
                return reader.ReadString();
            }

        return string.Empty;
    }

    public void Send(string info)
    {
        if (client != null && client.GetStream() != null)
            if (client.Connected)
            {
                BinaryWriter writer = new BinaryWriter(client.GetStream());
                writer.Write(info);
                writer.Flush();
            }
    }

    private void Demarrer(object sender, RoutedEventArgs e)
    {
        Start();
        boutonAnnuler.Content = "Stop";
        boutonDemarrer.IsEnabled = false;
        numPort.IsEnabled = false;
        numIp.IsEnabled = false;
    }

    private void Annuler(object sender, RoutedEventArgs e)
    {
        if ((string)boutonAnnuler.Content == "Annuler")
        {
            Stop();
            Close();
        }

        else if ((string)boutonAnnuler.Content == "Stop")
        {
            StopThread();
            boutonAnnuler.Content = "Annuler";
            boutonDemarrer.IsEnabled = true;
            numPort.IsEnabled = true;
            numIp.IsEnabled = true;
        }
    }


    #region Propriétés
    public string Ip { get { return numIp.ToString(); } }

    public int Port { get { return (int)numPort.Value; } }

    public bool IsConnected { get; private set; }
    #endregion

    #region Membres
    private TcpListener serveur = null;

    private TcpClient client = null;

    private Thread thread = null;
    #endregion
}

The problem is that, in debug mode, client.GetStream().DataAvailable return always false.

Why does it return that and how do I can solve this ?

(numIp and numPort are some fields that the user needs to fill)


Solution

  • It was longer than expected... I finally gave up on the TcpClient/Server to use my own sockets. Here is the result (i made a abstract class in my code because these classes are similar) :

    Abstract class :

    public abstract partial  class Connectable : Window
    {
        public abstract void Start();
    
        public abstract void Stop();
    
        public void WaitMessage()
        {
            WaitMessage(new StateObject() { socket = socket });
        }
    
        private void WaitMessage(StateObject so)
        {
            Socket s = so.socket;
            int read = s.Receive(so.buffer, 0, StateObject.BUFFER_SIZE, SocketFlags.None);
    
            so.sb.Append(Encoding.UTF8.GetString(so.buffer, 0, read));
    
            if (s.Available > 0)
                WaitMessage(so);
    
            else if (NewMessage != null)
            {
                NewMessage(so.sb.ToString());
                so.sb.Clear();
            }
        }
    
        public void ReceiveMessage()
        {
            StateObject state = new StateObject() { socket = socket };
    
            try { socket.BeginReceive(state.buffer, 0, StateObject.BUFFER_SIZE, 0, new AsyncCallback(MessageReceived), state); }
            catch (SocketException e) { Console.WriteLine(e.Message); }
        }
    
        protected void MessageReceived(IAsyncResult ar)
        {
            StateObject so = (StateObject)ar.AsyncState;
            Socket s = so.socket;
            int read = s.EndReceive(ar);
    
            so.sb.Append(Encoding.UTF8.GetString(so.buffer, 0, read));
    
            if (s.Available > 0)
                s.BeginReceive(so.buffer, 0, StateObject.BUFFER_SIZE, 0, new AsyncCallback(MessageReceived), so);
            else if (NewMessage != null)
            {
                NewMessage(so.sb.ToString());
                so.sb.Clear();
            }
        }
    
        public void SendMessage(string msg)
        {
            if (socket != null)
            {
                if (socket.Connected && !string.IsNullOrEmpty(msg))
                {
                    socket.Send(Encoding.UTF8.GetBytes(msg));
                }
            }
        }
    
        protected void ShowMessage(string message)
        {
            Console.WriteLine(message);
        }
    
        public virtual bool IsConnected()
        {
            if (socket == null)
                return false;
    
            return socket.Connected;
        }
    
        #region Members
        protected Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    
        public Message NewMessage;
        #endregion
    
        #region Delegates
        public delegate void Message(string message);
        #endregion
    }
    

    Server class :

    public partial class Server : Connectable
    {
        #region Constructeurs
        public Server() : this(12221) { }
    
        public Server(int numPortDefaut)
        {
            InitializeComponent();
            socket = null;
            NewMessage += ShowMessage;
    
            foreach (IPAddress addr in Dns.GetHostAddresses(Dns.GetHostName()))
                if (addr.AddressFamily == AddressFamily.InterNetwork)
                    numIp.FromString(addr.ToString());
    
            numPort.Value = numPortDefaut;
    
            if (!System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable())
            {
                boutonDemarrer.IsEnabled = false;
                MessageBox.Show(this, "Connection impossible - Tic Tac Toe", "Impossible de se connecter à internet. Vérifiez votre connection et réessayez.", MessageBoxButton.OK, MessageBoxImage.Warning);
                Close();
            }
        }
        #endregion
    
        public override void Start()
        {
            if (socketListener.IsBound)
            {
                if (socket != null)
                {
                    socket.Shutdown(SocketShutdown.Both);
                    socket.Disconnect(false);
                    socket.Dispose();
                    socket = null;
                }
    
                socketListener.Close();
                socketListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            }
    
            try
            {
                socketListener.Bind(new IPEndPoint(IPAddress.Parse(Ip), Port));
                socketListener.Listen(1);
                AcceptConnection();
            }
            catch (SocketException e) { Console.WriteLine(e); }
        }
    
        public override void Stop()
        {
            acceptConnection.Cancel();
    
            if (socket != null)
            {
                socketListener.Close();
    
                socket.Shutdown(SocketShutdown.Both);
                socket.Disconnect(false);
                socket.Dispose();
                socket = null;
            }
        }
    
        private void AcceptConnection()
        {
            acceptConnection = new CancellationTokenSource();
    
            new Thread(delegate()
            {
                try
                {
                    while (socket == null)
                    {
                        if (socketListener.Poll(1, SelectMode.SelectRead))
                            socket = socketListener.Accept();
    
                        acceptConnection.Token.ThrowIfCancellationRequested();
                    }
    
                    Dispatcher.Invoke(delegate ()
                    {
                        boutonDemarrer.Content = "Jouer";
                        boutonDemarrer.IsEnabled = true;
                    });
                }
                catch (OperationCanceledException e) { Console.WriteLine("Fin de l'attente de connection ({0})", e.Message); }
            }).Start();
        }
    
        private void ButtonClickStart(object sender, RoutedEventArgs e)
        {
            if ((string)boutonDemarrer.Content == "Jouer")
                Close();
    
            else if ((string)boutonDemarrer.Content == "Démarrer")
            {
                Start();
                boutonAnnuler.Content = "Stop";
                boutonDemarrer.IsEnabled = false;
                numPort.IsEnabled = false;
            }
        }
    
        private void ButtonClickCancel(object sender, RoutedEventArgs e)
        {
            if ((string)boutonAnnuler.Content == "Annuler")
                Close();
    
            else if ((string)boutonAnnuler.Content == "Stop")
            {
                Stop();
                boutonAnnuler.Content = "Annuler";
                boutonDemarrer.Content = "Démarrer";
                boutonDemarrer.IsEnabled = true;
                numPort.IsEnabled = true;
            }
        }
    
    
        #region Propriétés
        public string Ip { get { return numIp.ToString(); } }
    
        public int Port { get { return (int)numPort.Value; } }
        #endregion
    
        #region Membres
        private Socket socketListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    
        private CancellationTokenSource acceptConnection = new CancellationTokenSource();
        #endregion
    }
    

    Client class :

    public partial class Client : Connectable
    {
        #region Constructeurs
        public Client() : this(string.Empty, 12221) { }
    
        public Client(string ipDefaut, int portDefaut)
        {
            InitializeComponent();
            NewMessage += ShowMessage;
    
            numIp.FromString("192.168.2.168");
            numPort.Value = portDefaut;
        }
        #endregion
    
        public override void Start()
        {
            try
            {
                socket.Connect(Ip, Port);
    
                boutonConnecter.Content = "Jouer";
                numIp.IsEnabled = false;
                numPort.IsEnabled = false;
                boutonAnnuler.Content = "Déconnecter";
            }
            catch (SocketException e)
            {
                Console.WriteLine(e.Message);
            }
        }
    
        public override void Stop()
        {
            if (socket.Connected)
            {
                socket.Shutdown(SocketShutdown.Both);
                socket.Close();
                socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            }
        }
    
        private void ButtonClickStart(object sender, RoutedEventArgs e)
        {
            if ((string)boutonConnecter.Content == "Jouer")
                Close();
    
            else if ((string)boutonConnecter.Content == "Connecter")
            {
                foreach (string num in numIp.ToStringArray())
                    if (num == string.Empty)
                    {
                        ShowMessage("L'adresse ip doit être complète.");
                        return;
                    }
    
                Start();
            }
        }
    
        private void ButtonClickCancel(object sender, RoutedEventArgs e)
        {
            if ((string)boutonAnnuler.Content == "Annuler")
                Close();
    
            else if ((string)boutonAnnuler.Content == "Déconnecter")
            {
                Stop();
                boutonConnecter.IsEnabled = true;
                numIp.IsEnabled = true;
                numPort.IsEnabled = true;
                boutonAnnuler.Content = "Annuler";
                boutonConnecter.Content = "Connecter";
            }
        }
    
    
        #region Properties
        public string Ip { get { return numIp.ToString(); } }
    
        public int Port { get { return (int)numPort.Value; } }
        #endregion
    }
    

    If it can help someone else... :)