// '' <summary> // '' Sends the http response to the client and closes the connection using a separate thread. // '' </summary> // '' <param name="ar"></param> // '' <remarks></remarks> private void SendResponseAsync(IAsyncResult ar) { AsyncSendState asyncState = ((AsyncSendState)(ar.AsyncState)); try { asyncState.Socket.EndSend(ar); // disconnect the client if not keep-alive: if (asyncState.Persistent) { // asyncState.Socket.Disconnect(True) } DebugMessage("Sent " + asyncState.Tag + " to " + asyncState.Socket.RemoteEndPoint.ToString() + ".", DebugMessageType.UsageMessage, "SendAsync"); } catch (Exception ex) { // UNDONE: this DebugMessage() didn't used to trigger errors, but now it does... // DebugMessage("Failed to send " & asyncState.Tag & " to " & asyncState.Socket.RemoteEndPoint.ToString & ". The exception was: " & ex.Message, DebugMessageType.UsageMessage, "SendAsync") DebugMessage("SendResponseAsync encountered an exception when trying to send data to the client.", DebugMessageType.ErrorMessage, "SendResponseAsync", ex.Message); } // finally terminate the socket after allowing pending transmissions to complete. this eliminates ERR_CONNECTION_RESET that would happen occasionally on random resources: if (asyncState.Persistent) { // TODO: we check Persistent attribute twice in this method...if we put Close below Disconnect it will throw the exception that we can't access the socket because it is disposed // asyncState.Socket.Close() // update the connected client count in a thread safe way // Threading.Interlocked.Decrement(Me.ConnectedClients) // RaiseEvent ClientDisconnected(asyncState.Socket) } }
public void Add(AsyncSendState argState) { this.Messages.Enqueue(argState); if (MessageQueued != null) { MessageQueued(); } }
private void AsyncClientConnected(IAsyncResult ar) { // get the async state object returned by the callback AsyncSendState asyncState = ((AsyncSendState)(ar.AsyncState)); object state = asyncState.State; // end the async connection request so we can check if we are connected to the server bool connectSuccessful = false; try { // call the EndConnect method which will succeed or throw an error depending on the result of the connection asyncState.Socket.EndConnect(ar); // at this point, the EndConnect succeeded and we are connected to the server! handle the success outside this Try block. connectSuccessful = true; ConnectSucceeded(state, null); } catch (Exception ex) { // at this point, the EndConnect failed and we are NOT connected to the server! DebugMessage("Could not connect to the server.", DebugMessageType.ErrorMessage, "Connect", ex.Message); ConnectFailed(state, null); } // if the client has connected, proceed if (connectSuccessful) { // start waiting for messages from the server AsyncReceiveState receiveState = new AsyncReceiveState(ReceiveBufferSize, state); receiveState.Socket = asyncState.Socket; receiveState.Socket.BeginReceive(receiveState.Buffer, 0, ReceiveBufferSize, SocketFlags.None, new AsyncCallback(DataReceived), receiveState); // make a request to the server AsyncSendState sendState = new AsyncSendState(asyncState.Socket, SendBufferSize, state); // if the path is a directory, ensure it has a trailing / // If IO.Path.GetExtension(_request) = "" Then // If _request.EndsWith("/") = False Then // _request &= "/" // End If // End If // construct the GET request string and byte array: // NOTE: node.js requires two vbCrLf terminator where other servers only require one. IIS 7.5 requires HTTP/1.1 and Host // header or will not return headers with the response. string reqString = ""; byte[] reqBytes = null; reqString = ("GET " + (_req.Path + (" HTTP/1.1" + ('\n' + ("Host: " + (_req.Host + ('\n' + '\n'))))))); reqBytes = System.Text.Encoding.ASCII.GetBytes(reqString); // send the reqBytes data to the server LogMessage(reqString, null); sendState.Socket.BeginSend(reqBytes, 0, reqBytes.Length, SocketFlags.None, new AsyncCallback(DataSent), sendState); } }
private void DataSent(IAsyncResult ar) { // get the async state object returned by the callback AsyncSendState asyncState = ((AsyncSendState)(ar.AsyncState)); try { asyncState.Socket.EndSend(ar); } catch (Exception ex) { Console.WriteLine(("DataSent exception: " + ex.Message)); } }
// sends the http response to the client private void SendResponse(Request req, Response res, Socket client) { // convert the response into bytes and package it in an async object for callback purposes: // Dim responseBytes() As Byte = res.BuildResponseBytes AsyncSendState sendState = new AsyncSendState(client, SendBufferSize, null); sendState.BytesToSend = res.ResponseBytes; sendState.Tag = req.AbsPath; // start sending the response to the client in an async fashion: try { client.BeginSend(res.ResponseBytes, 0, res.ResponseBytes.Length, SocketFlags.None, SendResponseAsync, sendState); } catch (Exception ex) { DebugMessage("Unhandled exception in SendResponse when trying to send data to the client.", DebugMessageType.UsageMessage, "SendResponse", ex.Message); } // determine whether or not to continue receiving more data from the client: // TODO: tidy this up a bit instead of setting a property to true then checking it right afterwards... // IMPORTANT: for keep-alive connections we should make a final receive call to the client and if the client does not send a Connection: keep-alive header then we know to disconnect if (res.Headers.ContainsKey("Connection") && res.Headers["Connection"].ToString().ToLower() == "keep-alive") { sendState.Persistent = true; } // start receiving more data from the client in an async fashion if (sendState.Persistent) { AsyncReceiveState receiveState = new AsyncReceiveState(ReceiveBufferSize, null); receiveState.Site = req.Site; receiveState.Socket = client; try { receiveState.Socket.BeginReceive(receiveState.Buffer, 0, ReceiveBufferSize, SocketFlags.None, new AsyncCallback(RequestReceivedAsync), receiveState); } catch (Exception ex) { DebugMessage(("SendResponse encountered an exception when trying to BeginReceive on the client socket. " + ex.Message), DebugMessageType.ErrorMessage, "ClientRequest", ex.Message); } } }
public void Add(AsyncSendState argState) { Messages.Enqueue(argState); MessageQueued?.Invoke(); }