Unable to write data to the transport connection: An existing connection was forcibly closed by the remote host

xnoor picture xnoor · Sep 5, 2010 · Viewed 10.4k times · Source

I have an update server that sends client updates through TCP port 12000. The sending of a single file is successful only the first time, but after that I get an error message on the server "Unable to write data to the transport connection: An existing connection was forcibly closed by the remote host". If I restart the update service on the server, it works again only one time. I have normal multithreaded windows service.

SERVER CODE

namespace WSTSAU
{
    public partial class ApplicationUpdater : ServiceBase
    {
        private Logger logger = LogManager.GetCurrentClassLogger();
        private int _listeningPort;
        private int _ApplicationReceivingPort;
        private string _setupFilename;
        private string _startupPath;
        public ApplicationUpdater()
        {
            InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
            init();
            logger.Info("after init");
            Thread ListnerThread = new Thread(new ThreadStart(StartListener));
            ListnerThread.IsBackground = true;
            ListnerThread.Start();
            logger.Info("after thread start");
        }

        private void init()
        {
            _listeningPort = Convert.ToInt16(ConfigurationSettings.AppSettings["ListeningPort"]);
            _setupFilename = ConfigurationSettings.AppSettings["SetupFilename"];
            _startupPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase).Substring(6);
        }

        private void StartListener()
        {
            try
            {
                logger.Info("Listening Started");
                ThreadPool.SetMinThreads(50, 50);
                TcpListener listener = new TcpListener(_listeningPort);
                listener.Start();
                while (true)
                {
                    TcpClient c = listener.AcceptTcpClient();
                    ThreadPool.QueueUserWorkItem(ProcessReceivedMessage, c);
                }
            }
            catch (Exception ex)
            {
                logger.Error(ex.Message);
            }
        }

        void ProcessReceivedMessage(object c)
        {
            try
            {
                TcpClient tcpClient = c as TcpClient;
                NetworkStream Networkstream = tcpClient.GetStream();
                byte[] _data = new byte[1024];
                int _bytesRead = 0;

                _bytesRead = Networkstream.Read(_data, 0, _data.Length);

                MessageContainer messageContainer = new MessageContainer();
                messageContainer = SerializationManager.XmlFormatterByteArrayToObject(_data, messageContainer) as MessageContainer;

                switch (messageContainer.messageType)
                {
                    case MessageType.ApplicationUpdateMessage:
                        ApplicationUpdateMessage appUpdateMessage = new ApplicationUpdateMessage();
                        appUpdateMessage = SerializationManager.XmlFormatterByteArrayToObject(messageContainer.messageContnet, appUpdateMessage) as ApplicationUpdateMessage;
                        Func<ApplicationUpdateMessage, bool> HandleUpdateRequestMethod = HandleUpdateRequest;
                        IAsyncResult cookie = HandleUpdateRequestMethod.BeginInvoke(appUpdateMessage, null, null);
                        bool WorkerThread = HandleUpdateRequestMethod.EndInvoke(cookie);
                        break;
                }
            }
            catch (Exception ex)
            {
                logger.Error(ex.Message);
            }
        }


        private bool HandleUpdateRequest(ApplicationUpdateMessage appUpdateMessage)
        {
            try
            {
                TcpClient tcpClient = new TcpClient();
                NetworkStream networkStream;
                FileStream fileStream = null;

                tcpClient.Connect(appUpdateMessage.receiverIpAddress, appUpdateMessage.receiverPortNumber);
                networkStream = tcpClient.GetStream();

                fileStream = new FileStream(_startupPath + "\\" + _setupFilename, FileMode.Open, FileAccess.Read);

                FileInfo fi = new FileInfo(_startupPath + "\\" + _setupFilename);

                BinaryReader binFile = new BinaryReader(fileStream);

                FileUpdateMessage fileUpdateMessage = new FileUpdateMessage();
                fileUpdateMessage.fileName = fi.Name;
                fileUpdateMessage.fileSize = fi.Length;

                MessageContainer messageContainer = new MessageContainer();
                messageContainer.messageType = MessageType.FileProperties;
                messageContainer.messageContnet = SerializationManager.XmlFormatterObjectToByteArray(fileUpdateMessage);

                byte[] messageByte = SerializationManager.XmlFormatterObjectToByteArray(messageContainer);

                networkStream.Write(messageByte, 0, messageByte.Length);

                int bytesSize = 0;
                byte[] downBuffer = new byte[2048];

                while ((bytesSize = fileStream.Read(downBuffer, 0, downBuffer.Length)) > 0)
                {
                    networkStream.Write(downBuffer, 0, bytesSize);
                }

                fileStream.Close();
                tcpClient.Close();
                networkStream.Close();

                return true;
            }
            catch (Exception ex)
            {
                logger.Info(ex.Message);
                return false;
            }
            finally
            {
            }
        }


        protected override void OnStop()
        {
        }
    }

I have to note something that my windows service (server) is multithreaded.

Answer

ssamuel picture ssamuel · Aug 26, 2011

On the receiving end, set up a while loop to listen until there's no more data, then exit gracefully: close the stream and client. The framework TCP libs consider it an issue to drop a connection cold on thread exit and will therefore throw the exception you're seeing.

This will also save you from an intermittent problem you'll likely see once you correct the current one: Stream.Read with a length specifier won't always give you your full buffer each time. It looks like you're sending (up to) 2kb chunks and receiving into a (single-shot) 1kb buffer anyhow so you may start to get XML exceptions as well.

If that's not enough detail, ask and I'll dig up some old TcpClient code.