最近遇到了个问题,主要是在做一个异步通讯的时候会一直循环在某个代码段,始终无法跳出,还望各位大神给个建议
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Threading;
using System.Net.Sockets;
using RetDLL;
using System.Collections; //在C#中使用ArrayList必须引用Collections类
using System.Diagnostics;
namespace PTVKey
{
class ThreadServer:Form1
{
private byte[] recvBuffer;//存放消息数据
private Socket socket;//为客户端建立的SOCKET连接
public Form1 form1;
private bool bStop;
private bool bResult;
public int indexStra;
public string getkeymsg;
private Thread thread;
public string cmd ="00#0";
private KeyInfo keyInfo;
public ThreadServer()
{
}
public ThreadServer(Socket s, Form1 frm)
{
this.form1 = frm;
this.socket = s;
recvBuffer = new byte[65535];
bStop = false;
bResult = false;
}
public void End()
{
bStop = true;
}
public void Start()
{
socket.BeginReceive(recvBuffer, 0, recvBuffer.Length, 0, new AsyncCallback(RecieveCallBack), socket);
Thread.Sleep(50);
SendKey();
//开始心跳线程
thread = new Thread(Run);
thread.Start();
}
private Ret SendKey()
{
Ret ret = new Ret(true);
keyInfo = new KeyInfo();
ret = GetKeyFromDB(ref keyInfo);
if (!ret.b)
{
return ret;
}
//SET#KEY#160#字符串
string key = keyInfo.mainKey.Trim() ;
string msg = "SET#KEY#" + key.Length.ToString() + "#" + keyInfo.mainKey;
ret = sendServerMsg(msg);
return ret;
}
#region 功能函数
/// <summary>
/// 从数据库中获取一条未使用的KEY
/// </summary>
/// <returns></returns>
private Ret GetKeyFromDB(ref KeyInfo keyInfo)
{
Ret ret = new Ret(true);
DBData dd = new DBData();
string strSQL = string.Format("select top 1 * from key_info where batchId= {0} and status = 0 order by createTime asc" , Program.batchInfo.id);
ArrayList list = new ArrayList();
int cnt = dd.getKeInfo(strSQL, ref list);
if (cnt <= 0)
{
ret.b = false;
return ret;
}
keyInfo = (KeyInfo)list[0];
return ret;
}
/// <summary>
/// 修改数据库中key使用状态
/// </summary>
/// <returns></returns>
private Ret ModifyKeyStatus()
{
Ret ret = new Ret(true);
string strSQL = string.Format("update key_info set status = 1 where batchId= {0} and id = {1}", Program.batchInfo.id , keyInfo.id);
DB db = new DB();
int res = db.executeSQLNonQuery(strSQL);
if (res <= 0)
{
ret.b = false;
}
return ret;
}
#endregion
static bool IsSocketConnected(Socket s)
{
return !((s.Poll(1000, SelectMode.SelectRead) && (s.Available == 0)) || !s.Connected);
}
private void Run()
{
string strip = socket.RemoteEndPoint.ToString();
while (!bStop)
{
bool b = IsSocketConnected(socket);
if (!b)
{
break;
}
Thread.Sleep(200);
}
for (int i = 0; i < 3; i++)
{
string output;
RunCmd("arp -d", out output);
Thread.Sleep(200);
}
try
{
Thread.Sleep(100);
if (socket.Connected)
{
socket.Close();
}
form1.trace(strip + " 断开了服务器连接.");
}
catch
{
form1.trace(strip + " 断开了服务器连接.");
}
try
{
thread.Abort();
}
catch(Exception ex)
{
string str = ex.Message.ToString();
}
}
private void RecieveCallBack(IAsyncResult AR)
{
try
{
Socket RSocket = (Socket)AR.AsyncState;
int REnd = RSocket.EndReceive(AR);
RSocket.BeginReceive(recvBuffer, 0, recvBuffer.Length, 0, new AsyncCallback(RecieveCallBack), RSocket);
//转换
string recvMsg = Encoding.ASCII.GetString(recvBuffer, 0, REnd);
// string recvMsg = Encoding.Unicode.GetString(recvBuffer, 0, REnd);
HandleMsg(recvMsg);
}
catch
{
//解析处理结果
bResult = false;
bStop = true;
}
}
private Ret HandleMsg(string msg)
{
Ret ret = new Ret(true);
if (msg == "" || msg.Length <= 0)
{
ret.b = false;
ret.str = "接收消息为空";
//Process.GetCurrentProcess().Kill();
form1.trace1(ret.str);
return ret;
}
else
{
form1.trace("服务器收到消息:" + msg);
indexStra = msg.LastIndexOf("#") + 1;//获取最后一个#之后的字符串
string a = msg.Substring(indexStra, msg.Length - indexStra);
int b = a.LastIndexOf("\t") + 1;
getkeymsg = a.Substring(b, a.Length - b);
//SET#KEY#字符串长度#字符串
if (msg.Contains("SET"))
{
if (msg.Contains("FAIL"))
{
//设置失败:界面展示;发送停止指令
form1.trace("设置Key失败");
form1.resultDisp("NG", System.Drawing.Color.DarkRed);
form1.keyDisp(keyInfo.mainKey);
string cmd = "00#0";
sendServerMsg(cmd);
}
else
{
//这里可以检测服务器传递过来的KEY是否正确
string strSQL = string.Format("select * from key_info where key3 = '" + getkeymsg + "' and status = 0 ");//判断数据库里面是是否有该key
Ret ret1 = new Ret(true);
DBData dd1 = new DBData();
ArrayList list1 = new ArrayList();
int cnt = dd1.getKeInfo(strSQL, ref list1);
if (cnt <= 0)
{
form1.trace("检查结束 传递服务器传递的KEY值不正确");
form1.resultDisp("NG", System.Drawing.Color.Red);
form1.keyDisp(keyInfo.mainKey);
string cmd = "00#0";
sendServerMsg(cmd);
}
//发送GET#KEY#CHECKOK
else
{
string cmd = "GET#KEY#CHECKOK";
sendServerMsg(cmd);
form1.trace("检查结束 KEY值正确");
}
}
}
if (msg.Contains("GET"))
{
if (msg.Contains("FAIL"))
{
//设置失败:界面展示;发送停止指令
form1.trace("设置Key失败");
form1.resultDisp("NG", System.Drawing.Color.Red);
ThreadServer ss = new ThreadServer();
ss.End();
}
else
{
//更新数据库当前Key使用状态
ret = updateStatus();
if (!ret.b)
{
form1.trace1("设置Key失败");
form1.resultDisp("NG", System.Drawing.Color.Red);
ThreadServer ss = new ThreadServer();
ss.End();
}
else
{
form1.trace1("设置Key成功");
form1.resultDisp("PASS", System.Drawing.Color.DarkGreen);
ThreadServer ss = new ThreadServer();
ss.End();
}
}
form1.keyDisp(keyInfo.mainKey);
string cmd = "00#0";
sendServerMsg(cmd);
//
}
return ret;
}
}
/// <summary>
/// 发送消息到客户端(板子)
/// </summary>
/// <param name="msg"></param>
/// <returns></returns>
private Ret sendServerMsg(string msg)
{
Ret ret = new Ret(true);
try
{
byte[] s = Encoding.ASCII.GetBytes(msg);
// byte[] s = Encoding.Unicode.GetBytes(msg);
socket.Send(s, 0, s.Length, 0);
form1.trace("服务器发送消息:"+msg);
}
catch (Exception ey)
{
ret.b = false;
ret.str = ey.Message.ToString();
form1.trace("服务器发送异常:" + ret.str);
}
return ret;
}
#region 解析功能函数
private static string CmdPath = @"C:\Windows\System32\cmd.exe";
/// <summary>
/// 执行cmd命令
/// 多命令请使用批处理命令连接符:
/// <![CDATA[
/// &:同时执行两个命令
/// |:将上一个命令的输出,作为下一个命令的输入
/// &&:当&&前的命令成功时,才执行&&后的命令
/// ||:当||前的命令失败时,才执行||后的命令]]>
/// 其他请百度
/// </summary>
/// <param name="cmd"></param>
/// <param name="output"></param>
public void RunCmd(string cmd, out string output)
{
cmd = cmd.Trim().TrimEnd('&') + "&exit";//说明:不管命令是否成功均执行exit命令,否则当调用ReadToEnd()方法时,会处于假死状态
using (Process p = new Process())
{
p.StartInfo.FileName = CmdPath;
p.StartInfo.UseShellExecute = false; //是否使用操作系统shell启动
p.StartInfo.RedirectStandardInput = true; //接受来自调用程序的输入信息
p.StartInfo.RedirectStandardOutput = true; //由调用程序获取输出信息
p.StartInfo.RedirectStandardError = true; //重定向标准错误输出
p.StartInfo.CreateNoWindow = true; //不显示程序窗口
p.Start();//启动程序
//向cmd窗口写入命令
p.StandardInput.WriteLine(cmd);
p.StandardInput.AutoFlush = true;
//获取cmd窗口的输出信息
output = p.StandardOutput.ReadToEnd();
p.WaitForExit();//等待程序执行完退出进程
p.Close();
}
}
private Ret updateStatus()
{
Ret ret = new Ret(true);
try
{
string strSQL = string.Format("update key_info set status= 1 where batchId={0} and id={1}", Program.batchInfo.id, keyInfo.id);
DB db = new DB();
int cnt = db.executeSQLNonQuery(strSQL);
if (cnt <= 0)
{
ret.b = false;
ret.str = "更新数据库失败";
}
}
catch(Exception ex)
{
ret.b = false;
ret.str = ex.Message.ToString();
}
return ret;
}
private string parseInfo(string info)
{
string str = "";
int index = info.LastIndexOf("#");
str = info.Substring(index+1);
return str;
}
/// <summary>
/// 解析设备ID
/// </summary>
/// <param name="stbid"></param>
/// <returns></returns>
private string parseMacFromSTBID(string stbid)
{
string str = "";
if (stbid.Length <= 12)
{
return str;
}
return stbid.Substring(stbid.Length-12);
}
/// <summary>
/// 统计字符在字符串中出现的次数
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
private int StatisticsCount(string str)
{
string s = "#";
int Star = 0;
int Count = 0;
while (Star != -1)
{
Star = str.IndexOf(s, Star);//获取字符的索引
if (Star != -1)
{
Count++;
Star++;
}
}
return Count;
}
#endregion
}
}
还希望大神给个代码,你就这样说,说到天上也没人能解决你的问题
private Ret HandleMsg(string msg)
{
Ret ret = new Ret(true);
if (msg == "" || msg.Length <= 0)
{
ret.b = false;
ret.str = "接收消息为空";
//Process.GetCurrentProcess().Kill();
form1.trace1(ret.str);
return ret;
}
主要一直循环在这里 不知道为什么
看你的代码也不是自己写的,你可以再换一个代码,或者问写代码的人。如果都不行,就花点钱找个程序员吧。
会调试吗?在ide里面加断点调试下或者多加几个打印输出看下结果,确定问题在哪里
建议你在这个地方逐步加断点调试或是加提示框
你加个断点调试下, 看看是不是你每次处理消息的地方 msg都是空的 所以跳不出去
很明显,这是一个通信线程,线程在不断地接收数据
public void Start()
{
socket.BeginReceive(recvBuffer, 0, recvBuffer.Length, 0, new AsyncCallback(RecieveCallBack), socket);
Thread.Sleep(50);
SendKey();
//开始心跳线程
thread = new Thread(Run);
thread.Start();
}
这个函数里面有一个 socket.BeginReceive(recvBuffer, 0, recvBuffer.Length, 0, new AsyncCallback(RecieveCallBack), socket);
这是一个异步接收数据的方法,只要接收到数据,就会调用回调函数RecieveCallBack
private void RecieveCallBack(IAsyncResult AR)
{
try
{
Socket RSocket = (Socket)AR.AsyncState;
int REnd = RSocket.EndReceive(AR);
RSocket.BeginReceive(recvBuffer, 0, recvBuffer.Length, 0, new AsyncCallback(RecieveCallBack), RSocket);
//转换
string recvMsg = Encoding.ASCII.GetString(recvBuffer, 0, REnd);
// string recvMsg = Encoding.Unicode.GetString(recvBuffer, 0, REnd);
HandleMsg(recvMsg);
}
catch
{
//解析处理结果
bResult = false;
bStop = true;
}
}
通过回调函数再去调用HandleMsg方法,所以你看到HandleMsg里面一直在循环,因为你一直在接收数据
另外:Run()方法里面有一句 socket.Close(); 跑了这个后,你的循环就会停掉.
一般我们进行Socket通信时经常采用这种方法