コード例 #1
0
ファイル: SocketListener.cs プロジェクト: ststeiger/NancyHub
        private void Work()
        {
            byte[] buffer            = new byte[8192];
            int    selectMaximumTime = -1;

            while (true)
            {
                try
                {
                    // ReadSet: We want Select to return when either a new connection has arrived or when there is incoming socket data
                    List <Socket> socketsReadSet = OpenSockets.Keys.ToList();
                    if (tcpListenSocket != null && tcpListenSocket.IsBound)
                    {
                        socketsReadSet.Add(tcpListenSocket);
                    }
                    if (unixListenSocket != null && unixListenSocket.IsBound)
                    {
                        socketsReadSet.Add(unixListenSocket);
                    }

                    Socket.Select(socketsReadSet, null, null, selectMaximumTime);

                    foreach (Socket sock in socketsReadSet)
                    {
                        // In case this sock is in the read set just because a connection has been accepted,
                        // it must be a listen socket and we should accept the new queued connections
                        if (sock == tcpListenSocket || sock == unixListenSocket)
                        {
                            BeginAcceptNewConnections(sock);
                            continue;
                        }

                        // Get some data on the socket
                        FosRequest fosRequest;
                        if (!OpenSockets.TryGetValue(sock, out fosRequest))
                        {
                            // On socket shutdown we may find a socket returned by Select that has already been removed
                            // from OpenSockets from a normal connection closing
                            continue;
                        }

                        // Read data. The socket could have been disposed here.
                        // We need to remove it from our internal bookkeeping if that's the case.
                        int bytesRead;
                        try
                        {
                            bytesRead = sock.Receive(buffer, SocketFlags.None);
                        }
                        catch (ObjectDisposedException)
                        {
                            // This can happen if the application closed the socket but this loop
                            // still had time to find the request in OpenSockets before it got removed.
                            //TODO: This can also mean the socket was closed by the other side, so we need a way to differentiate them
                            continue;
                        }
                        catch (SocketException e)
                        {
                            if (SocketHelper.IsConnectionAbortedByTheOtherSide(e))
                            {
                                OnAbruptSocketClose(sock, fosRequest);
                                continue;
                            }
                            else if (e.SocketErrorCode == SocketError.Shutdown)
                            {
                                // Similar to the ObjectDisposedException above, but we tried to call Receive
                                // after the socket had been closed but still not marked as disposed (this should be rare)
                                // Give it another chance in the loop
                                continue;
                            }
                            else
                            {
                                throw;
                            }
                        }

                        if (bytesRead == 0)
                        {
                            // This could indicate both a socket closed prematurely or
                            // still the fact that the application closed the socket correctly and we received a bogus
                            // amount of bytes read (it seems to be possible, at least with Mono). So:
                            // If it was closed by the application it will be removed from OpenSockets
                            // If it was closed prematurely by the webserver it will throw an error next time
                            continue;
                        }

                        // Feed the request's record factory
                        // An exception thrown here means an implementer did not catch the application's exception. It is indeed a server error.
                        try
                        {
                            foreach (var rec in fosRequest.FeedBytes(buffer, 0, bytesRead))
                            {
                                OnRecordBuilt(fosRequest, rec);
                            }
                        }
                        catch (Exception e)
                        {
                            // Log and end request
                            if (Logger != null)
                            {
                                Logger.LogServerError(e, "The server did not handle an exception thrown by the application");
                            }

                            fosRequest.Dispose();
                            continue;
                        }
                    }
                }
                catch (Exception e)
                {
                    if (Logger != null)
                    {
                        Logger.LogServerError(e, "Exception would end the data receiving loop. This is extremely bad. Please file a bug report.");
                    }
                }
            }
        }