异步的TCP服务器程序
我做了个TCP服务器程序,用来监听各个客户端的连接,并与之通信。照着书上用异步的方式写了程序,以下是代码。
private void AcceptConnect()
{
IPAddress[] ip = Dns.GetHostAddresses(Dns.GetHostName());
listener = new TcpListener(ip[0], 51888);
listener.Start();
listBoxStatus.Invoke(setListBoxCallback, "开始等待客户连接");
while (isExit == false)
{
try
{
allDone.Reset();
AsyncCallback callback = new AsyncCallback(AcceptTcpClientCallback);
listener.BeginAcceptTcpClient(callback,listener);
allDone.WaitOne();
}
catch (Exception ex)
{
listBoxStatus.Invoke(setListBoxCallback,ex.Message);
break;
}
}
}
private void AcceptTcpClientCallback(IAsyncResult ar)
{
try
{
allDone.Set();
TcpListener myListener = (TcpListener)ar.AsyncState;
TcpClient client = myListener.EndAcceptTcpClient(ar);
listBoxStatus.Invoke(setListBoxCallback, "已接受客户连接:" + client.Client.RemoteEndPoint);
comboBox1.Invoke(setComboBoxCallback,client.Client.RemoteEndPoint.ToString());
ReadWriteObject readWriteObject = new ReadWriteObject(client);
clientList.Add(readWriteObject);
SendString(readWriteObject,"服务器已经接受连接");
readWriteObject.netStream.BeginRead(readWriteObject.readBytes,0,readWriteObject.readBytes.Length,ReadCallback,readWriteObject);
}
catch(Exception ex)
{
listBoxStatus.Invoke(setListBoxCallback, ex.Message);
}
}
private void ReadCallback(IAsyncResult ar)
{
try
{
ReadWriteObject readWriteObject = (ReadWriteObject)ar.AsyncState;
int count = readWriteObject.netStream.EndRead(ar);
richTextBoxReceive.Invoke(setRichTextBoxCallback,string.Format("[来自{0}]{1}",readWriteObject.client.Client.RemoteEndPoint,str));
if(isExit==false)
{
readWriteObject.InitReadArray();
readWriteObject.netStream.BeginRead(readWriteObject.readBytes, 0, readWriteObject.readBytes.Length, ReadCallback, readWriteObject);
}
}
catch(Exception ex)
{
//listBoxStatus.Invoke(setListBoxCallback,ex.Message);
}
}
至于你的问题可能部分在于客户。
客户发起了连接,如果没有及时socket.Disconnect或tcpClient.Close,那么服务方就要空等着。
在服务端ReadCallback方面,没有断线后清理连接资源的措施。加上你把资源放到clientList里面,将导致内存不能回收。
[解决办法]
通信的话你最好新建一个线程,要不通信会占用你的UI线程。
[解决办法]
凡是“貌似”是多线程、异步的程序,我习惯于先看看有没有些while语句。如果写了,你就知道可能是多累赘、多垃圾了。
while语句跟阻塞是“苍蝇和蛐”,总是在一起的。正因为你错误地写了while语句,这个错误引起了你再用更错误的阻塞方式来对付它。所以我说它们是“苍蝇和蛐”的关系。
删掉你的while语句。类似于这样(不保证语法正确,理解就好了)
private void AcceptConnect()
{
IPAddress[] ip = Dns.GetHostAddresses(Dns.GetHostName());
listener = new TcpListener(ip[0], 51888);
listener.Start();
listBoxStatus.Invoke(setListBoxCallback, "开始等待客户连接");
AcceptTcpClientCallback();
listener.BeginAcceptTcpClient(AcceptTcpClientCallback,listener);
}
private void AcceptTcpClientCallback(IAsyncResult ar)
{
try
{
TcpListener myListener = (TcpListener)ar.AsyncState;
TcpClient client = myListener.EndAcceptTcpClient(ar);
listBoxStatus.Invoke(setListBoxCallback, "已接受客户连接:" + client.Client.RemoteEndPoint);
comboBox1.Invoke(setComboBoxCallback,client.Client.RemoteEndPoint.ToString());
ReadWriteObject readWriteObject = new ReadWriteObject(client);
clientList.Add(readWriteObject);
SendString(readWriteObject,"服务器已经接受连接");
readWriteObject.netStream.BeginRead(readWriteObject.readBytes,0,readWriteObject.readBytes.Length,ReadCallback,readWriteObject);
}
catch(Exception ex)
{
listBoxStatus.Invoke(setListBoxCallback, ex.Message);
}
listener.BeginAcceptTcpClient(AcceptTcpClientCallback,listener);
}