سلسلة net. للمحترفين ضبط الخوادم والتعامل مع الطلبيات في dot Net


رضوى العربي

خادم HTTP

إنشاء خادم HTTP باستخدام الصنف HttpListener

يُستخدَم النوع HttpListener لإنشاء مُستمِع (listener) مُبسط للرد على طلبات HTTP. نُنشِئ نسخة من هذا النوع كالتالي:

listener = new HttpListener();

تُستخدَم الخاصية Prefixes لتخصيص الرابط (url) الذي يَستمِع إليه الخادم والذي ستُرسَل إليه طلبات الـ HTTP.

listener.Prefixes.Add("http://*:" + port + "/");
listener.Start();

عندما يَستلِم الخادم طَلَبًا (http request) مُعينًا، فإنه بالضرورة يحتاج إلى معلومات عن الطلب حتى يقوم بمُعالجته. تَتوَفر تلك المعلومات من خلال التابع GetContext()‎.

var context = listener.GetContext();

var request = context.Request;
response = context.Response;

نظرًا لأن الهدف من خادم الملفات هو إرسال الملفات عند طلبها، سيقوم الخادم أولًا بتحديد اسم الملف المطلوب:

var fileName = request.RawUrl.Substring(1);

ثم يُرسِل مُحتويات الملف إلى مَجْرى مَتْن الرد (response body) كالتالي:

using (var fileStream = File.OpenRead(fullFilePath))
{
    response.ContentType = "application/octet-stream";
    response.ContentLength64 = (new FileInfo(fullFilePath)).Length;
    response.AddHeader("Content-Disposition",
                       "Attachment; filename=\"" + Path.GetFileName(fullFilePath) + "\"");
    fileStream.CopyTo(response.OutputStream);
}

response.OutputStream.Close();

المثال بالكامل:

using System;
using System.IO;
using System.Net;

class HttpFileServer
{
    private static HttpListenerResponse response;
    private static HttpListener listener;
    private static string baseFilesystemPath;

    static void Main(string[] args)
    {
        if (!HttpListener.IsSupported)
        {
            Console.WriteLine(
                "*** HttpListener requires at least Windows XP SP2 or Windows Server 2003.");
            return;
        }
        if(args.Length < 2)
        {
            Console.WriteLine("Basic read-only HTTP file server");
            Console.WriteLine();
            Console.WriteLine("Usage: httpfileserver <base filesystem path> <port>");
            Console.WriteLine("Request format: http://url:port/path/to/file.ext");
            return;
        }
        baseFilesystemPath = Path.GetFullPath(args[0]);

        var port = int.Parse(args[1]);

        listener = new HttpListener();
        listener.Prefixes.Add("http://*:" + port + "/");
        listener.Start();

        Console.WriteLine("--- Server stated, base path is: " + baseFilesystemPath);
        Console.WriteLine("--- Listening, exit with Ctrl-C");

        try
        {
            ServerLoop();
        }
        catch(Exception ex)
        {
            Console.WriteLine(ex);
            if(response != null)
            {
                SendErrorResponse(500, "Internal server error");
            }
        }
    }

    static void ServerLoop()
    {
        while(true)
        {
            var context = listener.GetContext();
            var request = context.Request;

            response = context.Response;

            var fileName = request.RawUrl.Substring(1);
            Console.WriteLine("--- Got {0} request for: {1}", request.HttpMethod, fileName);
            if (request.HttpMethod.ToUpper() != "GET")
            {
                SendErrorResponse(405, "Method must be GET");
                continue;
            }

            var fullFilePath = Path.Combine(baseFilesystemPath, fileName);
            if(!File.Exists(fullFilePath))
            {
                SendErrorResponse(404, "File not found");
                continue;
            }

            Console.Write(" Sending file...");

            using (var fileStream = File.OpenRead(fullFilePath))
            {
                response.ContentType = "application/octet-stream";
                response.ContentLength64 = (new FileInfo(fullFilePath)).Length;
                response.AddHeader("Content-Disposition",
                                   "Attachment; filename=\"" + Path.GetFileName(fullFilePath) + "\"");
                fileStream.CopyTo(response.OutputStream);
            }

            response.OutputStream.Close();
            response = null;

            Console.WriteLine("Ok!");
        }
    }

    static void SendErrorResponse(int statusCode, string statusResponse)
    {
        response.ContentLength64 = 0;
        response.StatusCode = statusCode;
        response.StatusDescription = statusResponse;
        response.OutputStream.Close();
        Console.WriteLine("*** Sent error: {0} {1}", statusCode, statusResponse);
    }
}

إنشاء خادم HTTP باستخدام ASP.NET Core

بالمثل، نُنشِئ خادم ببروتوكول HTTP لقراءة الملفات (file server) مُشابه للمثال بالأعلى لكن باستخدام بيئة عمل ASP.NET Core المتطورة.

أولًا: اِنشِئ مجلد فارغ، سنُضيف إليه ملفات المشروع المُنشئة خلال الخطوات التالية.

ثانيًا: اِنشِئ ملف باسم project.json وأَضِف إليه المحتويات التالية:

{
    "dependencies": {
        "Microsoft.AspNet.Server.Kestrel": "1.0.0-rc1-final",
        "Microsoft.AspNet.StaticFiles": "1.0.0-rc1-final"
    },
    "commands": {
        "web": "Microsoft.AspNet.Server.Kestrel --server.urls http://localhost:60000"
    },
    "frameworks": {
        "dnxcore50": { }
    },
    "fileServer": {
        "rootDirectory": "c:\\users\\username\\Documents"
    }
}

ثالثًا: اِنشِئ ملف باسم Startup.cs وأضف إليه الشيفرة التالية:

using System;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.FileProviders;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.StaticFiles;
using Microsoft.Extensions.Configuration;

public class Startup
{
    public void Configure(IApplicationBuilder app)
    {
        var builder = new ConfigurationBuilder();
        builder.AddJsonFile("project.json");

        var config = builder.Build();
        var rootDirectory = config["fileServer:rootDirectory"];

        Console.WriteLine("File server root directory: " + rootDirectory);

        var fileProvider = new PhysicalFileProvider(rootDirectory);

        var options = new StaticFileOptions();
        options.ServeUnknownFileTypes = true;
        options.FileProvider = fileProvider;
        options.OnPrepareResponse = context =>
        {
            context.Context.Response.ContentType = "application/octet-stream";
            context.Context.Response.Headers.Add(
                "Content-Disposition",
                $"Attachment; filename=\"{context.File.Name}\"");
        };

        app.UseStaticFiles(options);
    }
}

لاحظ اِستخدَام التابع UseStaticFiles لتزويد الخادم بخاصية قراءة الملفات الساكنة من مجلد معين.

رابعًا: اِفتَح سطر الأوامر (command prompt) في المجلد الذي قُمت لتوك بإنشائه، ونفذ الأوامر التالية:

dnvm use 1.0.0-rc1-final -r coreclr -p
dnu restore

تُنْفَّذ الأوامر بالأعلى مرة واحدة فقط.

خامسًا: شَغِّل الخادم باستخدَام الأمر dnx web. كلمة web هنا هي مُجرد كلمة مُخصَّصة ضِمْن حَقْل الأوامر commands بالملف project.json وتُستخدَم اسمًا تعريفيًا لأمر مُخصَّص، وبالتالي ما يُنْفَّذ بالفعل هو قيمة هذا الحقل بالملف.

`Microsoft.AspNet.Server.Kestrel --server.urls http://localhost:60000

والآن تستطيع إرسال طلبات (requests) إلى الخادم من خلال الرابط http://localhost:60000 وهو نفس الرابط (url) المُخصَّص بالأعلى.

لاحظ أننا لغرض التبسيط قد افترضنا أن أسماء جميع الملفات ستكون بترميز ASCII، بالإضافة إلى أننا لم نُعالِج الأخطاء المُحتمَلة أثناء الولوج للملفات.

عميل HTTP

يَتوَفر الصنف HttpClient من خلال حزمة مكتبات مايكروسوفت Microsoft HTTP Client Libraries.

إرسال طلب GET باستخدام HttpClient.GetAsync

يُرسِل التابع GetAsync طلب GET إلى خَادِم (server) عن طريق رابط يُمرَّر إليه كمُعامِل، ويُعيد قيمة من النوع Task<HttpResponseMessage>‎ تُمثِل رد الخادم (response). يُمكن قراءة الرد كـسِلسِلة نصية string باستخدام التابع response.Content.ReadAsStringAsync، كالمثال التالي:

string requestUri = "http://www.example.com";
string responseData;

using (var client = new HttpClient())
{
    using(var response = client.GetAsync(requestUri).Result)
    {
        response.EnsureSuccessStatusCode();
        responseData = response.Content.ReadAsStringAsync().Result;
    }
}

إرسال طلب GET باستخدام HttpClient.GetStreamAsync

يُرسِل التابع HttpClient.GetStreamAsync طلب GET إلى خَادِم (server) عن طريق رابط يُمرَّر إليه كمُعامِل، ولكنه يُعيد مَتْن الرد (response body) في صورة مَجْرى (stream).

private static async Task DownloadAsync(string fromUrl, string toFile)
{
    using (var fileStream = File.OpenWrite(toFile))
    {
        using (var httpClient = new HttpClient())
        {
            Console.WriteLine("Connecting...");
            using (var networkStream = await httpClient.GetStreamAsync(fromUrl))
            {
                Console.WriteLine("Downloading...");
                await networkStream.CopyToAsync(fileStream);
                await fileStream.FlushAsync();
            }
        }
    }   
}

يُمكن استدعاء الدالة المُعرَّفة بالأعلى كالتالي:

using System;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;

class HttpGet
{
    static void Main(string[] args)
    {
        try
        {
            Run(args).Wait();
        }
        catch (Exception ex)
        {
            if (ex is AggregateException)
                ex = ((AggregateException)ex)
                        .Flatten().InnerExceptions.First();
            Console.WriteLine("--- Error: " +
                              (ex.InnerException?.Message ?? ex.Message));
        }
    }
    static async Task Run(string[] args)
    {
        if (args.Length < 2)
        {
            Console.WriteLine("Basic HTTP downloader");
            Console.WriteLine();
            Console.WriteLine("Usage: httpget <url>[<:port>] <file>");
            return;
        }
        await DownloadAsync(fromUrl: args[0], toFile: args[1]);
        Console.WriteLine("Done!");
    }
}

إرسال طلب POST باستخدام HttpClient.SendAsync

يُهيَّّئ الطلب في صورة كائن من النوع HttpRequestMessage، فمثلًا تُسْنَد قيمة الرابط للخاصية RequestUri بينما تُسنَد قيمة المَتْن (request body) للخاصية Content.

يُرسِل التابع SendAsync طلب POST إلى الخَادِم مع قيمة الطلب المُهيَّئ، ويُعيد قيمة من النوع Task<HttpResponseMessage>‎ تُمثِل رد الخادم (response)، كالمثال التالي:

string requestUri = "http://www.example.com";
string requestBodyString = "Request body string.";
string contentType = "text/plain";
string requestMethod = "POST";

using (var client = new HttpClient())
{
    var request = new HttpRequestMessage
    {
        RequestUri = requestUri,
        Method = requestMethod,
    };

    byte[] requestBodyBytes = Encoding.UTF8.GetBytes(requestBodyString);
    request.Content = new ByteArrayContent(requestBodyBytes);
    request.Content.Headers.ContentType = new MediaTypeHeaderValue(contentType);

    HttpResponseMessage result = client.SendAsync(request).Result;
    result.EnsureSuccessStatusCode();
}

إرسال طلب GET باستخدام HttpWebRequest.GetResponse

يُهيِّئ التابع WebRequest.Create طلب GET إلى خادم (server) بمُعامِل الرابط المُمرَّر إليه، ثم يتم الارسال الفعلي بواسطة التابع GetResponse وتُعاد قيمة من النوع WebResponse تُمثِل رد الخادم. في المثال التالي:

string requestUri = "http://www.example.com";
string responseData;

HttpWebRequest request =(HttpWebRequest)WebRequest.Create(parameters.Uri);
WebResponse response = request.GetResponse();

يُمكن تَحويل رد الخَادِم إلى سِلسِلة نصية كالتالي:

using (StreamReader responseReader = new StreamReader(response.GetResponseStream()))
{
    responseData = responseReader.ReadToEnd();
}

إرسال طلب POST باستخدام HttpWebRequest.GetResponse

يُهيِّئ التابع WebRequest.Create طلب POST إلى خادم (server) بمُعامِل الرابط المُمرر إليه. قد تحتاج إلى تهيئة مَتْن الطلب (request body) أيضًا. للقيام بذلك، استخدم التابع GetRequestStream لاستعادة مَتْن الطلب بصورة مَجْرى (stream) يُكتَّب عليه المُحتوَى المطلوب.

بعد انتهاء التهيئة، يتم الارسال الفعلي بواسطة التابع GetResponse وتُعاد قيمة من النوع WebResponse تُمثِل رد الخادم. في المثال التالي:

string requestUri = "http://www.example.com";
string requestBodyString = "Request body string.";
string contentType = "text/plain";
string requestMethod = "POST";

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUri)
{
    Method = requestMethod,
    ContentType = contentType,
};

byte[] bytes = Encoding.UTF8.GetBytes(requestBodyString);
Stream stream = request.GetRequestStream();
stream.Write(bytes, 0, bytes.Length);
stream.Close();

HttpWebResponse response = (HttpWebResponse)request.GetResponse();

رفع ملفات إلى خادم باستخدام HttpWebRequest.GetResponseAsync

تُرفَّع الملفات إلى الخوادم من خلال إرسال طلب POST إلى الخادم مع إرفاق مُحتوَى الملف ضِمْن مَتْن الطلب.

يُهيِّئ التابع WebRequest.CreateHttp طلب (request) إلى خادم (server) بمُعامِل الرابط المُمرَّر إليه.

var request = WebRequest.CreateHttp(url);

قد تحتاج إلى تهيئة إضافية للطلب مثل إضافة مَتْن إليه (request body). للقيام بذلك، اِستخدِم التابع GetRequestStream لاستعادة مَتْن الطلب بصورة مَجْرى (stream). تستطيع الكتابة على المَجْرى مباشرة أو تَضْمِينه داخل كائن من النوع StreamWriter ثم تَكتِب عليه المُحتوَى المطلوب.

using (var requestStream = request.GetRequestStream())
using (var writer = new StreamWriter(requestStream))
{
    await writer.WriteAsync("");
}

نَحتَاج لرَفع ملف إلى الخادم، مما يعني كتابة مُحتوَيات هذا الملف على مَجْرى مَتْن الطلب. يُفتَح الملف أولًا في صورة مَجْرى ثم تُنقَل محتوياته لمَجْرى الطلب، كالتالي:

using (var fileStream = File.OpenRead(filename))
    await fileStream.CopyToAsync(requestStream);

بعد انتهاء التهيئة، يتم الارسال الفعلي للطلب بواسطة التابع GetResponseAsync وتُعاد قيمة من النوع Task<WebResponse>‎ تُمثِل رد الخادم، كالتالي:

var response = (HttpWebResponse) await request.GetResponseAsync();

تستعرض الشيفرة التالية المثال بالكامل:

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Threading.Tasks;

public async Task<string> UploadFile(string url, 
                                     string filename,
                                     Dictionary<string, object> postData)
{

    var request = WebRequest.CreateHttp(url);
    var boundary = $"{Guid.NewGuid():N}"; 

    request.ContentType = $"multipart/form-data; {nameof(boundary)}={boundary}";
    request.Method = "POST";

    using (var requestStream = request.GetRequestStream())
    using (var writer = new StreamWriter(requestStream))
    {
        foreach (var data in postData)
            await writer.WriteAsync( 
            $"\r\n--{boundary}\r\nContent-Disposition: " +
            $"form-data; name=\"{data.Key}\"\r\n\r\n{data.Value}");

        await writer.WriteAsync( // file header
            $"\r\n--{boundary}\r\nContent-Disposition: " +
            $"form-data; name=\"File\"; filename=\"{Path.GetFileName(filename)}\"\r\n" +
            "Content-Type: application/octet-stream\r\n\r\n");

        await writer.FlushAsync();

        using (var fileStream = File.OpenRead(filename))
            await fileStream.CopyToAsync(requestStream);

        await writer.WriteAsync($"\r\n--{boundary}--\r\n");
    }

    using (var response = (HttpWebResponse) await request.GetResponseAsync())
    using (var responseStream = response.GetResponseStream())
    {
        if (responseStream == null)
            return string.Empty;

        using (var reader = new StreamReader(responseStream))
            return await reader.ReadToEndAsync();
    }
}

إرسال طلب GET باستخدام WebClient.DownloadString

يُرسِل التابع DownloadString طلب GET إلى خادم (server) عن طريق مُعامِل الرابط المُمرر إليه، ويُعيد قيمة من النوع string تُمثِل رد الخادم.

string requestUri = "http://www.example.com";
string responseData;
using (var client = new WebClient())
{
    responseData = client.DownloadString(requestUri);
}

إرسال طلب POST باستخدام WebClient.UploadData

يُرسِل التابع UploadData طلب POST إلى خادم (server) مع مَتْن الطلب المُمرر له، كالتالي:

string requestUri = "http://www.example.com";
string requestBodyString = "Request body string.";
string contentType = "text/plain";
string requestMethod = "POST";

byte[] responseBody;
byte[] requestBodyBytes = Encoding.UTF8.GetBytes(requestBodyString);

using (var client = new WebClient())
{
    client.Headers[HttpRequestHeader.ContentType] = contentType;
    responseBody = client.UploadData(requestUri, requestMethod, requestBodyBytes);
}

عميل SMTP لإرسال بريد إلكتروني

يُمكِنك بسهولة إنشاء كائن من النوع MailMessage بحيث يَحمِل معلومات البريد الإلكتروني المَطلوب إرساله، ثم مَرِّره إلى كائن من النوع SmtpClient حتى يقوم بالإرسال الفعلي.

يَحتوِي النوع MailMessage على الخاصيات:

  • To
  • From
  • ReplyToList
  • CC
  • Bcc
  • Subject
  • Body
  • IsBodyHtml
  • Attachments
  • Priority والتي يُمكن ضَبْط قيمها كأيّ بريد الكتروني عادي.
using(MailMessage MyMail = new MailMessage())
{
    MyMail.From = new MailAddress(mailfrom);
    MyMail.To.Add(mailto);
    MyMail.ReplyToList.Add(replyto);
    MyMail.CC.Add(mailcc);
    MyMail.Bcc.Add(mailbcc);
    MyMail.Subject = subject;
    MyMail.IsBodyHtml = true;
    MyMail.Body = body;
    MyMail.Priority = MailPriority.Normal;

    //
}

في المقابل، يَحتوِي النوع SmtpClient على الخاصيات Host و Port و Credentials لتخصيص بيانات خَادِم الـ SMTP المُستخدَم لإرسال البريد الإلكتروني.

SmtpClient smtpMailObj = new SmtpClient();
smtpMailObj.Host = "your host";
smtpMailObj.Port = 25;
smtpMailObj.Credentials = new System.Net.NetworkCredential("uid", "pwd");

الشيفرة بالكامل:

public class clsMail
{
    private static bool SendMail(string mailfrom, List<string>replytos, List<string> mailtos, List<string> mailccs, List<string> mailbccs, string body, string subject, List<string> Attachment)
    {
        try
        {
            using(MailMessage MyMail = new MailMessage())
            {
                MyMail.From = new MailAddress(mailfrom);

                foreach (string mailto in mailtos)
                    MyMail.To.Add(mailto);

                if (replytos != null && replytos.Any())
                {
                    foreach (string replyto in replytos)
                        MyMail.ReplyToList.Add(replyto);
                }
                if (mailccs != null && mailccs.Any())
                {
                    foreach (string mailcc in mailccs)
                        MyMail.CC.Add(mailcc);
                }
                if (mailbccs != null && mailbccs.Any())
                {
                    foreach (string mailbcc in mailbccs)
                        MyMail.Bcc.Add(mailbcc);
                }

                MyMail.Subject = subject;
                MyMail.IsBodyHtml = true;
                MyMail.Body = body;
                MyMail.Priority = MailPriority.Normal;

                if (Attachment != null && Attachment.Any())
                {
                    System.Net.Mail.Attachment attachment;
                    foreach (var item in Attachment)
                    {
                        attachment = new System.Net.Mail.Attachment(item);
                        MyMail.Attachments.Add(attachment);
                    }
                }

                SmtpClient smtpMailObj = new SmtpClient();
                smtpMailObj.Host = "your host";
                smtpMailObj.Port = 25;
                smtpMailObj.Credentials = new System.Net.NetworkCredential("uid", "pwd");

                smtpMailObj.Send(MyMail);
                return true;
            }
        }
        catch
        {
            return false;
        }
    }
}

يُدعم النوع MailMessage إضافة المُرفَقات من خلال الخاصية Attachments كالتالي:

using System.Net.Mail;
using(MailMessage myMail = new MailMessage())
{
    Attachment attachment = new Attachment(path);
    myMail.Attachments.Add(attachment);
}

عميل UDP لمزامنة التوقيت باستخدام خادم SNTP

يُمكِن لعميل إرسال طلبات لخادم SNTP لمُزامنة التوقيت مع ذلك الخادم. اطلع على RFC 2030 للمزيد من المعلومات عن بروتوكول SNTP.

تجهيز طلب SNTP كالتالي:

var sntpRequest = new byte[48];
sntpRequest[0] = 0x23; //LI=0 (no warning), VN=4, Mode=3 (client)

إرسال الطلب من خلال الصنف UDPClient:

var udpClient = new UdpClient();
udpClient.Client.ReceiveTimeout = 5000;
udpClient.Send(
    dgram: sntpRequest,
    bytes: sntpRequest.Length,
    hostname: args[0],
    port: SntpPort);

مُزامنة التوقيت:

var date = BaseDate.AddSeconds(numberOfSeconds).AddHours(localTimeZoneInHours);

الشيفرة بالكامل:

using System;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Sockets;
class SntpClient
{
    const int SntpPort = 123;
    static DateTime BaseDate = new DateTime(1900, 1, 1);

    static void Main(string[] args)
    {

        if(args.Length == 0) {
            Console.WriteLine("Simple SNTP client");
            Console.WriteLine();
            Console.WriteLine("Usage: sntpclient <sntp server url> [<local timezone>]");
            Console.WriteLine();
            Console.WriteLine("<local timezone>: a number between -12 and 12 as hours from UTC");
            Console.WriteLine("(append .5 for an extra half an hour)");
            return;
        }

        double localTimeZoneInHours = 0;
        if(args.Length > 1)
            localTimeZoneInHours = double.Parse(args[1], CultureInfo.InvariantCulture);

        var udpClient = new UdpClient();
        udpClient.Client.ReceiveTimeout = 5000;

        var sntpRequest = new byte[48];
        sntpRequest[0] = 0x23; //LI=0 (no warning), VN=4, Mode=3 (client)
        udpClient.Send(
            dgram: sntpRequest,
            bytes: sntpRequest.Length,
            hostname: args[0],
            port: SntpPort);

        byte[] sntpResponse;
        try
        {
            IPEndPoint remoteEndpoint = null;
            sntpResponse = udpClient.Receive(ref remoteEndpoint);
        }
        catch(SocketException)
        {
            Console.WriteLine("*** No response received from the server");
            return;
        }

        uint numberOfSeconds;
        if(BitConverter.IsLittleEndian)
            numberOfSeconds = BitConverter.ToUInt32(
            sntpResponse.Skip(40).Take(4).Reverse().ToArray(), 0);
        else
            numberOfSeconds = BitConverter.ToUInt32(sntpResponse, 40);

        var date = BaseDate.AddSeconds(numberOfSeconds).AddHours(localTimeZoneInHours);

        Console.WriteLine(
            $"Current date in server: {date:yyyy-MM-dd HH:mm:ss} UTC{localTimeZoneInHours:+0.#;-0.#;.}");

    }
}

خادم وعميل TCP لتنشئة برنامج دردشة

باستخدام الأنواع TcpListener و TcpClient و NetworkStream.

using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
class TcpChat
{
    static void Main(string[] args)
    {
        if(args.Length == 0)
        {
            Console.WriteLine("Basic TCP chat");
            Console.WriteLine();
            Console.WriteLine("Usage:");
            Console.WriteLine("tcpchat server <port>");
            Console.WriteLine("tcpchat client <url> <port>");
            return;
        }
        try
        {
            Run(args);
        }
        catch(IOException)
        {
            Console.WriteLine("--- Connection lost");
        }
        catch(SocketException ex)
        {
            Console.WriteLine("--- Can't connect: " + ex.Message);
        }
    }

    static void Run(string[] args)
    {
        TcpClient client;
        NetworkStream stream;
        byte[] buffer = new byte[256];
        var encoding = Encoding.ASCII;
        if(args[0].StartsWith("s", StringComparison.InvariantCultureIgnoreCase))
        {
            var port = int.Parse(args[1]);
            var listener = new TcpListener(IPAddress.Any, port);
            listener.Start();
            Console.WriteLine("--- Waiting for a connection...");
            client = listener.AcceptTcpClient();
        }
        else
        {
            var hostName = args[1];
            var port = int.Parse(args[2]);
            client = new TcpClient();
            client.Connect(hostName, port);
        }
        stream = client.GetStream();
        Console.WriteLine("--- Connected. Start typing! (exit with Ctrl-C)");
        while(true)
        {
            if(Console.KeyAvailable)
            {
                var lineToSend = Console.ReadLine();
                var bytesToSend = encoding.GetBytes(lineToSend + "\r\n");
                stream.Write(bytesToSend, 0, bytesToSend.Length);
                stream.Flush();
            }
            if (stream.DataAvailable)
            {
                var receivedBytesCount = stream.Read(buffer, 0, buffer.Length);
                var receivedString = encoding.GetString(buffer, 0, receivedBytesCount);
                Console.Write(receivedString);
            }
        }
    }
}

ترجمة -وبتصرف- للفصول:

  • HTTP servers
  • HTTP clients
  • Upload file and POST data to webserver
  • System.Net.Mail
  • Networking

من كتاب ‎.NET Framework Notes for Professionals





تفاعل الأعضاء


لا توجد أيّة تعليقات بعد



يجب أن تكون عضوًا لدينا لتتمكّن من التعليق

انشاء حساب جديد

يستغرق التسجيل بضع ثوان فقط


سجّل حسابًا جديدًا

تسجيل الدخول

تملك حسابا مسجّلا بالفعل؟


سجّل دخولك الآن