/// <summary> /// We can read a string from the StringSocket by doing /// /// ss.BeginReceive(callback, payload) /// /// where callback is a ReceiveCallback (see below) and payload is an arbitrary object. /// This is non-blocking, asynchronous operation. When the StringSocket has read a /// string of text terminated by a newline character from the underlying Socket, or /// failed in the attempt, it invokes the callback. The parameters to the callback are /// a (possibly null) string, a (possibly null) Exception, and the payload. Either the /// string or the Exception will be non-null, but nor both. If the string is non-null, /// it is the requested string (with the newline removed). If the Exception is non-null, /// it is the Exception that caused the send attempt to fail. /// /// This method is non-blocking. This means that it does not wait until a line of text /// has been received before returning. Instead, it arranges for a line to be received /// and then returns. When the line is actually received (at some time in the future), the /// callback is called on another thread. /// /// This method is thread safe. This means that multiple threads can call BeginReceive /// on a shared socket without worrying around synchronization. The implementation of /// BeginReceive must take care of synchronization instead. On a given StringSocket, each /// arriving line of text must be passed to callbacks in the order in which the corresponding /// BeginReceive call arrived. /// /// Note that it is possible for there to be incoming bytes arriving at the underlying Socket /// even when there are no pending callbacks. StringSocket implementations should refrain /// from buffering an unbounded number of incoming bytes beyond what is required to service /// the pending callbacks. /// /// <param name="callback"> The function to call upon receiving the data</param> /// <param name="payload"> /// The payload is "remembered" so that when the callback is invoked, it can be associated /// with a specific Begin Receiver.... /// </param> /// /// <example> /// Here is how you might use this code: /// <code> /// client = new TcpClient("localhost", port); /// Socket clientSocket = client.Client; /// StringSocket receiveSocket = new StringSocket(clientSocket, new UTF8Encoding()); /// receiveSocket.BeginReceive(CompletedReceive1, 1); /// /// </code> /// </example> /// </summary> public void BeginReceive(ReceiveCallback callback, object payload) { // Store the receive request, with its specified callback and payload. ReceiveRequest receiveRequest = new ReceiveRequest(callback, payload); ReceiveQueue.Enqueue(receiveRequest); // Ask the socket to call MessageReceive as soon as up to 1024 bytes arrive. byte[] buffer = new byte[1024];//this should work when this is set to a small number socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, MessageReceived, buffer); }
/// <summary> /// We can read a string from the StringSocket by doing /// /// ss.BeginReceive(callback, payload) /// /// where callback is a ReceiveCallback (see below) and payload is an arbitrary object. /// This is non-blocking, asynchronous operation. When the StringSocket has read a /// string of text terminated by a newline character from the underlying Socket, or /// failed in the attempt, it invokes the callback. The parameters to the callback are /// a (possibly null) string, a (possibly null) Exception, and the payload. Either the /// string or the Exception will be non-null, but nor both. If the string is non-null, /// it is the requested string (with the newline removed). If the Exception is non-null, /// it is the Exception that caused the send attempt to fail. /// /// This method is non-blocking. This means that it does not wait until a line of text /// has been received before returning. Instead, it arranges for a line to be received /// and then returns. When the line is actually received (at some time in the future), the /// callback is called on another thread. /// /// This method is thread safe. This means that multiple threads can call BeginReceive /// on a shared socket without worrying around synchronization. The implementation of /// BeginReceive must take care of synchronization instead. On a given StringSocket, each /// arriving line of text must be passed to callbacks in the order in which the corresponding /// BeginReceive call arrived. /// /// Note that it is possible for there to be incoming bytes arriving at the underlying Socket /// even when there are no pending callbacks. StringSocket implementations should refrain /// from buffering an unbounded number of incoming bytes beyond what is required to service /// the pending callbacks. /// /// <param name="callback"> The function to call upon receiving the data</param> /// <param name="payload"> /// The payload is "remembered" so that when the callback is invoked, it can be associated /// with a specific Begin Receiver.... /// </param> /// /// <example> /// Here is how you might use this code: /// <code> /// client = new TcpClient("localhost", port); /// Socket clientSocket = client.Client; /// StringSocket receiveSocket = new StringSocket(clientSocket, new UTF8Encoding()); /// receiveSocket.BeginReceive(CompletedReceive1, 1); /// /// </code> /// </example> /// </summary> public void BeginReceive(ReceiveCallback callback, object payload) { // Protect the ReceiveQueue lock (ReceiveQueue) { // Create and store the receive request. ReceiveRequest receiveRequest = new ReceiveRequest(callback, payload); ReceiveQueue.Enqueue(receiveRequest); // If there is no receive ongoing, start receiving. if (ReceiveQueue.Count == 1) { ProcessReceivedMessage(); } } }
/// <summary> /// This private method is the callback for the receive attempts. /// </summary> private void BytesReceived(IAsyncResult ar) { // Get the number of bytes received. int count; try { count = socket.EndReceive(ar); } catch (Exception e) { ReceiveRequest req = receiveRequests.Dequeue(); ThreadPool.QueueUserWorkItem(x => req.Callback(null, e, req.Payload)); ProcessReceiveQueue(); incompleteLine = ""; return; } // If no bytes were received, this means that the remote socket has // shut down. Send a null to the callback to signal this. if (count == 0) { receivedLines.Enqueue(null); ProcessReceiveQueue(); } // If bytes were received, save them. else { //incompleteLine += encoding.GetString(receiveBytes, 0, count); int charsRead = decoder.GetChars(receiveBytes, 0, count, receiveChars, 0, false); incompleteLine += new String(receiveChars, 0, charsRead); // Extract all complete lines of text and put into the ReceivedLines queue int lineEnd, lineStart = 0; while ((lineEnd = incompleteLine.IndexOf('\n', lineStart)) >= 0) { receivedLines.Enqueue(incompleteLine.Substring(lineStart, lineEnd - lineStart)); lineStart = lineEnd + 1; } incompleteLine = incompleteLine.Substring(lineStart); // Try to fill requests with the new data ProcessReceiveQueue(); } }