Как правильно утилизировать TcpClient, NetworkStream и их базовые сокеты? - PullRequest
0 голосов
/ 01 марта 2020

Я написал этот код для использования TcpClient как из клиентской, так и из серверной программы.

Пожалуйста, внимательно посмотрите на шаблон Одноразовый внизу исходного кода. код.

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace ClientServerLib
{
    public class ClientClass : IDisposable
    {
        // ...
        //...
        public TcpClient Tcp { get; private set; }    
        private System.Net.Sockets.NetworkStream stream;

        public ClientClass()
        {
        }

        //constructor for server program.
        public ClientClass(TcpListener listener)
        {
            Tcp = listener.AcceptTcpClient();

            Host = ((IPEndPoint)Tcp.Client.RemoteEndPoint).Address.ToString();
            Port = ((IPEndPoint)Tcp.Client.LocalEndPoint).Port;

            IsConnected = true;

            stream = Tcp.GetStream();

            Console.WriteLine("Client [{0}] is now connected.", ID);
        }

        public bool Connect()
        {
            if (IsConnected == false)
            {
                Console.WriteLine("Client [{0}] is now connected.", ID);

                IsConnected = true;

                Tcp = new TcpClient(Host, Port);

                stream = Tcp.GetStream();

                return true;
            }

            return false;
        }

        //constructor for client.
        public ClientClass(string host, int port)
        {
            Host = host;
            Port = port;
        }

        // ...
        //...

        public bool Disconnect()
        {
            if (IsConnected)
            {
                if (Tcp != null)
                {
                    stream.Close();
                    Tcp.Close();

                    Console.WriteLine("\nClient [{0}] is now disconnected.", ID);

                    return true;
                }
            }

            return false;
        }

        #region dispose pattern
        // Flag: Has Dispose already been called?
        bool disposed = false;

        // Public implementation of Dispose pattern callable by consumers.
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        // Protected implementation of Dispose pattern.
        protected virtual void Dispose(bool disposing)
        {
            if (disposed)
                return;

            if (disposing)
            {
                // Free any other managed objects here
                if (stream != null)
                {
                    stream.Close();
                    stream.Dispose();
                    stream = null;
                }
                if (Tcp != null)
                {
                    if (Tcp.Connected)
                    {
                        Tcp.Client.Disconnect(false);
                        Tcp.Client.Close();
                        Tcp.Client.Dispose();
                        Tcp.Client = null;

                        Tcp.GetStream().Close();
                        Tcp.Close();                        
                        Tcp = null;
                    }
                }
            }

            // Free any unmanaged objects here.
            // ...
            disposed = true;
        }

        ~ClientClass()
        {
            Dispose(false);
        }
        #endregion
    }
}

Правильно ли реализован шаблон Одноразового использования?

Кроме того, что вы говорите о Disconnect()?

...