Commit 7e98e23f gujlg

socket同步

1 个父辈 456a558d
/* /*
* @Description: 用于AIOBOX-32系列一体化IO模块 * @Description: 用于AIOBOX-32系列一体化IO模块
* @CreateDate: 2019-02-28 * @CreateDate: 2019-02-28
* @UpdateDate: 2019-05-21 * @UpdateDate: 2019-05-22
* @Author: Asa * @Author: Asa
* @Version: 1.8 * @Version: 1.9
* *
*/ */
...@@ -12,48 +12,64 @@ using System.Net; ...@@ -12,48 +12,64 @@ using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Threading; using System.Threading;
using System.Collections.Generic; using System.Collections.Generic;
using OnlineStore.Common;
namespace Asa.IOModule namespace Asa.IOModule
{ {
/// <summary> /// <summary>
/// AIOBOX操作类,同步通信 /// AIOBOX操作类,socket同步
/// </summary> /// </summary>
public class AIOBOX2 public class AIOBOX2
{ {
private ushort _flag; //ModBusTCP标识 /// <summary>
/// 暂停次数
/// WriteDO 命令非常多时,暂停一次发送 ReadDI 或 ReadDO
/// </summary>
private int suspend;
private bool suspendDI; //暂停一次DI
private bool suspendDO; //暂停一次DI
private Socket _client; //客户端 private Socket _client; //客户端
private Box_Type _type; //类型 private Box_Type _type; //类型
private byte[] _addr; //地址 private byte[] _addr; //地址
private Box_Sta[] _sta; //状态 private Box_Sta[] _sta; //状态
private int _unrevd; //没有收到数据的时间
private int _unrevdRemote; //本地还是远程没有收到数据 private int _unrevdRemote; //本地还是远程没有收到数据
private bool _readDI; //自动读取DI private bool _readDI; //自动读取DI
private bool _readDO; //自动读取DO private bool _readDO; //自动读取DO
private int _readDISleep; //自动读取DI间隔 private int _readDISleep; //自动读取DI间隔
private int _readDOSleep; //自动读取DO间隔 private int _readDOSleep; //自动读取DO间隔
private List<string> _log; //日志 private List<string> _log; //日志
//private byte[] _send; //发送的命令 private System.Collections.Concurrent.ConcurrentQueue<ushort> _flag;
private System.Collections.Concurrent.ConcurrentQueue<byte[]> _receive; //接收的数据
private System.Collections.Concurrent.ConcurrentQueue<byte[]> _send; private System.Collections.Concurrent.ConcurrentQueue<byte[]> _send;
private System.Collections.Concurrent.ConcurrentQueue<byte[]> _receive;
private Thread tSend; //private bool suspendWrite;
//private AutoResetEvent aWrite;
//private AutoResetEvent aReadDI;
//private AutoResetEvent aReadDO;
private Thread tSend; //发送命令处理
private Thread tReceive; //接收信息处理 private Thread tReceive; //接收信息处理
private Thread tListen; //监听网络 private Thread tListen; //监听网络
private Thread tTrigger; //触发DI、DO改变事件 private Thread tTrigger; //触发DI、DO改变事件
private Thread tReadDI; //自动读取DI线程 private Thread tReadDI; //自动读取DI线程
private Thread tReadDO; //自动读取DO线程 private Thread tReadDO; //自动读取DO线程
private Thread tLogOut; //日志输出 private Thread tLogOut; //日志输出
private Thread tFlag; //ModBusTCP标识
private bool suspendWrite; /// <summary>
private bool accept; /// 每条命令发送的间隔
private AutoResetEvent aWrite; /// 不能小于15,会出现IO接收不到的情况
private AutoResetEvent aReadDI; /// 小于30时,会出现接收数据连包的情况
private AutoResetEvent aReadDO; /// </summary>
private const int SEND_SLEEP = 15;
private const int SEND_SLEEP = 30; //发送命令间隔 /// <summary>
private const int NET_SLEEP = 30; //接收网络间隔 /// 监听网络接收数据的间隔
private const int TRIG_SLEEP = 30; //触发事件间隔 /// 必须小于SEND_SLEEP
/// </summary>
private const int NET_SLEEP = 10;
/// <summary>
/// 触发DIO状态事件的间隔
/// </summary>
private const int TRIG_SLEEP = 20;
/// <summary> /// <summary>
/// 自动读取DI委托 /// 自动读取DI委托
...@@ -101,9 +117,9 @@ namespace Asa.IOModule ...@@ -101,9 +117,9 @@ namespace Asa.IOModule
_log = new List<string>(); _log = new List<string>();
Type = Box_Type.DIO_32; Type = Box_Type.DIO_32;
aWrite = new AutoResetEvent(false); //aWrite = new AutoResetEvent(false);
aReadDI = new AutoResetEvent(false); //aReadDI = new AutoResetEvent(false);
aReadDO = new AutoResetEvent(false); //aReadDO = new AutoResetEvent(false);
} }
/// <summary> /// <summary>
...@@ -245,6 +261,7 @@ namespace Asa.IOModule ...@@ -245,6 +261,7 @@ namespace Asa.IOModule
/// <returns></returns> /// <returns></returns>
public bool Connect() public bool Connect()
{ {
IsConn = false;
try try
{ {
//IP合法 //IP合法
...@@ -258,40 +275,46 @@ namespace Asa.IOModule ...@@ -258,40 +275,46 @@ namespace Asa.IOModule
//Ping服务端 //Ping服务端
System.Net.NetworkInformation.Ping ping = new System.Net.NetworkInformation.Ping(); System.Net.NetworkInformation.Ping ping = new System.Net.NetworkInformation.Ping();
System.Net.NetworkInformation.PingReply result = ping.Send(IP, 3000); System.Net.NetworkInformation.PingReply result = ping.Send(IP, 5000);
if (result.Status != System.Net.NetworkInformation.IPStatus.Success) if (result.Status != System.Net.NetworkInformation.IPStatus.Success)
{ {
ErrInfo = "Ping " + IP + " 请求没有回应"; ErrInfo = "Ping " + IP + " 请求没有回应";
return false; return false;
} }
_unrevd = 0;
_unrevdRemote = 0; _unrevdRemote = 0;
_flag = 0; //suspendWrite = false;
suspendWrite = false; suspend = 0;
accept = false; suspendDI = false;
_log.Clear(); suspendDO = false;
_send = new System.Collections.Concurrent.ConcurrentQueue<byte[]>(); _send = new System.Collections.Concurrent.ConcurrentQueue<byte[]>();
_receive = new System.Collections.Concurrent.ConcurrentQueue<byte[]>(); _receive = new System.Collections.Concurrent.ConcurrentQueue<byte[]>();
_flag = new System.Collections.Concurrent.ConcurrentQueue<ushort>();
_log.Clear();
//建立连接 //建立连接
_client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); _client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 1000); _client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 500);
_client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 1000); _client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 500);
_client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.NoDelay, 1); _client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.NoDelay, 1);
//_client.BeginConnect(IP, Port, new AsyncCallback(ConnectCallback), null);
_client.Connect(IPAddress.Parse(IP), Port); _client.Connect(IPAddress.Parse(IP), Port);
Thread.Sleep(100); //需要等待一会才能获取连接状态 Thread.Sleep(100); //需要等待一会才能获取连接状态
tSend = new Thread(new ThreadStart(Send)); tFlag = new Thread(new ThreadStart(Flag));
tListen = new Thread(new ThreadStart(Listen)); tFlag.Start();
tTrigger = new Thread(new ThreadStart(TriggerDIO)); Thread.Sleep(10);
tReadDI = new Thread(new ThreadStart(AutoReadDI)); tReadDI = new Thread(new ThreadStart(AutoReadDI));
tReadDO = new Thread(new ThreadStart(AutoReadDO)); tReadDO = new Thread(new ThreadStart(AutoReadDO));
tSend = new Thread(new ThreadStart(Send));
tReceive = new Thread(new ThreadStart(Receive)); tReceive = new Thread(new ThreadStart(Receive));
tLogOut = new Thread(new ThreadStart(LogPrint)); tLogOut = new Thread(new ThreadStart(LogPrint));
tSend.Start(); tListen = new Thread(new ThreadStart(Listen));
tTrigger = new Thread(new ThreadStart(TriggerDIO));
tListen.Start(); tListen.Start();
tTrigger.Start(); tTrigger.Start();
tSend.Start();
tReceive.Start(); tReceive.Start();
tLogOut.Start(); tLogOut.Start();
tReadDI.Start(); tReadDI.Start();
...@@ -304,7 +327,6 @@ namespace Asa.IOModule ...@@ -304,7 +327,6 @@ namespace Asa.IOModule
catch (Exception ex) catch (Exception ex)
{ {
ErrInfo = ex.Message; ErrInfo = ex.Message;
IsConn = false;
return false; return false;
} }
} }
...@@ -329,6 +351,8 @@ namespace Asa.IOModule ...@@ -329,6 +351,8 @@ namespace Asa.IOModule
tSend = null; tSend = null;
if (tReceive != null) tReceive.Abort(); if (tReceive != null) tReceive.Abort();
tReceive = null; tReceive = null;
if (tFlag != null) tFlag.Abort();
tFlag = null;
if (_client != null) if (_client != null)
{ {
...@@ -466,57 +490,40 @@ namespace Asa.IOModule ...@@ -466,57 +490,40 @@ namespace Asa.IOModule
{ {
try try
{ {
//suspendWrite = true;
//if (_readDI) aWrite.WaitOne();
//if (_readDO) aWrite.WaitOne();
//if (_send.Count > 10)
//{
// while (_send.TryDequeue(out byte[] result))
// { }
//}
byte[] data = Command(); byte[] data = Command();
byte[] buff = new byte[12]; byte[] buff = new byte[12];
Array.Copy(data, 0, buff, 0, data.Length); Array.Copy(data, 0, buff, 0, data.Length);
buff[7] = 5; //功能码 buff[7] = 5; //功能码
buff[9] = _addr[(int)add]; //地址 buff[9] = _addr[(int)add]; //地址
buff[10] = (byte)sta; //写入值 buff[10] = (byte)sta; //写入值
suspendWrite = true;
if (_readDI) aWrite.WaitOne();
if (_readDO) aWrite.WaitOne();
accept = false; //接收完数据
int n = 0; //超时时间
int time = 0; //重试次数
while (!accept)
{
if (n == 0)
{
_client.Send(buff);
if (LogOut) AddLog(string.Format("WriteDO({0},{1})", add.ToString(), sta.ToString()), buff);
}
Thread.Sleep(SEND_SLEEP);
n += 5;
if (n >= 1000) //1秒内没有收到返回
{
time++;
n = 0;
}
if (time == 3)
{
ErrInfo = "重试3次都没有响应";
break;
}
}
if (accept)
_log.Add("WriteDO Receive");
else
_log.Add(string.Format("{0:HH:mm:ss:fff} WriteDO 重试3次都没有响应", DateTime.Now));
if (time > 0) if (LogOut)
{
return false;
}
else
{ {
suspendWrite = false; byte[] bb = new byte[2];
aReadDI.Set(); bb[0] = buff[1];
aReadDO.Set(); bb[1] = buff[0];
ErrInfo = "OK"; ushort flag = BitConverter.ToUInt16(bb, 0);
return true; string s = string.Format("{0:HH:mm:ss.fff} WriteDO {1} ({2},{3})", DateTime.Now, flag, add.ToString(), sta.ToString());
_log.Add(s);
} }
suspend++;
_send.Enqueue(buff);
//suspendWrite = false;
//aReadDI.Set();
//aReadDO.Set();
if (_unrevdRemote == 0) ErrInfo = "OK";
return true;
} }
catch (Exception ex) catch (Exception ex)
{ {
...@@ -544,18 +551,15 @@ namespace Asa.IOModule ...@@ -544,18 +551,15 @@ namespace Asa.IOModule
private void AddLog(string text, byte[] buff)
{
byte[] bb = new byte[2];
bb[0] = buff[1];
bb[1] = buff[0];
ushort flag = BitConverter.ToUInt16(bb, 0);
string s = string.Format("{0:HH:mm:ss:fff} " + text + " {1} fun={2} len={3}", DateTime.Now, flag, buff[7], buff.Length);
_log.Add(s);
}
/// <summary>
/// 发送命令
/// </summary>
private void Send() private void Send()
{ {
string s;
ushort flag;
while (true) while (true)
{ {
bool rtn = _send.TryDequeue(out byte[] result); bool rtn = _send.TryDequeue(out byte[] result);
...@@ -563,27 +567,26 @@ namespace Asa.IOModule ...@@ -563,27 +567,26 @@ namespace Asa.IOModule
{ {
try try
{ {
accept = false;
_client.Send(result); _client.Send(result);
if (LogOut) AddLog("Send", result); //_client.BeginSend(result, 0, result.Length, SocketFlags.None, new AsyncCallback(SendCallback), _client);
int n = 0; if (LogOut)
while (!accept)
{ {
n += 5; byte[] bb = new byte[2];
Thread.Sleep(5); bb[0] = result[1];
if (n >= 500) bb[1] = result[0];
{ flag = BitConverter.ToUInt16(bb, 0);
_log.Add("Send Timeout 500ms"); s = string.Format("{0:HH:mm:ss:fff} Send {1} fun={2} len={3}", DateTime.Now, flag, result[7], result.Length);
break; _log.Add(s);
}
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
ErrInfo = ex.Message; ErrInfo = ex.Message;
_unrevdRemote = 1;
break; break;
} }
} }
Thread.Sleep(SEND_SLEEP); Thread.Sleep(SEND_SLEEP);
} }
} }
...@@ -602,7 +605,7 @@ namespace Asa.IOModule ...@@ -602,7 +605,7 @@ namespace Asa.IOModule
else if (buff[7] == 2) else if (buff[7] == 2)
ReadDI(buff); ReadDI(buff);
else if (buff[7] == 5) else if (buff[7] == 5)
{ } ReadSingle(buff);
} }
Thread.Sleep(10); Thread.Sleep(10);
} }
...@@ -624,7 +627,7 @@ namespace Asa.IOModule ...@@ -624,7 +627,7 @@ namespace Asa.IOModule
bb[0] = buff[1]; bb[0] = buff[1];
bb[1] = buff[0]; bb[1] = buff[0];
ushort flag = BitConverter.ToUInt16(bb, 0); ushort flag = BitConverter.ToUInt16(bb, 0);
s = string.Format("{0:HH:mm:ss:fff} WriteDO Receive {1}", DateTime.Now, flag); s = string.Format("{0:HH:mm:ss:fff} WriteDO {1} fun={2} len={3}", DateTime.Now, flag, buff[7], buff.Length);
_log.Add(s); _log.Add(s);
} }
...@@ -676,10 +679,11 @@ namespace Asa.IOModule ...@@ -676,10 +679,11 @@ namespace Asa.IOModule
bb[0] = buff[1]; bb[0] = buff[1];
bb[1] = buff[0]; bb[1] = buff[0];
ushort flag = BitConverter.ToUInt16(bb, 0); ushort flag = BitConverter.ToUInt16(bb, 0);
s = string.Format("{0:HH:mm:ss:fff} ReadDO id={1} fun={2} len={3}", DateTime.Now, flag, buff[7], buff.Length); s = string.Format("{0:HH:mm:ss:fff} ReadDO {1} fun={2} len={3} (", DateTime.Now, flag, buff[7], buff.Length);
s += Convert.ToString(buff[9], 2); s += Convert.ToString(buff[9], 2);
if (buff[8] == 2) if (buff[8] == 2)
s += "," + Convert.ToString(buff[10], 2); s += "," + Convert.ToString(buff[10], 2);
s += ")";
_log.Add(s); _log.Add(s);
} }
...@@ -712,7 +716,6 @@ namespace Asa.IOModule ...@@ -712,7 +716,6 @@ namespace Asa.IOModule
catch (Exception ex) catch (Exception ex)
{ {
ErrInfo = ex.Message; ErrInfo = ex.Message;
LogUtil.error(ex.ToString());
return false; return false;
} }
...@@ -735,10 +738,11 @@ namespace Asa.IOModule ...@@ -735,10 +738,11 @@ namespace Asa.IOModule
bb[0] = buff[1]; bb[0] = buff[1];
bb[1] = buff[0]; bb[1] = buff[0];
ushort flag = BitConverter.ToUInt16(bb, 0); ushort flag = BitConverter.ToUInt16(bb, 0);
s = string.Format("{0:HH:mm:ss:fff} ReadDI id={1} fun={2} len={3}", DateTime.Now, flag, buff[7], buff.Length); s = string.Format("{0:HH:mm:ss:fff} ReadDI {1} fun={2} len={3} (", DateTime.Now, flag, buff[7], buff.Length);
s += Convert.ToString(buff[9], 2); s += Convert.ToString(buff[9], 2);
if (buff[8] == 2) if (buff[8] == 2)
s += "," + Convert.ToString(buff[10], 2); s += "," + Convert.ToString(buff[10], 2);
s += ")";
_log.Add(s); _log.Add(s);
} }
...@@ -771,7 +775,6 @@ namespace Asa.IOModule ...@@ -771,7 +775,6 @@ namespace Asa.IOModule
catch (Exception ex) catch (Exception ex)
{ {
ErrInfo = ex.Message; ErrInfo = ex.Message;
LogUtil.error(ex.ToString());
return false; return false;
} }
...@@ -785,7 +788,8 @@ namespace Asa.IOModule ...@@ -785,7 +788,8 @@ namespace Asa.IOModule
/// <returns></returns> /// <returns></returns>
private byte[] Command() private byte[] Command()
{ {
byte[] add = BitConverter.GetBytes(++_flag); _flag.TryDequeue(out ushort result);
byte[] add = BitConverter.GetBytes(result);
byte[] data = new byte[7]; byte[] data = new byte[7];
data[0] = add[1]; data[0] = add[1];
data[1] = add[0]; data[1] = add[0];
...@@ -794,7 +798,6 @@ namespace Asa.IOModule ...@@ -794,7 +798,6 @@ namespace Asa.IOModule
data[4] = 0; data[4] = 0;
data[5] = 0; data[5] = 0;
data[6] = 1; data[6] = 1;
if (_flag == ushort.MaxValue) _flag = 0;
return data; return data;
} }
...@@ -851,8 +854,6 @@ namespace Asa.IOModule ...@@ -851,8 +854,6 @@ namespace Asa.IOModule
_log.RemoveRange(0, len); _log.RemoveRange(0, len);
len = 0; len = 0;
} }
Thread.Sleep(1000); Thread.Sleep(1000);
} }
} }
...@@ -866,22 +867,31 @@ namespace Asa.IOModule ...@@ -866,22 +867,31 @@ namespace Asa.IOModule
{ {
if (IsConn && _readDI) if (IsConn && _readDI)
{ {
if (suspendWrite) //if (suspendWrite)
//{
// aWrite.Set();
// aReadDI.WaitOne();
//}
if (suspendDI && suspend > 0)
{ {
aWrite.Set(); suspendDI = false;
aReadDI.WaitOne(); suspend--;
}
else
{
byte[] data = Command();
byte[] buff = new byte[12];
Array.Copy(data, 0, buff, 0, data.Length);
buff[7] = 2; //功能码
buff[9] = _addr[(int)Box_Addr.DI_1]; //地址
if (_type == Box_Type.DIO_16)
buff[11] = 8; //个数
else if (_type == Box_Type.DIO_32)
buff[11] = 16; //个数
_send.Enqueue(buff);
suspendDI = true;
} }
byte[] data = Command();
byte[] buff = new byte[12];
Array.Copy(data, 0, buff, 0, data.Length);
buff[7] = 2; //功能码
buff[9] = _addr[(int)Box_Addr.DI_1]; //地址
if (_type == Box_Type.DIO_16)
buff[11] = 8; //个数
else if (_type == Box_Type.DIO_32)
buff[11] = 16; //个数
_send.Enqueue(buff);
} }
Thread.Sleep(_readDISleep); Thread.Sleep(_readDISleep);
} }
...@@ -896,24 +906,33 @@ namespace Asa.IOModule ...@@ -896,24 +906,33 @@ namespace Asa.IOModule
{ {
if (IsConn && _readDO) if (IsConn && _readDO)
{ {
if (suspendWrite) //if (suspendWrite)
//{
// aWrite.Set();
// aReadDO.WaitOne();
//}
if (suspendDO && suspend > 0)
{ {
aWrite.Set(); suspendDO = false;
aReadDO.WaitOne(); suspend--;
}
else
{
byte[] data = Command();
byte[] buff = new byte[12];
Array.Copy(data, 0, buff, 0, data.Length);
buff[7] = 1; //功能码
buff[9] = _addr[(int)Box_Addr.DO_1]; //地址
if (_type == Box_Type.DIO_16)
buff[11] = 8; //个数
else if (_type == Box_Type.DIO_32)
buff[11] = 16; //个数
else if (_type == Box_Type.DO_16)
buff[11] = 16; //个数
_send.Enqueue(buff);
suspendDO = true;
} }
byte[] data = Command();
byte[] buff = new byte[12];
Array.Copy(data, 0, buff, 0, data.Length);
buff[7] = 1; //功能码
buff[9] = _addr[(int)Box_Addr.DO_1]; //地址
if (_type == Box_Type.DIO_16)
buff[11] = 8; //个数
else if (_type == Box_Type.DIO_32)
buff[11] = 16; //个数
else if (_type == Box_Type.DO_16)
buff[11] = 16; //个数
_send.Enqueue(buff);
} }
Thread.Sleep(_readDOSleep); Thread.Sleep(_readDOSleep);
} }
...@@ -924,22 +943,104 @@ namespace Asa.IOModule ...@@ -924,22 +943,104 @@ namespace Asa.IOModule
/// </summary> /// </summary>
private void Listen() private void Listen()
{ {
byte[] bb = new byte[100]; byte[] temp = new byte[50];
while (true) while (true)
{ {
if (_client.Available > 0) if (_client.Available > 0)
{ {
Thread.Sleep(2); //_client.BeginReceive(temp, 0, temp.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), _client);
int len = _client.Receive(bb);
byte[] buff = new byte[len]; int len = _client.Receive(temp);
Array.Copy(bb, buff, len); if (len > 15) //连包
_receive.Enqueue(buff); {
accept = true; byte[] aa = new byte[len / 2];
byte[] bb = new byte[len - aa.Length];
Array.Copy(temp, 0, aa, 0, aa.Length);
Array.Copy(temp, aa.Length, bb, 0, bb.Length);
_receive.Enqueue(aa);
_receive.Enqueue(bb);
}
else
{
byte[] cc = new byte[len];
Array.Copy(temp, cc, len);
_receive.Enqueue(cc);
}
} }
Thread.Sleep(NET_SLEEP); Thread.Sleep(NET_SLEEP);
} }
} }
private void SendCallback(IAsyncResult ar)
{
try
{
Socket client = (Socket)ar.AsyncState;
int bytesSent = client.EndSend(ar);
}
catch (Exception ex)
{
ErrInfo = ex.Message;
}
}
private void ReceiveCallback(IAsyncResult ar)
{
try
{
int len = _client.EndReceive(ar);
//if (len > 0)
//{
// if (len > 15) //连包
// {
// byte[] aa = new byte[len / 2];
// byte[] bb = new byte[len - aa.Length];
// Array.Copy(temp, 0, aa, 0, aa.Length);
// Array.Copy(temp, aa.Length, bb, 0, bb.Length);
// _receive.Enqueue(aa);
// _receive.Enqueue(bb);
// }
// else
// {
// byte[] cc = new byte[len];
// Array.Copy(temp, cc, len);
// _receive.Enqueue(cc);
// }
//}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private void ConnectCallback(IAsyncResult ar)
{
if (!ar.IsCompleted) return;
if (_client == null || !_client.Connected) return;
_client.EndConnect(ar);
}
private void Flag()
{
ushort n = 0;
while (true)
{
if (_flag.Count < 10)
{
_flag.Enqueue(++n);
if (n == ushort.MaxValue) n = 0;
}
Thread.Sleep(5);
}
}
} }
} }
\ No newline at end of file \ No newline at end of file
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!