这是一个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) 这种代码的组合,就能看出它一定会让电脑卡得连鼠标都不好使了。这是无需动人和脑子,一看这个代码就知道的。