当前位置: 代码迷 >> C# >> TCP客户端连接服务端有关问题
  详细解决方案

TCP客户端连接服务端有关问题

热度:106   发布时间:2016-05-05 02:58:45.0
TCP客户端连接服务端问题
这是一个TCP客户端程序,可以同时创建多个客户端去连服务端的多线程程序。
客户端程序能正常与服务端连接,服务端没有关闭的情况下运行正常,但在多个客户端已连接的状态下服务端突然关闭,客户端软件会卡死,操作系统内存几乎爆掉,内存占用达到90%几。
求各位帮忙看看~谢谢

以下为ClintForm.cs:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections.Concurrent;
using System.Text.RegularExpressions;
using System.Net;
using System.Threading;
using System.Net.Sockets;
using Communication.TCP;

namespace CLIENTRtu
{
    public partial class ClientForm : Form
    {
        MainFrm f1;
        private string RuleType;
        public ClientForm(MainFrm f1)
        {
            InitializeComponent();
            Global.GetInstance();
            this.f1 = f1;
            RuleType = f1.StringValue;
        }
        private Thread HeartOutgoingThread;
        private Thread SendOutgoingThread;
        private AbcProtocol AbcProtocolObj = null;
        AynTcpClient tcpClient = null;
        private bool isReadRunning = false;
        private bool isRecvRunning = false;
        private DateTime SysStartTime = DateTime.Now;
        private void SendThreadFunc()
        {
            try
            {
                byte[] buff = new byte[4000];
                int len = 0;
                while (isReadRunning)
                {
                    while (isReadRunning && tcpClient.IsConnected)
                    {
                        //len = 0;
                        len = AbcProtocolObj.Pack(ref buff);
                        if (len > 0)
                        {
                            byte[] SendBuf = new byte[len];
                            Array.Copy(buff, 0, SendBuf, 0, len);
                            tcpClient.AynSend(SendBuf);
                        }
                        Thread.Sleep(50);
                    }
                    Thread.Sleep(50);
                }
            }
            catch { }
        }
        private void HeartThreadFunc()
        {
            byte[] buff = new byte[4000];
            while (isRecvRunning)
            {
                while (isRecvRunning && tcpClient.IsConnected)
                {
                    try
                    {
                        while (!tcpClient.recvQueue.IsEmpty && isRecvRunning)
                        {
                            RecvObject recvObj = null;
                            tcpClient.recvQueue.TryDequeue(out recvObj);
                            if (recvObj == null) break;
                            uint len = recvObj.receLen;
                            if (len > 0)
                            {
                                Array.Copy(recvObj.receiveBuffer, buff, len);
                                AbcProtocolObj.UnPack(buff, len);
                            }
                        }
                    }
                    catch { }
                    Thread.Sleep(50);
                }
            }
            Thread.Sleep(50);
        }
        void AddMessage(string Caption, string s, bool newLine)
        {
            try
            {
                if (IsPauseOutPut) return;

                Action action = () =>
                {
                    if (listBox1.Items.Count > 1000)
                    {
                        listBox1.Items.Clear();
                    }
                    if (!string.IsNullOrEmpty(Caption)) listBox1.Items.Add(Caption);
                    listBox1.Items.Add(s);
                    if (newLine) listBox1.Items.Add(Environment.NewLine);
                    ListBoxAutoCroll(listBox1);
                };
                this.BeginInvoke(action);
            }
            catch { }
        }
        void ListBoxAutoCroll(System.Windows.Forms.ListBox lbox)
        {
            try
            {
                lbox.TopIndex = lbox.Items.Count - (int)((lbox.Height - 10) / lbox.ItemHeight);
            }
            catch { }
        }
        void AddProtocolInfo(string Caption, string message, bool line)
        {
            AddMessage(Caption, message, line);
        }
        private void tsmi2_Clear_Click(object sender, EventArgs e)
        {
            listBox1.Items.Clear();
        }

        private void tsmi2_CopyItem_Click(object sender, EventArgs e)
        {
            if (listBox1.SelectedItems.Count > 0)
            {
                Clipboard.SetDataObject(listBox1.SelectedItem.ToString());
            }
        }
        private void button1_Click(object sender, EventArgs e)
        {
           fun();
        }
        public void fun()
        {
            try
            {
                if (button1.Text.Equals("连 接"))
                {
                    if (StartSystem())
                    {
                        SysStartTime = DateTime.Now;
                        this.Text = "EVTRtu (" + "车牌号:" + CarNumber + "  VIM码:" + Global.CarVimCode + ")";
                    }
                    button1.Text = "断 开";
                }
                else
                {
                    StopSystem();
                    button1.Text = "连 接";
                    this.Text = "EVTRtu";
                }
            }
            catch (Exception ex)
            {
            }
        }
        public void funtext()
        {
            button1.Text = "连 接";
        }
        public bool StartSystem()
        {
            bool rtn = false;
            try
            {
                tcpClient = new AynTcpClient(Global.RemoteHost, ushort.Parse(Global.RemotePort), 1, 3, 3000);
                tcpClient._start();
                Thread.Sleep(10);
                if (tcpClient != null && tcpClient.IsConnected)
                {
                    AddMessage("", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ": 已建立TCP连接!", true);
                        AbcProtocolObj = new AbcProtocol();
                        AbcProtocolObj.addMessageEventHandler += new AbcProtocol.AddMessageEventHandler(AddProtocolInfo);
                        isReadRunning = true;
                        SendOutgoingThread = new Thread(new ThreadStart(SendThreadFunc));
                        SendOutgoingThread.Start();
                        isRecvRunning = true;
                        HeartOutgoingThread = new Thread(new ThreadStart(HeartThreadFunc));
                        HeartOutgoingThread.Start();
                    timer2.Enabled = true;
                    rtn = true;
                }
                else
                {
                    AddMessage("", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ": 无法与服务器建立连接! RemoteIP-" + Global.RemoteHost + " RemotePort-" + Global.RemotePort, true);
                }
            }
            catch { }
            return rtn;
        }
        public void StopSystem()
        {
            try
            {
                isRecvRunning = false;
                isReadRunning = false;
                timer2.Enabled = false;
                if (tcpClient != null && tcpClient.IsConnected)
                {
                    tcpClient._stop();
                    tcpClient = null;
                }
                if (HeartOutgoingThread != null && HeartOutgoingThread.IsAlive)
                {
                    HeartOutgoingThread.Abort();
                    HeartOutgoingThread = null;
                }
                if (SendOutgoingThread != null && SendOutgoingThread.IsAlive)
                {
                    SendOutgoingThread.Abort();
                    SendOutgoingThread = null;
                }
                if (AbcProtocolObj != null) AbcProtocolObj.StopThread();

                AddMessage("", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ": 已断开TCP连接!", true);
            }
            catch { }
        }
        private void timer2_Tick(object sender, EventArgs e)
        {
            try
            {
                if (AbcProtocolObj != null&& isRecvRunning && isReadRunning && tcpClient.IsRunning && !tcpClient.IsConnected)
                {
                    StopSystem();
                }
            }
            catch { }
        }
    }
}
------解决思路----------------------
把你客户端里各种诡异的while死循环去掉,你的问题就自然得到解决了

还有,既然你的问题是确定的,能够复现的,那么你断点跟客户端,看服务端关闭后,客户端到底干什么了,不就知道了
------解决思路----------------------
是的,正如#1楼所说,其实不看技术单看思路就能发现,套在一起的“各种诡异的死循环”用来做控制逻辑,这种思路稍不留神必将产生恶性循环结果。

在“非轮询、事件驱动”式的思路中,没有任何大的性能损耗的机会。当你发送消息时(包括发送业务上的心跳消息时),由于是异步的,一旦发现连接失败则可以自动地重连然后发送。

其实当你的代码中有 while、Thread.Sleep(50) 这种代码的组合,就能看出它一定会让电脑卡得连鼠标都不好使了。这是无需动人和脑子,一看这个代码就知道的。
  相关解决方案