我正在异步套接字侦听器控制台应用程序中使用system.Timers计时器。 我希望计时器每40秒运行一次,并检查客户端设备的连接状态。
一旦计时器启动,服务器套接字将不再监听(不再等待更多连接),并且连接的第一台设备始终只能接收数据。当我从网络中删除设备并再次连接时,没有任何反应。没有其他功能正在运行。 这是计时器的代码-
IPStatusTimer = new System.Timers.Timer(35000);
IPStatusTimer.Elapsed += IPStatusTimer_Elapsed;
IPStatusTimer.AutoReset = true;
IPStatusTimer.Enabled = true;
private static void IPStatusTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
Console.WriteLine("Inside Timer");
if (connectedClient > 0)
{
foreach (KeyValuePair<string, int> i in IPStatus)
{
if (i.Value == 1)
{
IPStatus[i.Key] = 0;
}
else if (i.Value == 0)
{
Decode dr = new Decode();
string m = dr.offlineMessage();
if (Clients.Count > 0)
{
foreach (KeyValuePair<int, StateObject> c in Clients)
{
if (((IPEndPoint)c.Value.workSocket.RemoteEndPoint).Address.ToString() == i.Key)
{
Clients.Remove(c.Key);
}
}
SendMessage(i.Key, m);
}
}
}
}
}
计时器不应该影响我的其他功能。它应该在后台安静地运行,直到应用程序正常运行为止。
编辑:(在上面的代码中)如果CLients.Count> 0添加,则只会从CLients中删除项目,因此那里不会有任何异常。
只要有连接,我都会将Stateobject添加到字典中,以便在需要时可以向所有客户端广播数据。
public static void AcceptCallback(IAsyncResult ar)
{
connectedClient++;
// Signal the main thread to continue.
allDone.Set();
// Get the socket that handles the client request.
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
string ip = ((IPEndPoint)handler.RemoteEndPoint).Address.ToString();
Console.WriteLine("ip " + ip);
// Create the state object.
StateObject state = new StateObject();
state.buffer = new byte[StateObject.BufferSize];
Clients.Add(connectedClient, state);
if (IPStatus.ContainsKey(ip))
IPStatus[ip] = 1;
else
IPStatus.Add(ip, 1);
Console.WriteLine(" Total Connected client : " + connectedClient);
state.workSocket = handler;
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
如您所见。如果客户端返回网络并且服务器始终处于侦听模式,则它应该接受连接,并且状态对象应再次添加到Client(字典对象)。这应该不是问题。客户端一连接好,我就给IPStatus(字典对象)一个值1,因为它表示客户端在线。
然后在我的readCallBack()中,每当我从任何客户端接收到数据时,然后在我的字典中,我都会在IPStatus中再次将其值设置为1。
public static void ReadCallback(IAsyncResult ar)
{
string content = string.Empty;
// Retrieve the state object and the handler socket
// from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.workSocket;
// Read data from the client socket.
int bytesRead = handler.EndReceive(ar);
int i = 0;
string ip = ((IPEndPoint)handler.RemoteEndPoint).Address.ToString();
if (IPStatus.ContainsKey(ip))
{
IPStatus[ip] = 1;
}
}
然后当Timer运行时,如果任何IP的值为1,则将其设置为0。因此,如果下次运行Timer并获得值0,则表示它在过去35秒内未从客户端收到任何数据。客户不再在线。 ReadCallback和所有状态都使用StateObject而不是Clients(字典对象)来进行。因此,如果我要从“客户端”中删除任何项目,则在“任何新连接”启动时会再次添加该项目。
我希望你们的情况变得更加清楚。
答案 0 :(得分:0)
感谢@ rs232 ...指出异常的原因。 是字典对象抛出错误。因此在对字典进行读写操作之前要先使用锁(对象)。
lock (Clients)
{
if (Clients.Count > 0)
{
foreach (KeyValuePair<string, StateObject> c in Clients)
{
if (c.Value.workSocket == handler)
{
Clients.Remove(c.Key);
Console.WriteLine("Client automatically disconnected");
Decode dr = new Decode();
string m = dr.offlineMessage();
SendMessage(ip, m);
break;
}
}
}
}
以及该页面上其他任何考虑计时器问题的人。上面的代码(在问题中)非常好,可以按要求工作。您可以从中获取参考。