public NewPayLoad SendRequest(NewPayLoad payload) { // get stuck when Ginger close while (mProcessingStatus != eProcessingStatus.Ready && mProcessingStatus != eProcessingStatus.ResponseCompleted) { Thread.Sleep(1); //TODO: add timeout!!! or?? } OutgoingRequetsesCounter++; mRequestProcessingDone.Reset(); mSendDone.Reset(); Response = null; mProcessingStatus = eProcessingStatus.SendingRequest; byte[] b = payload.GetPackage(); // This is where the actual Payload bytes start being sent mSocket.BeginSend(b, 0, b.Length, SocketFlags.None, SendCallback, this); bytesOut += b.Length; mProcessingStatus = eProcessingStatus.WaitingForResponse; mSendDone.WaitOne(); // blocking until send completed bool bOK = mRequestProcessingDone.WaitOne(ResponseTimeoutMS); // wait for response - blocking if (!bOK) { throw new Exception("Timeout waiting for response, Payload-" + payload.Name); } mProcessingStatus = eProcessingStatus.ResponseCompleted; mSocket.Blocking = false; return(Response); }
// Each time new data arrive we get callback private void ReceiveCallback(IAsyncResult ar) { Console.WriteLine("ReceiveCallback"); while (mProcessingStatus == eProcessingStatus.SendingRequest) { Thread.Sleep(1); } try { // Retrieve the state object and the socket // from the asynchronous state object. GingerSocketInfo gingerSocketInfo = (GingerSocketInfo)ar.AsyncState; Socket socket = gingerSocketInfo.Socket; // Read data from the socket int bytesRead = socket.EndReceive(ar); BytesIn += bytesRead; if (bytesRead > 0) { if (gingerSocketInfo.BufferPOS == 0) // do only once per Payload { //TODO: There might be more data, so store the data received so far - need to veruf completion, create TC !! byte[] rcvLenBytesBB = gingerSocketInfo.buffer; // TODO: !!!!!!!!!!!!!temp do work direct - avoid creating a new byte array PayloadLen = ((rcvLenBytesBB[0]) << 24) + (rcvLenBytesBB[1] << 16) + (rcvLenBytesBB[2] << 8) + rcvLenBytesBB[3]; if (PayloadLen > gingerSocketInfo.buffer.Length) { Array.Resize(ref gingerSocketInfo.buffer, PayloadLen + 4); // Make sure we will have enough space // Add 1024 !!! // TODO: check if buffer is more than x size release it back.... } } gingerSocketInfo.BufferPOS += bytesRead; if (gingerSocketInfo.BufferPOS == PayloadLen + 4) { NewPayLoad Resp = new NewPayLoad(gingerSocketInfo.buffer, true); // We got the full packet, convert to Payload and process if (Resp.PaylodType == NewPayLoad.ePaylodType.ResponsePayload || Resp.PaylodType == NewPayLoad.ePaylodType.SocketResponse) { mProcessingStatus = eProcessingStatus.ResponseStarted; // Create new Payload from the buffer, ignoring the extra space at the end Response = new NewPayLoad(gingerSocketInfo.buffer, true); mProcessingStatus = eProcessingStatus.ResponseCompleted; // we are done with pair of Req/Resp - good job - mission completed // signal receive is complete so ready for processing mRequestProcessingDone.Set(); // !!! } else // this is new request, we need to process and respond { IncomingRequetsesCounter++; mProcessingStatus = eProcessingStatus.ProcessingRequest; // This is a request need to respond switch (Resp.PaylodType) { case NewPayLoad.ePaylodType.RequestPayload: MessageHandler(gingerSocketInfo); gingerSocketInfo.Response.PaylodType = NewPayLoad.ePaylodType.ResponsePayload; break; case NewPayLoad.ePaylodType.SocketRequest: SocketRequestHandler(gingerSocketInfo); break; default: throw new Exception("Unknown Payload Type, Payload.Name: " + Resp.Name); } mProcessingStatus = eProcessingStatus.SendingResponse; byte[] bb = gingerSocketInfo.Response.GetPackage(); bytesOut += bb.Length; mSocket.BeginSend(bb, 0, bb.Length, SocketFlags.None, SendCallback, this); mSendDone.WaitOne(); } gingerSocketInfo.BufferPOS = 0; // be ready to accept more new request or incoming data socket.BeginReceive(gingerSocketInfo.buffer, 0, gingerSocketInfo.buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), gingerSocketInfo); mProcessingStatus = eProcessingStatus.Ready; } else { // we got a big package more than 1024, starting collecting the bytes until all received socket.BeginReceive(gingerSocketInfo.buffer, gingerSocketInfo.BufferPOS, gingerSocketInfo.buffer.Length - gingerSocketInfo.BufferPOS, SocketFlags.None, new AsyncCallback(ReceiveCallback), gingerSocketInfo); } } else { // All the data has arrived; put it in response. // ???????????????????????????????????????????????????????????????????? // Signal that all bytes have been received. mRequestProcessingDone.Set(); //move up like server ??? } } catch (SocketException e) { if (e.SocketErrorCode == SocketError.ConnectionReset) { Console.WriteLine("SocketException: " + e.Message); //TODO: raise event // other side closed connection - mark socket as dead TODO !!!!!!!!!!!!!!!!!!!!!!! return; } throw e; } catch (Exception ex) { throw ex; } }