151120 TPL/async/await 정리

Edit
public partial class MainWindow : Window
{
    // . . .
    private async void startButton_Click(object sender, RoutedEventArgs e)
    {
        // ONE
        Task<int> getLengthTask = AccessTheWebAsync();

        // FOUR
        int contentLength = await getLengthTask;

        // SIX
        resultsTextBox.Text +=
            String.Format("\r\nLength of the downloaded string: {0}.\r\n", contentLength);
    }


    async Task<int> AccessTheWebAsync()
    {
        // TWO
        HttpClient client = new HttpClient();
        Task<string> getStringTask =
            client.GetStringAsync("http://msdn.microsoft.com");

        // THREE                 
        string urlContents = await getStringTask;

        // FIVE
        return urlContents.Length;
    }
}

비동기 작업의 취소

https://msdn.microsoft.com/ko-kr/library/jj155759.aspx
CancellationTokenSource
cts.Token
cts.Cancel();
cts = new CancellationTokenSource();

HttpResponseMessage response = await client.GetAsync("http://msdn.microsoft.com/en-us/library/dd470362.aspx", cts.Token);

cts.Cancel();

다수의 비동기 작업 모두 완료되면 다수의 값을 배열로 리턴

// Create a query.
IEnumerable<Task<int>> downloadTasksQuery = from url in urlList select ProcessURL(url, client);
Task<int>[] downloadTasks = downloadTasksQuery.ToArray();

// You can do other work here before awaiting.

// Await the completion of all the running tasks.
int[] lengths = await Task.WhenAll(downloadTasks);

다수의 비동기 작업중 한개가 완료되면 모두 취소하는 기능

https://msdn.microsoft.com/ko-kr/library/jj155758.aspx
CancellationToken 와 함께 Task.WhenAny 메서드를 사용
Task<int>[] downloadTasks = downloadTasksQuery.ToArray();
Task<int> firstFinishedTask = await Task.WhenAny(downloadTasks);

다수의 비동기 작업중 한개가 완료될때마다 처리

// ***Create a query that, when executed, returns a collection of tasks.
IEnumerable<Task<int>> downloadTasksQuery =
    from url in urlList select ProcessURL(url, client, ct);

// ***Use ToList to execute the query and start the tasks. 
List<Task<int>> downloadTasks = downloadTasksQuery.ToList();

// ***Add a loop to process the tasks one at a time until none remain.
while (downloadTasks.Count > 0)
{
    // Identify the first task that completes.
    Task<int> firstFinishedTask = await Task.WhenAny(downloadTasks);

    // ***Remove the selected task from the list so that you don't
    // process it more than once.
    downloadTasks.Remove(firstFinishedTask);    
}

C# http web server with TPL/async/await

서버메인클래스
클라이언트 접속처리
class Listener
{
    public readonly int Port;
    private readonly TcpListener _tcpListener;
    private readonly Task _listenTask;

    public Listener(int port)
    {
        Port = port;

        // Start listening
        _tcpListener = new TcpListener(IPAddress.Any, Port);
        _tcpListener.Start();

        // Start a background thread to listen for incoming
        _listenTask = Task.Factory.StartNew(() => ListenLoop());

    }

    private async void ListenLoop()
    {
        for (; ; )
        {
            // Wait for connection
            var socket = await _tcpListener.AcceptSocketAsync();
            if (socket == null)
                break;

            // Got new connection, create a client handler for it
            var client = new Client(socket);
            // Create a task to handle new connection
            Task.Factory.StartNew(client.Do);
        }
    }
}
서버에 접속한 클라이언트 처리
class Client
{
    private readonly Socket _socket;
    private readonly NetworkStream _networkStream;
    private readonly MemoryStream _memoryStream = new MemoryStream();
    private readonly StreamReader _streamReader;
    private readonly string _serverName = "Tedd.Demo.HttpServer";

    public Client(Socket socket)
    {
        _socket = socket;
        _networkStream = new NetworkStream(socket, true);
        _streamReader = new StreamReader(_memoryStream);
    }

    public async void Do()
    {
        // We are executed on a separate thread from listener, but will release this back to the threadpool as often as we can.
        byte[] buffer = new byte[4096];
        for (; ; )
        {
            // Read a chunk of data
            int bytesRead = await _networkStream.ReadAsync(buffer, 0, buffer.Length);

            // If Read returns with no data then the connection is closed.
            if (bytesRead == 0)
                return;

            // Write to buffer and process
            _memoryStream.Seek(0, SeekOrigin.End);
            _memoryStream.Write(buffer, 0, bytesRead);
            bool done = ProcessHeader();
            if (done)
                break;
        }

        }

    private bool ProcessHeader()
    {
        // Our task is to find when full HTTP header has been received, then send reply.
        for (; ; )
        {
            _memoryStream.Seek(0, SeekOrigin.Begin);
            var line = _streamReader.ReadLine();
            if (line == null)
                break;

            if (line.ToUpperInvariant().StartsWith("GET "))
            {
                // We got a request: GET /file HTTP/1.1
                var file = line.Split(' ')[1].TrimStart('/');
                // Default document is index.html
                if (string.IsNullOrWhiteSpace(file))
                    file = "index.html";
                // Send header+file
                SendFile(file);
                return true;
            }

        }
        return false;
        }

    private async void SendFile(string file)
    {
        // Get info and assemble header
        byte[] data;
        string responseCode = "";
        string contentType = "";
        try
        {
            if (File.Exists(file))
            {
                // Read file
                data = File.ReadAllBytes(file);
                contentType = GetContentType(Path.GetExtension(file).TrimStart(".".ToCharArray()));
                responseCode = "200 OK";
            }
            else
            {
                data = System.Text.Encoding.ASCII.GetBytes("<html><body><h1>404 File Not Found</h1></body></html>");
                contentType = GetContentType("html");
                responseCode = "404 Not found";
            }
        }
        catch (Exception exception)
        {
            // In case of error dump exception to client.
            data = System.Text.Encoding.ASCII.GetBytes("<html><body><h1>500 Internal server error</h1><pre>" + exception.ToString() + "</pre></body></html>");
            responseCode = "500 Internal server error";
        }

        string header = string.Format("HTTP/1.1 {0}\r\n"
                                      + "Server: {1}\r\n"
                                      + "Content-Length: {2}\r\n"
                                      + "Content-Type: {3}\r\n"
                                      + "Keep-Alive: Close\r\n"
                                      + "\r\n",
                                      responseCode, _serverName, data.Length, contentType);
        // Send header & data
        var headerBytes = System.Text.Encoding.ASCII.GetBytes(header)
        await _networkStream.WriteAsync(headerBytes, 0, headerBytes.Length);
        await _networkStream.WriteAsync(data, 0, data.Length);
        await _networkStream.FlushAsync();
        // Close connection (we don't support keep-alive)
        _networkStream.Dispose();
    }

    /// <summary>
    /// Get mime type from a file extension
    /// </summary>
    /// <param name="extension">File extension without starting dot (html, not .html)</param>
    /// <returns>Mime type or default mime type "application/octet-stream" if not found.</returns>
    private string GetContentType(string extension)
    {
        // We are accessing the registry with data received from third party, so we need to have a strict security test. We only allow letters and numbers.
        if (Regex.IsMatch(extension, "^[a-z0-9]+$", RegexOptions.IgnoreCase | RegexOptions.Compiled))
            return (Registry.GetValue(@"HKEY_CLASSES_ROOT\." + extension, "Content Type", null) as string) ?? "application/octet-stream";
        return "application/octet-stream";
    }
}
서버실행
class Program
{
    private static Listener listener;
    static void Main(string[] args)
    {
        listener = new Listener(8080);
        Console.WriteLine("Listening on port 8080 (http://localhost:8080/).");
        Console.WriteLine("Remember to put the files you want to serve in the output folder of the project.");
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
%23%20151120%20TPL/async/await%20%uC815%uB9AC%0A@%28%uD669%uD604%uB3D9%20%uB178%uD2B8%uBD81%29%5Bc%23%7C.net%7Cuwp%5D%0A%0A%5Btoc%5D%0A%0A---%0A%0A%21%5BAlt%20text%5D%28./1447997697536.png%29%0A%0A---%0A%0A%23%23%20%uBE44%uB3D9%uAE30%20%uBA54%uC18C%uB4DC%uC758%20%uD750%uB984%0Ahttps%3A//msdn.microsoft.com/ko-kr/library/hh873191.aspx%0A%0A%60%60%60c%23%0Apublic%20partial%20class%20MainWindow%20%3A%20Window%0A%7B%0A%20%20%20%20//%20.%20.%20.%0A%20%20%20%20private%20async%20void%20startButton_Click%28object%20sender%2C%20RoutedEventArgs%20e%29%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20//%20ONE%0A%20%20%20%20%20%20%20%20Task%3Cint%3E%20getLengthTask%20%3D%20AccessTheWebAsync%28%29%3B%0A%0A%20%20%20%20%20%20%20%20//%20FOUR%0A%20%20%20%20%20%20%20%20int%20contentLength%20%3D%20await%20getLengthTask%3B%0A%0A%20%20%20%20%20%20%20%20//%20SIX%0A%20%20%20%20%20%20%20%20resultsTextBox.Text%20+%3D%0A%20%20%20%20%20%20%20%20%20%20%20%20String.Format%28%22%5Cr%5CnLength%20of%20the%20downloaded%20string%3A%20%7B0%7D.%5Cr%5Cn%22%2C%20contentLength%29%3B%0A%20%20%20%20%7D%0A%0A%0A%20%20%20%20async%20Task%3Cint%3E%20AccessTheWebAsync%28%29%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20//%20TWO%0A%20%20%20%20%20%20%20%20HttpClient%20client%20%3D%20new%20HttpClient%28%29%3B%0A%20%20%20%20%20%20%20%20Task%3Cstring%3E%20getStringTask%20%3D%0A%20%20%20%20%20%20%20%20%20%20%20%20client.GetStringAsync%28%22http%3A//msdn.microsoft.com%22%29%3B%0A%0A%20%20%20%20%20%20%20%20//%20THREE%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20string%20urlContents%20%3D%20await%20getStringTask%3B%0A%0A%20%20%20%20%20%20%20%20//%20FIVE%0A%20%20%20%20%20%20%20%20return%20urlContents.Length%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A---%0A%0A%23%23%20%uBE44%uB3D9%uAE30%20%uC791%uC5C5%uC758%20%uCDE8%uC18C%0Ahttps%3A//msdn.microsoft.com/ko-kr/library/jj155759.aspx%0A%60CancellationTokenSource%60%0A%60cts.Token%60%0A%60cts.Cancel%28%29%3B%60%0A%0A%60%60%60c%23%0Acts%20%3D%20new%20CancellationTokenSource%28%29%3B%0A%0AHttpResponseMessage%20response%20%3D%20await%20client.GetAsync%28%22http%3A//msdn.microsoft.com/en-us/library/dd470362.aspx%22%2C%20cts.Token%29%3B%0A%0Acts.Cancel%28%29%3B%0A%60%60%60%0A%0A---%0A%0A%23%23%20%uB2E4%uC218%uC758%20%uBE44%uB3D9%uAE30%20%uC791%uC5C5%20%uBAA8%uB450%20%uC644%uB8CC%uB418%uBA74%20%uB2E4%uC218%uC758%20%uAC12%uC744%20%uBC30%uC5F4%uB85C%20%uB9AC%uD134%0Ahttps%3A//msdn.microsoft.com/ko-kr/library/hh556530.aspx%0A%60Task.WhenAll%60%0A%0A%60%60%60c%23%0A//%20Create%20a%20query.%0AIEnumerable%3CTask%3Cint%3E%3E%20downloadTasksQuery%20%3D%20from%20url%20in%20urlList%20select%20ProcessURL%28url%2C%20client%29%3B%0ATask%3Cint%3E%5B%5D%20downloadTasks%20%3D%20downloadTasksQuery.ToArray%28%29%3B%0A%0A//%20You%20can%20do%20other%20work%20here%20before%20awaiting.%0A%0A//%20Await%20the%20completion%20of%20all%20the%20running%20tasks.%0Aint%5B%5D%20lengths%20%3D%20await%20Task.WhenAll%28downloadTasks%29%3B%0A%60%60%60%0A%0A%0A---%0A%0A%23%23%20%uB2E4%uC218%uC758%20%uBE44%uB3D9%uAE30%20%uC791%uC5C5%uC911%20%uD55C%uAC1C%uAC00%20%uC644%uB8CC%uB418%uBA74%20%uBAA8%uB450%20%uCDE8%uC18C%uD558%uB294%20%uAE30%uB2A5%0Ahttps%3A//msdn.microsoft.com/ko-kr/library/jj155758.aspx%0A%60CancellationToken%20%uC640%20%uD568%uAED8%20Task.WhenAny%20%uBA54%uC11C%uB4DC%uB97C%20%uC0AC%uC6A9%60%0A%0A%60%60%60c%23%0ATask%3Cint%3E%5B%5D%20downloadTasks%20%3D%20downloadTasksQuery.ToArray%28%29%3B%0ATask%3Cint%3E%20firstFinishedTask%20%3D%20await%20Task.WhenAny%28downloadTasks%29%3B%0A%60%60%60%0A%0A---%0A%0A%23%23%20%uB2E4%uC218%uC758%20%uBE44%uB3D9%uAE30%20%uC791%uC5C5%uC911%20%uD55C%uAC1C%uAC00%20%uC644%uB8CC%uB420%uB54C%uB9C8%uB2E4%20%uCC98%uB9AC%0Ahttps%3A//msdn.microsoft.com/ko-kr/library/jj155756.aspx%0A%60Task.WhenAny%60%0A%0A%60%60%60c%23%0A//%20***Create%20a%20query%20that%2C%20when%20executed%2C%20returns%20a%20collection%20of%20tasks.%0AIEnumerable%3CTask%3Cint%3E%3E%20downloadTasksQuery%20%3D%0A%20%20%20%20from%20url%20in%20urlList%20select%20ProcessURL%28url%2C%20client%2C%20ct%29%3B%0A%0A//%20***Use%20ToList%20to%20execute%20the%20query%20and%20start%20the%20tasks.%20%0AList%3CTask%3Cint%3E%3E%20downloadTasks%20%3D%20downloadTasksQuery.ToList%28%29%3B%0A%0A//%20***Add%20a%20loop%20to%20process%20the%20tasks%20one%20at%20a%20time%20until%20none%20remain.%0Awhile%20%28downloadTasks.Count%20%3E%200%29%0A%7B%0A%09//%20Identify%20the%20first%20task%20that%20completes.%0A%09Task%3Cint%3E%20firstFinishedTask%20%3D%20await%20Task.WhenAny%28downloadTasks%29%3B%0A%09%0A%09//%20***Remove%20the%20selected%20task%20from%20the%20list%20so%20that%20you%20don%27t%0A%09//%20process%20it%20more%20than%20once.%0A%09downloadTasks.Remove%28firstFinishedTask%29%3B%09%0A%7D%0A%60%60%60%0A%0A---%0A%0A%23%23%20async/await%20best%20practice%0Ahttps%3A//msdn.microsoft.com/en-us/magazine/jj991977.aspx%0A%0A%0A---%0A%0A%23%23%20C%23%20http%20web%20server%20with%20TPL/async/await%20%0Ahttp%3A//blog.tedd.no/2012/07/28/asyncawait-http-server-in-c/%0A%0A%0A%3E%20%uC11C%uBC84%uBA54%uC778%uD074%uB798%uC2A4%0A%3E%20%uD074%uB77C%uC774%uC5B8%uD2B8%20%uC811%uC18D%uCC98%uB9AC%0A%60%60%60c%23%0Aclass%20Listener%0A%7B%0A%20%20%20%20public%20readonly%20int%20Port%3B%0A%20%20%20%20private%20readonly%20TcpListener%20_tcpListener%3B%0A%20%20%20%20private%20readonly%20Task%20_listenTask%3B%0A%0A%20%20%20%20public%20Listener%28int%20port%29%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20Port%20%3D%20port%3B%0A%0A%20%20%20%20%20%20%20%20//%20Start%20listening%0A%20%20%20%20%20%20%20%20_tcpListener%20%3D%20new%20TcpListener%28IPAddress.Any%2C%20Port%29%3B%0A%20%20%20%20%20%20%20%20_tcpListener.Start%28%29%3B%0A%0A%20%20%20%20%20%20%20%20//%20Start%20a%20background%20thread%20to%20listen%20for%20incoming%0A%20%20%20%20%20%20%20%20_listenTask%20%3D%20Task.Factory.StartNew%28%28%29%20%3D%3E%20ListenLoop%28%29%29%3B%0A%0A%20%20%20%20%7D%0A%0A%20%20%20%20private%20async%20void%20ListenLoop%28%29%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20for%20%28%3B%20%3B%20%29%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20//%20Wait%20for%20connection%0A%20%20%20%20%20%20%20%20%20%20%20%20var%20socket%20%3D%20await%20_tcpListener.AcceptSocketAsync%28%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20%28socket%20%3D%3D%20null%29%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20break%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20//%20Got%20new%20connection%2C%20create%20a%20client%20handler%20for%20it%0A%20%20%20%20%20%20%20%20%20%20%20%20var%20client%20%3D%20new%20Client%28socket%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20//%20Create%20a%20task%20to%20handle%20new%20connection%0A%20%20%20%20%20%20%20%20%20%20%20%20Task.Factory.StartNew%28client.Do%29%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%3E%20%uC11C%uBC84%uC5D0%20%uC811%uC18D%uD55C%20%uD074%uB77C%uC774%uC5B8%uD2B8%20%uCC98%uB9AC%0A%60%60%60c%23%0Aclass%20Client%0A%7B%0A%09private%20readonly%20Socket%20_socket%3B%0A%09private%20readonly%20NetworkStream%20_networkStream%3B%0A%09private%20readonly%20MemoryStream%20_memoryStream%20%3D%20new%20MemoryStream%28%29%3B%0A%09private%20readonly%20StreamReader%20_streamReader%3B%0A%09private%20readonly%20string%20_serverName%20%3D%20%22Tedd.Demo.HttpServer%22%3B%0A%09%09%0A%09public%20Client%28Socket%20socket%29%0A%09%7B%0A%09%09_socket%20%3D%20socket%3B%0A%09%09_networkStream%20%3D%20new%20NetworkStream%28socket%2C%20true%29%3B%0A%09%09_streamReader%20%3D%20new%20StreamReader%28_memoryStream%29%3B%0A%09%7D%0A%09%09%0A%09public%20async%20void%20Do%28%29%0A%09%7B%0A%09%09//%20We%20are%20executed%20on%20a%20separate%20thread%20from%20listener%2C%20but%20will%20release%20this%20back%20to%20the%20threadpool%20as%20often%20as%20we%20can.%0A%09%09byte%5B%5D%20buffer%20%3D%20new%20byte%5B4096%5D%3B%0A%09%09for%20%28%3B%20%3B%20%29%0A%09%09%7B%0A%09%09%20%20%20%20//%20Read%20a%20chunk%20of%20data%0A%09%09%20%20%20%20int%20bytesRead%20%3D%20await%20_networkStream.ReadAsync%28buffer%2C%200%2C%20buffer.Length%29%3B%0A%09%09%0A%09%09%20%20%20%20//%20If%20Read%20returns%20with%20no%20data%20then%20the%20connection%20is%20closed.%0A%09%09%20%20%20%20if%20%28bytesRead%20%3D%3D%200%29%0A%09%09%20%20%20%20%20%20%20%20return%3B%0A%09%09%0A%09%09%20%20%20%20//%20Write%20to%20buffer%20and%20process%0A%09%09%20%20%20%20_memoryStream.Seek%280%2C%20SeekOrigin.End%29%3B%0A%09%09%20%20%20%20_memoryStream.Write%28buffer%2C%200%2C%20bytesRead%29%3B%0A%09%09%20%20%20%20bool%20done%20%3D%20ProcessHeader%28%29%3B%0A%09%09%20%20%20%20if%20%28done%29%0A%09%09%20%20%20%20%20%20%20%20break%3B%0A%09%09%7D%0A%09%09%0A%09%09%7D%0A%09%09%0A%09private%20bool%20ProcessHeader%28%29%0A%09%7B%0A%09%09//%20Our%20task%20is%20to%20find%20when%20full%20HTTP%20header%20has%20been%20received%2C%20then%20send%20reply.%0A%09%09for%20%28%3B%20%3B%20%29%0A%09%09%7B%0A%09%09%20%20%20%20_memoryStream.Seek%280%2C%20SeekOrigin.Begin%29%3B%0A%09%09%20%20%20%20var%20line%20%3D%20_streamReader.ReadLine%28%29%3B%0A%09%09%20%20%20%20if%20%28line%20%3D%3D%20null%29%0A%09%09%20%20%20%20%20%20%20%20break%3B%0A%09%09%0A%09%09%20%20%20%20if%20%28line.ToUpperInvariant%28%29.StartsWith%28%22GET%20%22%29%29%0A%09%09%20%20%20%20%7B%0A%09%09%20%20%20%20%20%20%20%20//%20We%20got%20a%20request%3A%20GET%20/file%20HTTP/1.1%0A%09%09%20%20%20%20%20%20%20%20var%20file%20%3D%20line.Split%28%27%20%27%29%5B1%5D.TrimStart%28%27/%27%29%3B%0A%09%09%20%20%20%20%20%20%20%20//%20Default%20document%20is%20index.html%0A%09%09%20%20%20%20%20%20%20%20if%20%28string.IsNullOrWhiteSpace%28file%29%29%0A%09%09%20%20%20%20%20%20%20%20%20%20%20%20file%20%3D%20%22index.html%22%3B%0A%09%09%20%20%20%20%20%20%20%20//%20Send%20header+file%0A%09%09%20%20%20%20%20%20%20%20SendFile%28file%29%3B%0A%09%09%20%20%20%20%20%20%20%20return%20true%3B%0A%09%09%20%20%20%20%7D%0A%09%09%0A%09%09%7D%0A%09%09return%20false%3B%0A%09%09%7D%0A%09%09%0A%09private%20async%20void%20SendFile%28string%20file%29%0A%09%7B%0A%09%09//%20Get%20info%20and%20assemble%20header%0A%09%09byte%5B%5D%20data%3B%0A%09%09string%20responseCode%20%3D%20%22%22%3B%0A%09%09string%20contentType%20%3D%20%22%22%3B%0A%09%09try%0A%09%09%7B%0A%09%09%20%20%20%20if%20%28File.Exists%28file%29%29%0A%09%09%20%20%20%20%7B%0A%09%09%20%20%20%20%20%20%20%20//%20Read%20file%0A%09%09%20%20%20%20%20%20%20%20data%20%3D%20File.ReadAllBytes%28file%29%3B%0A%09%09%20%20%20%20%20%20%20%20contentType%20%3D%20GetContentType%28Path.GetExtension%28file%29.TrimStart%28%22.%22.ToCharArray%28%29%29%29%3B%0A%09%09%20%20%20%20%20%20%20%20responseCode%20%3D%20%22200%20OK%22%3B%0A%09%09%20%20%20%20%7D%0A%09%09%20%20%20%20else%0A%09%09%20%20%20%20%7B%0A%09%09%20%20%20%20%20%20%20%20data%20%3D%20System.Text.Encoding.ASCII.GetBytes%28%22%3Chtml%3E%3Cbody%3E%3Ch1%3E404%20File%20Not%20Found%3C/h1%3E%3C/body%3E%3C/html%3E%22%29%3B%0A%09%09%20%20%20%20%20%20%20%20contentType%20%3D%20GetContentType%28%22html%22%29%3B%0A%09%09%20%20%20%20%20%20%20%20responseCode%20%3D%20%22404%20Not%20found%22%3B%0A%09%09%20%20%20%20%7D%0A%09%09%7D%0A%09%09catch%20%28Exception%20exception%29%0A%09%09%7B%0A%09%09%20%20%20%20//%20In%20case%20of%20error%20dump%20exception%20to%20client.%0A%09%09%20%20%20%20data%20%3D%20System.Text.Encoding.ASCII.GetBytes%28%22%3Chtml%3E%3Cbody%3E%3Ch1%3E500%20Internal%20server%20error%3C/h1%3E%3Cpre%3E%22%20+%20exception.ToString%28%29%20+%20%22%3C/pre%3E%3C/body%3E%3C/html%3E%22%29%3B%0A%09%09%20%20%20%20responseCode%20%3D%20%22500%20Internal%20server%20error%22%3B%0A%09%09%7D%0A%09%09%0A%09%09string%20header%20%3D%20string.Format%28%22HTTP/1.1%20%7B0%7D%5Cr%5Cn%22%0A%09%09%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20+%20%22Server%3A%20%7B1%7D%5Cr%5Cn%22%0A%09%09%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20+%20%22Content-Length%3A%20%7B2%7D%5Cr%5Cn%22%0A%09%09%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20+%20%22Content-Type%3A%20%7B3%7D%5Cr%5Cn%22%0A%09%09%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20+%20%22Keep-Alive%3A%20Close%5Cr%5Cn%22%0A%09%09%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20+%20%22%5Cr%5Cn%22%2C%0A%09%09%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20responseCode%2C%20_serverName%2C%20data.Length%2C%20contentType%29%3B%0A%09%09//%20Send%20header%20%26%20data%0A%09%09var%20headerBytes%20%3D%20System.Text.Encoding.ASCII.GetBytes%28header%29%0A%09%09await%20_networkStream.WriteAsync%28headerBytes%2C%200%2C%20headerBytes.Length%29%3B%0A%09%09await%20_networkStream.WriteAsync%28data%2C%200%2C%20data.Length%29%3B%0A%09%09await%20_networkStream.FlushAsync%28%29%3B%0A%09%09//%20Close%20connection%20%28we%20don%27t%20support%20keep-alive%29%0A%09%09_networkStream.Dispose%28%29%3B%0A%09%7D%0A%0A%09///%20%3Csummary%3E%0A%09///%20Get%20mime%20type%20from%20a%20file%20extension%0A%09///%20%3C/summary%3E%0A%09///%20%3Cparam%20name%3D%22extension%22%3EFile%20extension%20without%20starting%20dot%20%28html%2C%20not%20.html%29%3C/param%3E%0A%09///%20%3Creturns%3EMime%20type%20or%20default%20mime%20type%20%22application/octet-stream%22%20if%20not%20found.%3C/returns%3E%0A%09private%20string%20GetContentType%28string%20extension%29%0A%09%7B%0A%09%09//%20We%20are%20accessing%20the%20registry%20with%20data%20received%20from%20third%20party%2C%20so%20we%20need%20to%20have%20a%20strict%20security%20test.%20We%20only%20allow%20letters%20and%20numbers.%0A%09%09if%20%28Regex.IsMatch%28extension%2C%20%22%5E%5Ba-z0-9%5D+%24%22%2C%20RegexOptions.IgnoreCase%20%7C%20RegexOptions.Compiled%29%29%0A%09%09%20%20%20%20return%20%28Registry.GetValue%28@%22HKEY_CLASSES_ROOT%5C.%22%20+%20extension%2C%20%22Content%20Type%22%2C%20null%29%20as%20string%29%20%3F%3F%20%22application/octet-stream%22%3B%0A%09%09return%20%22application/octet-stream%22%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%3E%20%uC11C%uBC84%uC2E4%uD589%0A%0A%60%60%60c%23%0Aclass%20Program%0A%7B%0A%20%20%20%20private%20static%20Listener%20listener%3B%0A%20%20%20%20static%20void%20Main%28string%5B%5D%20args%29%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20listener%20%3D%20new%20Listener%288080%29%3B%0A%20%20%20%20%20%20%20%20Console.WriteLine%28%22Listening%20on%20port%208080%20%28http%3A//localhost%3A8080/%29.%22%29%3B%0A%20%20%20%20%20%20%20%20Console.WriteLine%28%22Remember%20to%20put%20the%20files%20you%20want%20to%20serve%20in%20the%20output%20folder%20of%20the%20project.%22%29%3B%0A%20%20%20%20%20%20%20%20Console.WriteLine%28%22Press%20any%20key%20to%20exit.%22%29%3B%0A%20%20%20%20%20%20%20%20Console.ReadKey%28%29%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60

이 글은 Evernote에서 작성되었습니다. Evernote는 하나의 업무 공간입니다. Evernote를 다운로드하세요.

댓글