我说的这个问题应该是比较常见的问题,不知道童鞋们都是怎么做的,问题描述如下:
设计一个类库(LicSDK);
公开两个方法(Start,Stop);
其中start方法中创建一个对象(LicConnector)用来通过Socket连接服务器,接受服务器发来的消息以及发送消息给服务器;
LicConnector接收消息是在一个独立的线程做的。
我现在的需求是当从服务器收到指定的消息(登录成功),Start 方法返回True ,否则返回False;
一般的,Start方法调用了LicConnector的Connec方法,连接成功了就会返回
mConnector = new LicConnector();
mConnector.Debug += mConnector_Debug;
mConnector.MessageReceived += mConnector_MessageReceived;
mConnector.Host = mServerHost;
mConnector.Port = mServerPort;
if (!mConnector.Connect())
{
sdkReturn.Code = LicDefines.RET_CONNECT_FAIL;
sdkReturn.Message = string.Format("Connect to License server fail.\t{0}:{1}", mServerHost, mServerPort);
return sdkReturn;
}
return true;
为了让Start等待收到登录成功消息后才返回,我在Start方法里加了个循环
int intNum = 0;
while (!wait.IsFinished && intNum < LicDefines.NET_TIMEOUT * 10)
{
Thread.Sleep(100);
intNum++;
}
if(intNum<LicDefines.NET_TIMEOUT*10){
retrun false;
}
else{
return true;
}
在mConnector_MessageReceived方法中当收到登录成功消息后将wait.IsFinished置为True从而结束上面的循环;
但是现在的结果是每次调Start方法返回都是超时的;
详细代码如下:
LicSDK
[code=csharp]
public class LicSDK
{
public event Action<string, string> Debug;
private string mName;
private LicConnector mConnector;
private string mServerHost;
private int mServerPort;
private string mClientName;
private bool mIsAuthenticated;
private string mRequest;
private List<WaitResponse> mListWaitResponse;
#region Properties
public string Name
{
get { return mName; }
set { mName = value; }
}
public string ClientName
{
set { mClientName = value; }
}
public string ServerHost
{
set
{
mServerHost = value;
if (mConnector != null)
{
mConnector.Host = value;
}
}
}
public int ServerPort
{
set
{
mServerPort = value;
if (mConnector != null)
{
mConnector.Port = value;
}
}
}
#endregion
public LicSDK()
{
mName = "LicSDK";
mClientName = "LicSDK";
mServerHost = "127.0.0.1";
mServerPort = 3070;
mIsAuthenticated = false;
mRequest = string.Empty;
mListWaitResponse = new List<WaitResponse>();
}
public LicSDKReturn Start()
{
LicSDKReturn sdkReturn = new LicSDKReturn();
sdkReturn.Result = true;
if (mConnector != null)
{
mConnector.Stop();
}
WaitResponse wait = mListWaitResponse.FirstOrDefault(w => w.Name == LicDefines.WAIT_LOGON);
if (wait != null)
{
mListWaitResponse.Remove(wait);
}
wait = new WaitResponse();
wait.Name = mRequest;
wait.IsFinished = false;
mListWaitResponse.Add(wait);
mConnector = new LicConnector();
mConnector.Debug += mConnector_Debug;
mConnector.MessageReceived += mConnector_MessageReceived;
mConnector.Host = mServerHost;
mConnector.Port = mServerPort;
if (!mConnector.Connect())
{
sdkReturn.Code = LicDefines.RET_CONNECT_FAIL;
sdkReturn.Message = string.Format("Connect to License server fail.\t{0}:{1}", mServerHost, mServerPort);
return sdkReturn;
}
//int intNum = WaitForResponse(wait);
//if (intNum >= LicDefines.NET_TIMEOUT * 10)
//{
// sdkReturn.Result = false;
// sdkReturn.Code = LicDefines.RET_NET_TIMEOUT;
// sdkReturn.Message = string.Format("Wait for {0} response timeout.", mRequest);
// return sdkReturn;
//}
//if (!wait.IsSuccessful)
//{
// sdkReturn.Result = false;
// sdkReturn.Code = LicDefines.RET_FAIL;
// sdkReturn.Message = string.Format("Logon fail.\t{0}", wait.Message);
// return sdkReturn;
//}
return sdkReturn;
}
public void Stop()
{
if (mConnector != null)
{
mConnector.Stop();
}
}
public LicSDKReturn GetLicense(List<License> listLicenses)
{
LicSDKReturn sdkReturn = new LicSDKReturn();
sdkReturn.Result = true;
try
{
if (listLicenses == null || listLicenses.Count <= 0)
{
sdkReturn.Result = false;
sdkReturn.Code = LicDefines.RET_PARAM_INVALID;
sdkReturn.Message = string.Format("License names is null or no member.");
return sdkReturn;
}
if (!mIsAuthenticated)
{
sdkReturn.Result = false;
sdkReturn.Code = LicDefines.RET_NOT_AUTHENTICATE;
sdkReturn.Message = string.Format("Not authenticate");
return sdkReturn;
}
JsonObject json = GetBasicMessageObject(LicDefines.LICENSE_MSG_CLASS_REQRES, LicDefines.LICENSE_MSG_REQUEST_GET_LICENSE);
json["requestid"] = new JsonProperty(2);
json[LicDefines.KEYWORD_MSG_DATA] = new JsonProperty(new JsonObject());
foreach (License lic in listLicenses)
{
if (lic.Type == 1)
{
if (json[LicDefines.KEYWORD_MSG_DATA]["share"] == null)
{
json[LicDefines.KEYWORD_MSG_DATA]["share"] = new JsonProperty(new JsonObject());
}
json[LicDefines.KEYWORD_MSG_DATA]["share"][lic.Name] = new JsonProperty("\"" + lic.Name + "\"");
}
if (lic.Type == 2)
{
if (json[LicDefines.KEYWORD_MSG_DATA]["monopolize"] == null)
{
json[LicDefines.KEYWORD_MSG_DATA]["monopolize"] = new JsonProperty(new JsonObject());
}
json[LicDefines.KEYWORD_MSG_DATA]["monopolize"][lic.Name] = new JsonProperty("\"" + lic.Name + "\"");
}
}
if (mConnector == null)
{
sdkReturn.Result = false;
sdkReturn.Code = LicDefines.RET_SERVER_NOT_CONNECTED;
sdkReturn.Message = string.Format("Connector is null");
return sdkReturn;
}
mConnector.SendMessage(json.ToString());
//mRequest = "GETLIC";
//int intNum = WaitForResponse(mRequest);
//if (intNum >= LicDefines.NET_TIMEOUT * 100)
//{
// sdkReturn.Result = false;
// sdkReturn.Code = LicDefines.RET_NET_TIMEOUT;
// sdkReturn.Message = string.Format("Wait for {0} response timeout.", mRequest);
// return sdkReturn;
//}
sdkReturn.Message = json.ToString();
return sdkReturn;
}
catch (Exception ex)
{
sdkReturn.Result = false;
sdkReturn.Code = LicDefines.RET_FAIL;
sdkReturn.Message = string.Format("Get Licenses info fail.\t{0}", ex.Message);
return sdkReturn;
}
return sdkReturn;
}
#region Basic
private void SubDebug(string category, string msg)
{
if (Debug != null)
{
Debug(mName, string.Format("{0}\t{1}", category, msg));
}
}
private void AuthRequest(string session)
{
string orgSession = session;
string mySession = Utils.GetValidication(orgSession);
JsonObject json = GetBasicMessageObject(LicDefines.LICENSE_MSG_CLASS_AUTHENTICATE, LicDefines.LICENSE_MSG_AUTH_LOGON);
json[LicDefines.KEYWORD_MSG_DATA] = new JsonProperty(new JsonObject());
json[LicDefines.KEYWORD_MSG_DATA][LicDefines.KEYWORD_MSG_CLIENT_NAME] = new JsonProperty("\"" + mClientName + "\"");
json[LicDefines.KEYWORD_MSG_DATA][LicDefines.KEYWORD_MSG_CLIENT_TYPE] = new JsonProperty(1);
json[LicDefines.KEYWORD_MSG_DATA][LicDefines.KEYWORD_MSG_HEARTBEAT] = new JsonProperty(30);
json[LicDefines.KEYWORD_MSG_DATA][LicDefines.KEYWORD_MSG_PROTOCOL] = new JsonProperty("\"1.00\"");
json[LicDefines.KEYWORD_MSG_DATA][LicDefines.KEYWORD_MSG_SESSION] = new JsonProperty("\"" + orgSession + "\"");
json[LicDefines.KEYWORD_MSG_DATA][LicDefines.KEYWORD_MSG_VERIFICATION] = new JsonProperty("\"" + mySession + "\"");
//SubDebug("AuthRequest", string.Format("Logon message:{0}", json.ToString()));
mConnector.SendMessage(json.ToString());
}
private JsonObject GetBasicMessageObject(int classID, int messageID)
{
JsonObject json = new JsonObject();
json[LicDefines.KEYWORD_MSG_CLASSID] = new JsonProperty(classID);
json[LicDefines.KEYWORD_MSG_CLASSDESC] = new JsonProperty("\"" + classID + "\"");
json[LicDefines.KEYWORD_MSG_MESSAGEID] = new JsonProperty(messageID);
json[LicDefines.KEYWORD_MSG_MESSAGEDESC] = new JsonProperty("\"" + messageID + "\"");
json[LicDefines.KEYWORD_MSG_CURRENTTIME] = new JsonProperty("\"" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "\"");
switch (classID)
{
case LicDefines.LICENSE_MSG_CLASS_CONNECTION:
switch (messageID)
{
case LicDefines.LICENSE_MSG_CONNECTION_HEARTBEAT:
json[LicDefines.KEYWORD_MSG_CLASSDESC].SetValue("connection");
json[LicDefines.KEYWORD_MSG_MESSAGEDESC].SetValue("heartbeat");
break;
}
break;
case LicDefines.LICENSE_MSG_CLASS_AUTHENTICATE:
switch (messageID)
{
case LicDefines.LICENSE_MSG_AUTH_LOGON:
json[LicDefines.KEYWORD_MSG_CLASSDESC].SetValue("authenticate");
json[LicDefines.KEYWORD_MSG_MESSAGEDESC].SetValue("logon");
break;
}
break;
case LicDefines.LICENSE_MSG_CLASS_NOTIFY:
switch (messageID)
{
case LicDefines.LICENSE_MSG_CONNECTION_HEARTBEAT:
json[LicDefines.KEYWORD_MSG_CLASSDESC].SetValue("connection");
json[LicDefines.KEYWORD_MSG_MESSAGEDESC].SetValue("heartbeat");
break;
}
break;
case LicDefines.LICENSE_MSG_CLASS_REQRES:
switch (messageID)
{
case LicDefines.LICENSE_MSG_REQUEST_GET_LICENSE:
json[LicDefines.KEYWORD_MSG_CLASSDESC].SetValue("request and response");
json[LicDefines.KEYWORD_MSG_MESSAGEDESC].SetValue("request get license");
break;
}
break;
}
return json;
}
private int WaitForResponse(WaitResponse wait)
{
int intNum = 0;
while (!wait.IsFinished && intNum < LicDefines.NET_TIMEOUT * 10)
{
Thread.Sleep(100);
intNum++;
}
return intNum;
}
#endregion
#region EventHandler
void mConnector_MessageReceived(string client, string msg)
{
string strMsg = string.Empty;
string strCategory = string.Format("ProcessMsg[{0}]", client);
try
{
JsonObject jsonMessage = new JsonObject(msg);
int classid = Convert.ToInt32(jsonMessage[LicDefines.KEYWORD_MSG_CLASSID].GetValue());
int msgid = Convert.ToInt32(jsonMessage[LicDefines.KEYWORD_MSG_MESSAGEID].GetValue());
SubDebug(strCategory, string.Format("ClassID:{0}\tMessageID:{1}", classid, msgid));
switch (classid)
{
case LicDefines.LICENSE_MSG_CLASS_CONNECTION:
switch (msgid)
{
case LicDefines.LICENSE_MSG_CONNECTION_HEARTBEAT:
SubDebug(strCategory, string.Format("Server hearbeat.\t{0}", jsonMessage[LicDefines.KEYWORD_MSG_CURRENTTIME].GetValue().ToString()));
break;
default:
SubDebug(strCategory, string.Format("Unkown message id.\t{0}", msgid));
break;
}
break;
case LicDefines.LICENSE_MSG_CLASS_AUTHENTICATE:
switch (msgid)
{
case LicDefines.LICENSE_MSG_AUTH_WELCOME:
AuthRequest(jsonMessage[LicDefines.KEYWORD_MSG_DATA][LicDefines.KEYWORD_MSG_SESSION].GetValue().ToString());
break;
case LicDefines.LICENSE_MSG_AUTH_SUCCESS:
strMsg = jsonMessage[LicDefines.KEYWORD_MSG_DATA][LicDefines.KEYWORD_MSG_VERIFICATION].GetValue().ToString();
WaitResponse wait = mListWaitResponse.FirstOrDefault(w => w.Name == LicDefines.WAIT_LOGON);
if (wait != null)
{
wait.IsFinished = true;
wait.IsSuccessful = true;
wait.Message = strMsg;
}
mIsAuthenticated = true;
SubDebug(strCategory, string.Format("Authentication success.\t{0}", strMsg));
break;
default:
SubDebug(strCategory, string.Format("Unkown message id.\t{0}", msgid));
break;
}
break;
case LicDefines.LICENSE_MSG_CLASS_NOTIFY:
SubDebug(strCategory, string.Format("Server notification.\t{0}", jsonMessage.ToString()));
break;
case LicDefines.LICENSE_MSG_CLASS_REQRES:
SubDebug(strCategory, string.Format("Server response.\t{0}", jsonMessage.ToString()));
break;
default:
SubDebug(strCategory, string.Format("Unkown classid.\t{0}", classid));
break;
}
}
catch (Exception ex)
{
SubDebug(strCategory, string.Format("Process message fail.\t{0}", ex.Message));
}
}
void mConnector_Debug(string client, string msg)
{
SubDebug("Connector[" + client + "]", msg);
}
#endregion
}
[/code]
LicConnector
[code=csharp]
class LicConnector
{
public event Action<string, string> Debug;
public event Action<string, string> MessageReceived;
private string mClient;
private TcpClient mTcpClient;
private SslStream mSslStream;
private string mHost;
private int mPort;
private byte[] mBuffer;
private Thread mReceiveThread;
private Thread mHearBeatThread;
private int mDataLength;
private bool mIsReceiveHead;
private bool mIsEncryt;
#region Properties
public string Client
{
get { return mClient; }
set { mClient = value; }
}
public string Host
{
set { mHost = value; }
}
public int Port
{
set { mPort = value; }
}
#endregion
public LicConnector()
{
mClient = "LicConnector";
mHost = "127.0.0.1";
mPort = 3070;
mDataLength = 0;
mBuffer = new byte[LicDefines.NET_BUFFER_SIZE];
mIsReceiveHead = true;
mIsEncryt = false;
}
public bool Connect()
{
if (mTcpClient != null)
{
try
{
mTcpClient.Close();
mTcpClient = null;
}
catch { }
}
try
{
mTcpClient = new TcpClient();
mTcpClient.Connect(mHost, mPort);
if (mTcpClient.Connected)
{
SubDebug("Connect", string.Format("Server connected.\tLocal:{0}\tRemote:{1}", mTcpClient.Client.LocalEndPoint, mTcpClient.Client.RemoteEndPoint));
mSslStream = new SslStream(mTcpClient.GetStream(), false, new RemoteCertificateValidationCallback(ServerValidation), null);
mSslStream.AuthenticateAsClient(mHost);
mIsReceiveHead = true;
StartReceiveThread();
//StartHeartBeatThread();
return true;
}
else
{
return false;
}
}
catch (Exception ex)
{
SubDebug("Connect", string.Format("Connector connect fail.\t{0}", ex.Message));
return false;
}
}
public void Stop()
{
StopHearBeatThread();
StopReceiveThread();
if (mTcpClient != null)
{
try
{
mTcpClient.Close();
mTcpClient = null;
}
catch { }
}
SubDebug("Stop", string.Format("Connector stopped."));
}
#region SendData
public void SendMessage(string msg)
{
try
{
//byte[] data = CryptoHelper.EncryptNN256(msg);
byte[] data = Encoding.ASCII.GetBytes(msg);
NetPacketHeader header = new NetPacketHeader();
header.Flag = Encoding.ASCII.GetBytes("LM");
header.Format = 1;
header.State = 0;
header.Size = (uint)data.Length;
byte[] headData = Utils.StructToBytes(header);
mSslStream.Write(headData);
mSslStream.Write(data);
mSslStream.Flush();
}
catch (Exception ex)
{
SubDebug("SendMessage", string.Format("Send message fail.\t{0}", ex.Message));
}
}
#endregion
#region ReceiveData
private void StartReceiveThread()
{
if (mReceiveThread != null)
{
try
{
mReceiveThread.Abort();
mReceiveThread = null;
}
catch { }
}
try
{
mReceiveThread = new Thread(new ThreadStart(ReceiveThreadWorker));
mReceiveThread.Start();
SubDebug("StartReceiveThread", string.Format("Receive thread started.\t{0}", mReceiveThread.ManagedThreadId));
}
catch (Exception ex)
{
SubDebug("StartReceiveThread", string.Format("Start receive thread fail.\t{0}", ex.Message));
}
}
private void StopReceiveThread()
{
if (mReceiveThread != null)
{
try
{
mReceiveThread.Abort();
mReceiveThread = null;
SubDebug("StopReceiveThread", string.Format("Receive thread stopped."));
}
catch (Exception ex)
{
SubDebug("StopReceiveThread", string.Format("Stop receive thread fail.\t{0}", ex.Message));
}
}
}
private void ReceiveThreadWorker()
{
int intSize = 0;
int intRest = 0;
int intBuffered = 0;
byte[] byteHead = new byte[LicDefines.NET_HEAD_SIZE];
byte[] byteData;
while (true)
{
try
{
if (mSslStream.CanRead && mTcpClient.Connected)
{
if (mIsReceiveHead)
{
intRest = LicDefines.NET_HEAD_SIZE;
intBuffered = 0;
intSize = mSslStream.Read(mBuffer, intBuffered, intRest);
if (intSize == 0) { continue; }
while (intSize + intBuffered < LicDefines.NET_HEAD_SIZE)
{
intBuffered += intSize;
intRest = LicDefines.NET_HEAD_SIZE - intBuffered;
intSize = mSslStream.Read(mBuffer, intBuffered, intRest);
}
Array.Copy(mBuffer, 0, byteHead, 0, LicDefines.NET_HEAD_SIZE);
NetPacketHeader header = new NetPacketHeader();
header = (NetPacketHeader)Utils.BytesToStruct(byteHead, typeof(NetPacketHeader));
mDataLength = (int)header.Size;
mIsEncryt = (header.State & 4) == 0 ? false : true;
//SubDebug("ReceiveThreadWorker", string.Format("Head received.\t{0}\t{1}", Encoding.ASCII.GetString(header.Flag), mDataLength));
mIsReceiveHead = false;
}
else
{
intRest = mDataLength;
intBuffered = 0;
intSize = mSslStream.Read(mBuffer, intBuffered, intRest);
if (intSize == 0) { continue; }
while (intSize + intBuffered < mDataLength)
{
intBuffered += intSize;
intRest = mDataLength - intBuffered;
intSize = mSslStream.Read(mBuffer, intBuffered, intRest);
}
byteData = new byte[mDataLength];
Array.Copy(mBuffer, 0, byteData, 0, mDataLength);
string strData = string.Empty;
if (mIsEncryt)
{
strData = CryptoHelper.DecryptNN256(byteData);
}
else
{
strData = Encoding.ASCII.GetString(byteData);
}
//SubDebug("ReceiveThreadWorker", string.Format("Receive data:{0}", strData));
Processmessage(strData);
SubMessageReceived(strData);
mIsReceiveHead = true;
}
}
}
catch (Exception ex)
{
SubDebug("ReceiveThreadWorker", string.Format("Receive data fail.\t{0}", ex.Message));
}
Thread.Sleep(10);
}
}
private void Processmessage(string msg)
{
try
{
JsonObject jsonMessage = new JsonObject(msg);
int classid = Convert.ToInt32(jsonMessage[LicDefines.KEYWORD_MSG_CLASSID].GetValue());
int msgid = Convert.ToInt32(jsonMessage[LicDefines.KEYWORD_MSG_MESSAGEID].GetValue());
switch (classid)
{
case LicDefines.LICENSE_MSG_CLASS_CONNECTION:
switch (msgid)
{
case LicDefines.LICENSE_MSG_CONNECTION_HEARTBEAT:
SubDebug("Processmessage", string.Format("Server hearbeat.\t{0}", jsonMessage[LicDefines.KEYWORD_MSG_CURRENTTIME].GetValue().ToString()));
break;
default:
break;
}
break;
case LicDefines.LICENSE_MSG_CLASS_AUTHENTICATE:
switch (msgid)
{
case LicDefines.LICENSE_MSG_AUTH_SUCCESS:
StartHeartBeatThread();
break;
default:
break;
}
break;
default:
break;
}
}
catch (Exception ex)
{
SubDebug("Processmessage", string.Format("Process message fail.\t{0}", ex.Message));
}
}
#endregion
#region HeartBeat
private void StartHeartBeatThread()
{
if (mHearBeatThread != null)
{
try
{
mHearBeatThread.Abort();
mHearBeatThread = null;
}
catch { }
}
try
{
mHearBeatThread = new Thread(new ThreadStart(HearBeatThreadWorker));
mHearBeatThread.Start();
SubDebug("StartHeartBeatThread", string.Format("HearBeat thread started.\t{0}", mHearBeatThread.ManagedThreadId));
}
catch (Exception ex)
{
SubDebug("StartHeartBeatThread", string.Format("Start HeartBeat thread fail.\t{0}", ex.Message));
}
}
private void StopHearBeatThread()
{
if (mHearBeatThread != null)
{
try
{
mHearBeatThread.Abort();
mHearBeatThread = null;
SubDebug("StopHearBeatThread", string.Format("HeartBeat thread stopped."));
}
catch (Exception ex)
{
SubDebug("StopHearBeatThread", string.Format("Stop HeartBeat thread fail.\t{0}", ex.Message));
}
}
}
private void HearBeatThreadWorker()
{
while (true)
{
try
{
JsonObject json = new JsonObject();
json[LicDefines.KEYWORD_MSG_CLASSID] = new JsonProperty(LicDefines.LICENSE_MSG_CLASS_CONNECTION);
json[LicDefines.KEYWORD_MSG_CLASSDESC] = new JsonProperty("\"connection\"");
json[LicDefines.KEYWORD_MSG_MESSAGEID] = new JsonProperty(LicDefines.LICENSE_MSG_CONNECTION_HEARTBEAT);
json[LicDefines.KEYWORD_MSG_MESSAGEDESC] = new JsonProperty("\"heartbeat\"");
json[LicDefines.KEYWORD_MSG_CURRENTTIME] = new JsonProperty(DateTime.Now.ToString("\"" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "\""));
string strJson = json.ToString();
SubDebug("HearBeatThreadWorker", string.Format("HeartBeat:{0}", strJson));
SendMessage(strJson);
}
catch (Exception ex)
{
SubDebug("HearBeatThreadWorker", string.Format("Send HeartBeat fail.\t{0}", ex.Message));
}
Thread.Sleep(LicDefines.NET_HEARTBEAT_INTEVAL * 1000);
}
}
#endregion
#region Basic
private bool ServerValidation(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
if (certificate != null)
{
SubDebug("ServerValidation", string.Format("{0}", certificate.GetCertHashString()));
}
return true;
}
private void SubDebug(string category, string msg)
{
if (Debug != null)
{
Debug(mClient, string.Format("{0}\t{1}", category, msg));
}
}
private void SubMessageReceived(string msg)
{
if (MessageReceived != null)
{
MessageReceived(mClient, msg);
}
}
#endregion
}
[/code]