异步TCP调用BeginReceive和EndAccept有时候会产生异常

benny904 benny904 墨衍会员 · AI 创作全网分发 墨衍智能分发 通过墨衍一键同步至各平台 可同步平台 CSDN微信公众号微博知乎掘金百家号博客园抖音小红书 你的文章也可以这样分发 墨衍会员 ¥399起/年,写一次发全网 我也要 + 加入社区
首先说一下我的代码的大概结构
1.程序是CS架构的。客户端负责把有硬件采集到的数据发到服务器,当服务器接收到某个客户端发来的数据(结构体来的),把接收到的数据推进一个队列,有专门的线程循环检测队列中是否有数据,有数据就取数据更新图形界面,并且再分发到其他客户端,客户端接收到来自服务器发来的数据会更新本客户端的图形界面,从而能看到别的客户端的实时情况。目前有16个客户端同时接入服务器。
2.服务器和客户端都是用.Net2.0和C#开发,通信部分都采用异步Socket,代码的结构大致相同,下面会给出代码。
3.服务器端代码主要的函数有:
(1)initListener(),初始化listen的Socket,并启动异步接收客户端连接(这里没有采用while循环来Accept,而是在BeginAccept的回调函数中再次调用BeginAccept)。
(2)OnConnectReuqest(),作为BeginAccept的回调函数,当异步接收到一个客户端连接时调用该函数,在该函数中再次调用lietener.BeginAccept(),继续接受下一个连接
(3)OnReceiveData()函数接收来自客户端的操作并且执行一系列的操作
4.一些自定义类型的解释
TrackStateStr是我自定义的结构体类型
SocketChatClient类封装了一个Socket和接收缓冲区,当接受了一个客户端的连接时候,把与客户端通信的Socket封装到该类中,该类提供了SetupReceiveCallback方法调用BeginReceive异步接收数据(回调函数就是OnReceiveData)

出现的问题:
1.程序运行久了(大概一天不到),会在OnConnectRequest()函数的SockChatClient client = new SockChatClient(listener.EndAccept(ar), this)这一句出现异常,提示只能对一个异步操作调用一次EndAccept,不知道是由什么引起的。
2.运行了一段时间(也是大概一天不到)在SockChatClient类的SetupReceiveCallback()会出现异常,应该是调用BeginReceive失败了,提示要 访问的资源已经释放,应该是在调用的时候Socket已经被释放了。不知道是不是由于客户端的关闭引起的。但是我在OnReceiveData函数里面有捕获客户端关闭的异常。
3.出现了一个异常提示:集合已修改;可能无法执行枚举操作。应该是在SetTrackStateCall()这个函数中出现的异常,不知道是因为什么。SetTrackStateCall()是循环检测接收队列里面是否有数据并进行相应处理的函数。

主要就是以上3个问题,请各位对Socket方面有丰富经验的大大门帮我看看问题是在哪,关键代码我都贴在下面。

服务端异步TCP的主要代码:
Socket listener;
int listenPort;
public bool isRun;
Type trackStateType = (new TrackStateStr()).GetType();
public ArrayList m_clientSockList = new ArrayList();
Dictionary<string, int> m_IPIndex;
object curAllTrackStateLocker = new object();
public Queue<TrackStateStr> recvTrackStateQueue = new Queue<TrackStateStr>(100);
public ManualResetEvent manualResetEvent = new ManualResetEvent(true);
AutoResetEvent writeHandler = new AutoResetEvent(true);
Thread setTrackTrackThread;

public void initListener()
{
this.listenPort = (int)Port.ServerListenPort;
IPEndPoint iep = new IPEndPoint(IPAddress.Parse(MyIP), this.listenPort);
this.listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
this.listener.Bind(iep);
this.listener.Listen(16);
this.listener.BeginAccept(new AsyncCallback(OnConnectRequest), this.listener);
this.isRun = true;
}

private void OnConnectRequest(IAsyncResult ar)
{
if (!isRun)
return;

Socket listener = (Socket)ar.AsyncState;
SockChatClient client = new SockChatClient(listener.EndAccept(ar), this);
if (this.IsHandleCreated)
{
int stationIndex = 0;
foreach (KeyValuePair<int, string> kvp in IPArray)
{
if (kvp.Value == ((IPEndPoint)client.Sock.RemoteEndPoint).Address.ToString())
{
stationIndex = kvp.Key;
break;
}
}
if (stationIndex != 0)
{
Invoke(this.m_AddToMsgTips, new string[] { this.stationName[stationIndex] + " 成功连接到服务器" });
client.StationName = this.stationName[stationIndex];
client.StationId = stationIndex;
Invoke(this.m_SetZColor, new object[] { _ZArray[stationIndex], _connectedColor });
m_clientSockList.Add(client);
client.SetupReceiveCallBack();
}
else
{
Invoke(this.m_AddToMsgTips, new string[] { "unknown client join!" });
client.Sock.Close();
//client.StationName = "unknow client";
//client.StationId = 0;
}

}
listener.BeginAccept(new AsyncCallback(OnConnectRequest), listener);
}

object queueLocker = new object();
public void OnReceiveData(IAsyncResult ar)
{
if (!isRun)
return;

SockChatClient client = (SockChatClient)ar.AsyncState;
byte[] recvData = client.GetReceiveData(ar);
try
{

if (recvData.Length < 1)
{
//收到的字节数为0,远程机器可能已经断开连接
if (this.IsHandleCreated)
{
this.Invoke(this.m_AddToMsgTips, new string[] { "与 " + client.StationName + " 的连接断开" });
if (client.StationId != 0)
{
if (this.stationCtrlState[client.StationId] == 2)
this._twinklingTimerArr[client.StationId].Stop();
this.Invoke(this.m_SetZColor, new object[] { _ZArray[client.StationId], _disconnectedColor });
}
}
this.stationCtrlState[client.StationId] = 0;
client.Sock.Close();
this.m_clientSockList.Remove(client);
return;
}

TrackStateStr newTrackState = (TrackStateStr)this.BytesToStruct(recvData, this.trackStateType);
Invoke(m_AddToMsgTips, new string[] { "from " + client.StationName });

//writeHandler.WaitOne();
lock (queueLocker)
{
recvTrackStateQueue.Enqueue(newTrackState);
}
//writeHandler.Set();
}
catch (Exception er)
{
this.Invoke(this.m_AddToMsgTips, new string[] { er.Message });
}

client.SetupReceiveCallBack();
}

int j = 0;
private void SetTrackStateCall()
{
while (true)
{
manualResetEvent.WaitOne();
//manualResetEvent.Reset();
lock (queueLocker)
{
if (recvTrackStateQueue.Count > 0)
{
try
{
TrackStateStr newTrackState = recvTrackStateQueue.Dequeue();
//更新当前状态
Invoke(m_UpdateCurTrackState, new object[] { newTrackState });
//回发到各个车站
SendBackToCli();
//设置控件状态
Invoke(m_SetTrackState, new object[] { newTrackState });
for (int i = 0; i < 16; i++)
{
this._curAllTrackState.Z[i].modified = false;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, DateTime.Now + ":From SetTrackStateCall");
}
}
}
//manualResetEvent.Set();
Thread.Sleep(10);
}
}

/// <summary>
/// 回发全线状态到所有客户端
/// </summary>
public void SendBackToCli()
{
byte[] sendData = StructToBytes(this._curAllTrackState);
foreach (SockChatClient cli in this.m_clientSockList)
{
try
{
cli.Sock.Send(sendData);
}
catch
{
cli.Sock.Close();
m_clientSockList.Remove(cli);
//return;
}
}
}
#endregion



SockChatClient的代码
 class SockChatClient
{
private Socket m_sock;
public Socket Sock
{
get { return m_sock; }
}

private string m_stationName;
public string StationName
{
get { return m_stationName; }
set { m_stationName = value; }
}

private int m_stationId;
public int StationId
{
get { return m_stationId; }
set { m_stationId = value; }
}


private byte[] m_buff;
private int m_bufSize;

ServerForm frmMain;
AsyncCallback receiveData;

public SockChatClient(Socket sock, ServerForm frmMain)
{
this.m_sock = sock;
this.m_bufSize = Marshal.SizeOf((new TrackStateStr()).GetType());
this.frmMain = frmMain;
receiveData = new AsyncCallback(this.frmMain.OnReceiveData);
}

public void SetupReceiveCallBack()
{
try
{
m_buff = null;
m_buff = new byte[m_bufSize];
//AsyncCallback receiveData = new AsyncCallback(frmMain.OnReceiveData);
m_sock.BeginReceive(m_buff, 0, m_buff.Length, SocketFlags.None, receiveData, this);
}
catch (Exception ex)
{
MessageBox.Show("Setup receive callback fail! " + ex.Message, DateTime.Now + ":From Sock " + this.m_stationId + "," + m_stationName);
}
}

public byte[] GetReceiveData(IAsyncResult ar)
{
int nRecvBytes = 0;
try
{
nRecvBytes = m_sock.EndReceive(ar);
}
catch
{
}

byte[] bytesReturn = new byte[nRecvBytes];
Array.Copy(m_buff, bytesReturn, nRecvBytes);
return bytesReturn;
}
}
...全文
评论 5
收藏 已收藏
分享
返回顶部
benny904
C# 111,129 成员 642,539 内容