ترقي يافته سائيڪل بلڊنگ يا ڪلائنٽ-سرور ايپليڪيشن C# .Net فريم ورڪ جي بنياد تي

جائز آهي

اهو سڀ شروع ٿيو جڏهن هڪ همراهه تجويز ڪيو ته مان هڪ ننڍڙي ويب سروس ٺاهي. اهو ڪجهه ٿيڻو هو ٽينڊر وانگر، پر آئي ٽي ميڙ لاءِ. ڪارڪردگي انتهائي سادو آهي، توهان رجسٽر ٿيو، هڪ پروفائل ڀريو ۽ مکيه نقطي ڏانهن وڃو، يعني ڳالهائڻ لاءِ هڪ شخص ڳولهڻ ۽ پنهنجا رابطا وڌائڻ ۽ نوان واقفڪار بڻائڻ.

هتي مون کي هڪ پٺڀرائي ڪرڻ گهرجي ۽ پنهنجي باري ۾ ٿورو ٻڌائڻ گهرجي، ته جيئن مستقبل ۾ اهو وڌيڪ واضح ٿئي ته مون ترقي ۾ اهڙا قدم ڇو کنيا.

هن وقت مان هڪ گيم اسٽوڊيو ۾ ٽيڪنيڪل آرٽسٽ جي عهدي تي فائز آهيان، C# ۾ منهنجو پروگرامنگ تجربو صرف اسڪرپٽس ۽ يوٽيلٽيز فار يونٽي لکڻ تي ٺاهيو ويو هو ۽ ان کان علاوه، Android ڊوائيسز سان گهٽ سطحي ڪم لاءِ پلگ ان ٺاهڻ. مان اڃا هن ننڍڙي دنيا کان ٻاهر نڪري نه سگهيو هئس، ته پوءِ اهڙو موقعو پيدا ٿيو.

حصو 1. فريم پروٽوٽائپنگ

فيصلو ڪيو ته هي خدمت ڪهڙي هوندي، مون عمل ڪرڻ لاء اختيارن کي ڳولڻ شروع ڪيو. سڀ کان سولو ڪم اهو هوندو ته ڪو اهڙو تيار ٿيل حل ڳوليو وڃي، جنهن جي بنياد تي، دنيا جي اُلو وانگر، اسان جي مشينري کي ڇڪي سگهجي ۽ سڄي شيءِ کي عوام جي تنقيد جو نشانو بڻائي سگهجي.
پر اهو دلچسپ ناهي، مون ان ۾ ڪو به چئلينج يا احساس نه ڏٺو، ۽ ان ڪري مون ويب ٽيڪنالاجيز ۽ انهن سان رابطي جي طريقن جو مطالعو شروع ڪيو.

مون C# .Net تي آرٽيڪلز ۽ ڊاڪيومينٽيشن ڏسي پڙهڻ شروع ڪيو. هتي مون کي ڪم مڪمل ڪرڻ جا مختلف طريقا مليا. نيٽ ورڪ سان رابطي لاءِ ڪيترائي ميکانيزم آھن، مڪمل حل ٿيل حلن جھڙوڪ ASP.Net يا Azure خدمتن کان وٺي، TcpHttp ڪنيڪشن سان سڌو رابطو ڪرڻ لاءِ.

ASP سان منهنجي پهرين ڪوشش ڪئي، مون ان کي فوري طور تي رد ڪري ڇڏيو؛ منهنجي خيال ۾، اسان جي خدمت لاء اهو تمام ڏکيو فيصلو هو. اسان هن پليٽ فارم جي صلاحيتن جو ٽيون به استعمال نه ڪندا سين، تنهنڪري مون پنهنجي ڳولا جاري رکي. چونڊ TCP ۽ Http ڪلائنٽ سرور جي وچ ۾ هئي. هتي، Habré تي، مون کي هڪ مضمون جي باري ۾ آيو multithreaded سرور، ان کي گڏ ڪرڻ ۽ جانچڻ بعد، مون خاص طور تي TCP ڪنيڪشن سان رابطي تي ڌيان ڏيڻ جو فيصلو ڪيو، ڪجهه سببن لاءِ مون سوچيو ته http مون کي ڪراس پليٽ فارم حل ٺاهڻ جي اجازت نه ڏيندو.

سرور جي پهرين ورزن ۾ ڪنيڪشن پروسيسنگ شامل آهي، جامد ويب پيج جو مواد پيش ڪيو ويو آهي، ۽ هڪ صارف ڊيٽابيس شامل آهي. ۽ شروع ڪرڻ لاءِ، مون فيصلو ڪيو ته سائيٽ سان ڪم ڪرڻ لاءِ فنڪشنلٽي ٺاهڻ جو، ته جيئن پوءِ مان Android ۽ iOS تي ايپليڪيشن جي پروسيسنگ کي شامل ڪري سگهان.

هتي ڪجهه ڪوڊ آهي
لامحدود لوپ ۾ ڪلائنٽ حاصل ڪرڻ جو مکيه موضوع:

using System;
using System.Net.Sockets;
using System.Net;
using System.Threading;

namespace ClearServer
{

    class Server
    {
        TcpListener Listener;
        public Server(int Port)
        {
            Listener = new TcpListener(IPAddress.Any, Port);
            Listener.Start();

            while (true)
            {
                TcpClient Client = Listener.AcceptTcpClient();
                Thread Thread = new Thread(new ParameterizedThreadStart(ClientThread));
                Thread.Start(Client);
            }
        }

        static void ClientThread(Object StateInfo)
        {
            new Client((TcpClient)StateInfo);
        }

        ~Server()
        {
            if (Listener != null)
            {
                Listener.Stop();
            }
        }

        static void Main(string[] args)
        {
            DatabaseWorker sqlBase = DatabaseWorker.GetInstance;

            new Server(80);
        }
    }
}

ڪلائنٽ سنڀاليندڙ پاڻ:

using System;
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;

namespace ClearServer
{
    class Client
    {


        public Client(TcpClient Client)
        {

            string Message = "";
            byte[] Buffer = new byte[1024];
            int Count;
            while ((Count = Client.GetStream().Read(Buffer, 0, Buffer.Length)) > 0)
            {
                Message += Encoding.UTF8.GetString(Buffer, 0, Count);

                if (Message.IndexOf("rnrn") >= 0 || Message.Length > 4096)
                {
                    Console.WriteLine(Message);
                    break;
                }
            }

            Match ReqMatch = Regex.Match(Message, @"^w+s+([^s?]+)[^s]*s+HTTP/.*|");
            if (ReqMatch == Match.Empty)
            {
                ErrorWorker.SendError(Client, 400);
                return;
            }
            string RequestUri = ReqMatch.Groups[1].Value;
            RequestUri = Uri.UnescapeDataString(RequestUri);
            if (RequestUri.IndexOf("..") >= 0)
            {
                ErrorWorker.SendError(Client, 400);
                return;
            }
            if (RequestUri.EndsWith("/"))
            {
                RequestUri += "index.html";
            }

            string FilePath =

quot;D:/Web/TestSite{RequestUri}";

if (!File.Exists(FilePath))
{
ErrorWorker.SendError(Client, 404);
return;
}

string Extension = RequestUri.Substring(RequestUri.LastIndexOf('.'));

string ContentType = "";

switch (Extension)
{
case ".htm":
case ".html":
ContentType = "text/html";
break;
case ".css":
ContentType = "text/css";
break;
case ".js":
ContentType = "text/javascript";
break;
case ".jpg":
ContentType = "image/jpeg";
break;
case ".jpeg":
case ".png":
case ".gif":
ContentType =


quot;image/{Extension.Substring(1)}";
break;
default:
if (Extension.Length > 1)
{
ContentType =


quot;application/{Extension.Substring(1)}";
}
else
{
ContentType = "application/unknown";
}
break;
}

FileStream FS;
try
{
FS = new FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.Read);
}
catch (Exception)
{
ErrorWorker.SendError(Client, 500);
return;
}

string Headers =


quot;HTTP/1.1 200 OKnContent-Type: {ContentType}nContent-Length: {FS.Length}nn";
byte[] HeadersBuffer = Encoding.ASCII.GetBytes(Headers);
Client.GetStream().Write(HeadersBuffer, 0, HeadersBuffer.Length);

while (FS.Position < FS.Length)
{
Count = FS.Read(Buffer, 0, Buffer.Length);
Client.GetStream().Write(Buffer, 0, Count);
}

FS.Close();
Client.Close();
}
}
}

۽ پهريون ڊيٽابيس مقامي SQL تي ٺهيل آهي:

using System;
using System.Data.Linq;
namespace ClearServer
{
    class DatabaseWorker
    {

        private static DatabaseWorker instance;

        public static DatabaseWorker GetInstance
        {
            get
            {
                if (instance == null)
                    instance = new DatabaseWorker();
                return instance;
            }
        }


        private DatabaseWorker()
        {
            string connectionStr = databasePath;
            using (DataContext db = new DataContext(connectionStr))
            {
                Table<User> users = db.GetTable<User>();
                foreach (var item in users)
                {
                    Console.WriteLine(

quot;{item.login} {item.password}");
}
}
}
}
}

جئين توهان ڏسي سگهو ٿا، هي نسخو آرٽيڪل ۾ هڪ کان ٿورو مختلف آهي. حقيقت ۾، هتي اسان صرف ڪمپيوٽر تي فولڊر ۽ ڊيٽابيس مان صفحن جي لوڊشيڊنگ شامل ڪئي آهي (جيڪو، طريقي سان، غلط ڪنيڪشن آرڪيٽيڪچر جي ڪري هن نسخي ۾ ڪم نه ڪيو).

باب 2. سائيڪلن کي ڇڪڻ

سرور کي جانچڻ کان پوءِ، مان ان نتيجي تي پهتو ته هي هڪ بهترين حل هوندو(خراب ڪندڙ: نه)، اسان جي خدمت لاء، تنهنڪري منصوبي منطق حاصل ڪرڻ شروع ڪيو.
قدم بہ قدم، نوان ماڊل ظاهر ٿيڻ شروع ٿيا ۽ سرور جي ڪارڪردگي وڌي وئي. سرور حاصل ڪيو آھي ھڪ ٽيسٽ ڊومين ۽ SSL ڪنيڪشن انڪرپشن.

ٿورڙو وڌيڪ ڪوڊ بيان ڪري ٿو سرور جي منطق ۽ ڪلائنٽ پروسيسنگ
سرور جو هڪ اپڊيٽ ورجن جنهن ۾ سرٽيفڪيٽ جو استعمال شامل آهي.

using System;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Security;
using System.Security.Cryptography.X509Certificates;
using System.Security.Permissions;
using System.Security.Policy;
using System.Threading;


namespace ClearServer
{

    sealed class Server
    {
        readonly bool ServerRunning = true;
        readonly TcpListener sslListner;
        public static X509Certificate serverCertificate = null;
        Server()
        {
            serverCertificate = X509Certificate.CreateFromSignedFile(@"C:sslitinder.online.crt");
            sslListner = new TcpListener(IPAddress.Any, 443);
            sslListner.Start();
            Console.WriteLine("Starting server.." + serverCertificate.Subject + "n" + Assembly.GetExecutingAssembly().Location);
            while (ServerRunning)
            {
                TcpClient SslClient = sslListner.AcceptTcpClient();
                Thread SslThread = new Thread(new ParameterizedThreadStart(ClientThread));
                SslThread.Start(SslClient);
            }
            
        }
        static void ClientThread(Object StateInfo)
        {
            new Client((TcpClient)StateInfo);
        }

        ~Server()
        {
            if (sslListner != null)
            {
                sslListner.Stop();
            }
        }

        public static void Main(string[] args)
        {
            if (AppDomain.CurrentDomain.IsDefaultAppDomain())
            {
                Console.WriteLine("Switching another domain");
                new AppDomainSetup
                {
                    ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase
                };
                var current = AppDomain.CurrentDomain;
                var strongNames = new StrongName[0];
                var domain = AppDomain.CreateDomain(
                    "ClearServer", null,
                    current.SetupInformation, new PermissionSet(PermissionState.Unrestricted),
                    strongNames);
                domain.ExecuteAssembly(Assembly.GetExecutingAssembly().Location);
            }
            new Server();
        }
    }
}

۽ پڻ هڪ نئون ڪلائنٽ هينڊلر SSL اختيار سان:

using ClearServer.Core.Requester;
using System;
using System.Net.Security;
using System.Net.Sockets;

namespace ClearServer
{
    public class Client
    {
        public Client(TcpClient Client)
        {
            SslStream SSlClientStream = new SslStream(Client.GetStream(), false);
            try
            {
                SSlClientStream.AuthenticateAsServer(Server.serverCertificate, clientCertificateRequired: false, checkCertificateRevocation: true);
            }
            catch (Exception e)
            {
                Console.WriteLine(
                    "---------------------------------------------------------------------n" +


quot;|{DateTime.Now:g}n|------------n|{Client.Client.RemoteEndPoint}n|------------n|Exception: {e.Message}n|------------n|Authentication failed - closing the connection.n" +
"---------------------------------------------------------------------n");
SSlClientStream.Close();
Client.Close();
}
new RequestContext(SSlClientStream, Client);
}

}
}

پر جيئن ته سرور خاص طور تي TCP ڪنيڪشن تي هلندو آهي، اهو ضروري آهي ته هڪ ماڊل ٺاهيو جيڪو درخواست جي حوالي سان سڃاڻي سگهي. مون فيصلو ڪيو ته هتي هڪ پارسر مناسب هوندو جيڪو ڪلائنٽ جي درخواست کي الڳ الڳ حصن ۾ ٽوڙيندو جنهن سان آئون ڪلائنٽ کي ضروري جواب ڏيڻ لاءِ رابطو ڪري سگهان ٿو.

پرسر

using ClearServer.Core.UserController;
using ReServer.Core.Classes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Security;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;

namespace ClearServer.Core.Requester
{
    public class RequestContext
    {
        public string Message = "";
        private readonly byte[] buffer = new byte[1024];
        public string RequestMethod;
        public string RequestUrl;
        public User RequestProfile;
        public User CurrentUser = null;
        public List<RequestValues> HeadersValues;
        public List<RequestValues> FormValues;
        private TcpClient TcpClient;

        private event Action<SslStream, RequestContext> OnRead = RequestHandler.OnHandle;

        DatabaseWorker databaseWorker = new DatabaseWorker();

        public RequestContext(SslStream ClientStream, TcpClient Client)
        {

            this.TcpClient = Client;
            try
            {
                ClientStream.BeginRead(buffer, 0, buffer.Length, ClientRead, ClientStream);
            }
            catch { return; }
        }
        private void ClientRead(IAsyncResult ar)
        {
            SslStream ClientStream = (SslStream)ar.AsyncState;

            if (ar.IsCompleted)
            {
                Message = Encoding.UTF8.GetString(buffer);
                Message = Uri.UnescapeDataString(Message);
                Console.WriteLine(

quot;n{DateTime.Now:g} Client IP:{TcpClient.Client.RemoteEndPoint}n{Message}");
RequestParse();
HeadersValues = HeaderValues();
FormValues = ContentValues();
UserParse();
ProfileParse();
OnRead?.Invoke(ClientStream, this);
}
}

private void RequestParse()
{
Match methodParse = Regex.Match(Message, @"(^w+)s+([^s?]+)[^s]*s+HTTP/.*|");
RequestMethod = methodParse.Groups[1].Value.Trim();
RequestUrl = methodParse.Groups[2].Value.Trim();
}
private void UserParse()
{
string cookie;
try
{
if (HeadersValues.Any(x => x.Name.Contains("Cookie")))
{
cookie = HeadersValues.FirstOrDefault(x => x.Name.Contains("Cookie")).Value;
try
{
CurrentUser = databaseWorker.CookieValidate(cookie);
}
catch { }
}
}
catch { }

}
private List<RequestValues> HeaderValues()
{
var values = new List<RequestValues>();
var parse = Regex.Matches(Message, @"(.*?): (.*?)n");
foreach (Match match in parse)
{
values.Add(new RequestValues()
{
Name = match.Groups[1].Value.Trim(),
Value = match.Groups[2].Value.Trim()
});
}
return values;
}

private void ProfileParse()
{
if (RequestUrl.Contains("@"))
{
RequestProfile = databaseWorker.FindUser(RequestUrl.Substring(2));
RequestUrl = "/profile";
}
}
private List<RequestValues> ContentValues()
{
var values = new List<RequestValues>();
var output = Message.Trim('n').Split().Last();
var parse = Regex.Matches(output, @"([^&].*?)=([^&]*b)");
foreach (Match match in parse)
{
values.Add(new RequestValues()
{
Name = match.Groups[1].Value.Trim(),
Value = match.Groups[2].Value.Trim().Replace('+', ' ')
});
}
return values;
}
}
}

ان جو جوهر باقاعده اظهار استعمال ڪندي حصن ۾ درخواست کي ٽوڙڻ آهي. اسان ڪلائنٽ کان هڪ پيغام وصول ڪندا آهيون، پهرين لائن چونڊيو، جنهن ۾ طريقو ۽ درخواست url شامل آهي. پوءِ اسان هيڊنگس پڙهون ٿا، جن کي اسان فارم HeaderName=Content جي هڪ صف ۾ رکون ٿا، ۽ اسان پڻ ڳولهيون ٿا، جيڪڏهن موجود هجي ته، ان سان گڏ مواد (مثال طور، querystring) جنهن کي اسان پڻ ساڳي صف ۾ رکون ٿا. اضافي طور تي، پارسر اهو معلوم ڪري ٿو ته ڇا موجوده ڪلائنٽ بااختيار آهي ۽ پنهنجي ڊيٽا کي محفوظ ڪري ٿو. بااختيار ڪلائنٽ جي سڀني درخواستن ۾ هڪ اختيار واري هيش شامل آهي، جيڪو ڪوڪيز ۾ ذخيرو ٿيل آهي، انهي جي مهرباني، اهو ممڪن آهي ته ٻن قسمن جي ڪلائنٽ لاء وڌيڪ آپريٽنگ منطق کي الڳ ڪرڻ ۽ انهن کي درست جواب ڏيو.

خير، هڪ ننڍڙي، سٺي خصوصيت جيڪا هڪ الڳ ماڊل ۾ رکڻ جي قابل هوندي، سوالن جي تبديلي جهڙوڪ “site.com/@UserName” کي متحرڪ طور تي ٺاهيل صارف صفحن ۾. درخواست تي عمل ڪرڻ کان پوء، هيٺيان ماڊلز راند ۾ ايندا.

باب 3. اسٽيئرنگ ويل کي نصب ڪرڻ، زنجير جي لوڻ

جيئن ئي پارسر پنهنجو ڪم مڪمل ڪري چڪو آهي، هينڊلر راند ۾ اچي ٿو، سرور کي وڌيڪ هدايتون ڏئي ٿو ۽ ڪنٽرول کي ٻن حصن ۾ ورهائي ٿو.

سادو سنڀاليندڙ

using ClearServer.Core.UserController;
using System.Net.Security;
namespace ClearServer.Core.Requester
{
    public class RequestHandler
    {
        public static void OnHandle(SslStream ClientStream, RequestContext context)
        {

            if (context.CurrentUser != null)
            {
                new AuthUserController(ClientStream, context);
            }
            else 
            {
                new NonAuthUserController(ClientStream, context);
            };
        }
    }
}

حقيقت ۾، صارف جي اختيار لاء صرف هڪ چيڪ آهي، جنهن کان پوء درخواست جي پروسيسنگ شروع ٿئي ٿي.

ڪلائنٽ ڪنٽرولرز
جيڪڏهن صارف بااختيار نه آهي، ته پوء هن لاء ڪارڪردگي صرف صارف جي پروفائل جي ڊسپلي ۽ اختيار جي رجسٽريشن ونڊو تي ٻڌل آهي. هڪ بااختيار صارف لاء ڪوڊ ساڳيو ئي ڏسڻ ۾ اچي ٿو، تنهنڪري مون کي ان کي نقل ڪرڻ جو ڪو سبب ناهي.

غير مجاز استعمال ڪندڙ

using ClearServer.Core.Requester;
using System.IO;
using System.Net.Security;

namespace ClearServer.Core.UserController
{
    internal class NonAuthUserController
    {
        private readonly SslStream ClientStream;
        private readonly RequestContext Context;
        private readonly WriteController WriteController;
        private readonly AuthorizationController AuthorizationController;

        private readonly string ViewPath = "C:/Users/drdre/source/repos/ClearServer/View";

        public NonAuthUserController(SslStream clientStream, RequestContext context)
        {
            this.ClientStream = clientStream;
            this.Context = context;
            this.WriteController = new WriteController(clientStream);
            this.AuthorizationController = new AuthorizationController(clientStream, context);
            ResourceLoad();
        }

        void ResourceLoad()
        {
            string[] blockextension = new string[] {"cshtml", "html", "htm"};
            bool block = false;
            foreach (var item in blockextension)
            {
                if (Context.RequestUrl.Contains(item))
                {
                    block = true;
                    break;
                }
            }
            string FilePath = "";
            string Header = "";
            var RazorController = new RazorController(Context, ClientStream);
            
            switch (Context.RequestMethod)
            {
                case "GET":
                    switch (Context.RequestUrl)
                    {
                        case "/":
                            FilePath = ViewPath + "/loginForm.html";
                            Header =

quot;HTTP/1.1 200 OKnContent-Type: text/html";
WriteController.DefaultWriter(Header, FilePath);
break;
case "/profile":
RazorController.ProfileLoader(ViewPath);
break;
default:
//в данном блоке кода происходит отсечение запросов к серверу по прямому адресу страницы вида site.com/page.html
if (!File.Exists(ViewPath + Context.RequestUrl) | block)
{
RazorController.ErrorLoader(404);

}
else if (Path.HasExtension(Context.RequestUrl) && File.Exists(ViewPath + Context.RequestUrl))
{
Header = WriteController.ContentType(Context.RequestUrl);
FilePath = ViewPath + Context.RequestUrl;
WriteController.DefaultWriter(Header, FilePath);
}
break;
}
break;

case "POST":
AuthorizationController.MethodRecognizer();
break;

}

}

}
}

۽ يقينا، صارف کي ڪجهه قسم جي صفحي جي مواد حاصل ڪرڻ گهرجي، تنهنڪري جوابن لاء هيٺ ڏنل ماڊل آهي، جيڪو وسيلن جي درخواستن جي جواب ڏيڻ لاء ذميوار آهي.

ليکڪ ڪنٽرولر

using System;
using System.IO;
using System.Net.Security;
using System.Text;

namespace ClearServer.Core.UserController
{
    public class WriteController
    {
        SslStream ClientStream;
        public WriteController(SslStream ClientStream)
        {
            this.ClientStream = ClientStream;
        }

        public void DefaultWriter(string Header, string FilePath)
        {
            FileStream fileStream;
            try
            {
                fileStream = new FileStream(FilePath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
                Header =

quot;{Header}nContent-Length: {fileStream.Length}nn";
ClientStream.Write(Encoding.UTF8.GetBytes(Header));
byte[] response = new byte[fileStream.Length];
fileStream.BeginRead(response, 0, response.Length, OnFileRead, response);
}
catch { }
}

public string ContentType(string Uri)
{
string extension = Path.GetExtension(Uri);
string Header = "HTTP/1.1 200 OKnContent-Type:";
switch (extension)
{
case ".html":
case ".htm":
return


quot;{Header} text/html";
case ".css":
return


quot;{Header} text/css";
case ".js":
return


quot;{Header} text/javascript";
case ".jpg":
case ".jpeg":
case ".png":
case ".gif":
return


quot;{Header} image/{extension}";
default:
if (extension.Length > 1)
{
return


quot;{Header} application/" + extension.Substring(1);
}
else
{
return


quot;{Header} application/unknown";
}
}
}

public void OnFileRead(IAsyncResult ar)
{
if (ar.IsCompleted)
{
var file = (byte[])ar.AsyncState;
ClientStream.BeginWrite(file, 0, file.Length, OnClientSend, null);
}
}

public void OnClientSend(IAsyncResult ar)
{
if (ar.IsCompleted)
{
ClientStream.Close();
}
}
}

پر صارف کي سندس پروفائل ۽ ٻين استعمال ڪندڙن جي پروفائلز کي ڏيکارڻ لاء، مون فيصلو ڪيو RazorEngine استعمال ڪرڻ، يا ان جو ھڪڙو حصو. اهو پڻ شامل آهي پروسيسنگ غلط درخواستن ۽ هڪ مناسب غلطي ڪوڊ جاري ڪرڻ.

ريزر ڪنٽرولر

using ClearServer.Core.Requester;
using RazorEngine;
using RazorEngine.Templating;
using System;
using System.IO;
using System.Net;
using System.Net.Security;

namespace ClearServer.Core.UserController
{
    internal class RazorController
    {
        private RequestContext Context;
        private SslStream ClientStream;
        dynamic PageContent;


        public RazorController(RequestContext context, SslStream clientStream)
        {
            this.Context = context;
            this.ClientStream = clientStream;

        }

        public void ProfileLoader(string ViewPath)
        {
            string Filepath = ViewPath + "/profile.cshtml";
            if (Context.RequestProfile != null)
            {
                if (Context.CurrentUser != null && Context.RequestProfile.login == Context.CurrentUser.login)
                {
                    try
                    {
                        PageContent = new { isAuth = true, Name = Context.CurrentUser.name, Login = Context.CurrentUser.login, Skills = Context.CurrentUser.skills };
                        ClientSend(Filepath, Context.CurrentUser.login);
                    }
                    catch (Exception e) { Console.WriteLine(e); }

                }
                else
                {
                    try
                    {
                        PageContent = new { isAuth = false, Name = Context.RequestProfile.name, Login = Context.RequestProfile.login, Skills = Context.RequestProfile.skills };
                        ClientSend(Filepath, "PublicProfile:"+ Context.RequestProfile.login);
                    }
                    catch (Exception e) { Console.WriteLine(e); }
                }
            }
            else
            {
                ErrorLoader(404);
            }


        }

        public void ErrorLoader(int Code)
        {
            try
            {
                PageContent = new { ErrorCode = Code, Message = ((HttpStatusCode)Code).ToString() };
                string ErrorPage = "C:/Users/drdre/source/repos/ClearServer/View/Errors/ErrorPage.cshtml";
                ClientSend(ErrorPage, Code.ToString());
            }
            catch { }

        }

        private void ClientSend(string FilePath, string Key)
        {
            var template = File.ReadAllText(FilePath);
            var result = Engine.Razor.RunCompile(template, Key, null, (object)PageContent);
            byte[] buffer = System.Text.Encoding.UTF8.GetBytes(result);
            ClientStream.BeginWrite(buffer, 0, buffer.Length, OnClientSend, ClientStream);
        }

        private void OnClientSend(IAsyncResult ar)
        {
            if (ar.IsCompleted)
            {
                ClientStream.Close();
            }
        }
    }
}

۽ يقينا، ڪم ڪرڻ لاء بااختيار صارفين جي تصديق لاء، اختيار جي ضرورت آهي. اختيار ڪرڻ وارو ماڊل ڊيٽابيس سان رابطو ڪري ٿو. سائيٽ تي فارمن مان حاصل ڪيل ڊيٽا کي حوالن مان پارس ڪيو ويو آهي، صارف محفوظ ڪيو ويو آهي ۽ موٽ ۾ ڪوڪيز وصول ڪري ٿو ۽ خدمت تائين رسائي حاصل ڪري ٿو.

اختيار ڪرڻ وارو ماڊل

using ClearServer.Core.Cookies;
using ClearServer.Core.Requester;
using ClearServer.Core.Security;
using System;
using System.Linq;
using System.Net.Security;
using System.Text;

namespace ClearServer.Core.UserController
{
    internal class AuthorizationController
    {
        private SslStream ClientStream;
        private RequestContext Context;
        private UserCookies cookies;
        private WriteController WriteController;
        DatabaseWorker DatabaseWorker;
        RazorController RazorController;
        PasswordHasher PasswordHasher;
        public AuthorizationController(SslStream clientStream, RequestContext context)
        {
            ClientStream = clientStream;
            Context = context;
            DatabaseWorker = new DatabaseWorker();
            WriteController = new WriteController(ClientStream);
            RazorController = new RazorController(context, clientStream);
            PasswordHasher = new PasswordHasher();
        }

        internal void MethodRecognizer()
        {
            if (Context.FormValues.Count == 2 && Context.FormValues.Any(x => x.Name == "password")) Authorize();
            else if (Context.FormValues.Count == 3 && Context.FormValues.Any(x => x.Name == "regPass")) Registration();
            else
            {
                RazorController.ErrorLoader(401);
            }
        }

        private void Authorize()
        {
            var values = Context.FormValues;
            var user = new User()
            {
                login = values[0].Value,
                password = PasswordHasher.PasswordHash(values[1].Value)
            };
            user = DatabaseWorker.UserAuth(user);
            if (user != null)
            {
                cookies = new UserCookies(user.login, user.password);
                user.cookie = cookies.AuthCookie;
                DatabaseWorker.UserUpdate(user);
                var response = Encoding.UTF8.GetBytes(

quot;HTTP/1.1 301 Moved PermanentlynLocation: /@{user.login}nSet-Cookie: {cookies.AuthCookie}; Expires={DateTime.Now.AddDays(2):R}; Secure; HttpOnlynn");
ClientStream.BeginWrite(response, 0, response.Length, WriteController.OnClientSend, null);

}
else
{
RazorController.ErrorLoader(401);

}
}

private void Registration()
{
var values = Context.FormValues;
var user = new User()
{
name = values[0].Value,
login = values[1].Value,
password = PasswordHasher.PasswordHash(values[2].Value),
};
cookies = new UserCookies(user.login, user.password);
user.cookie = cookies.AuthCookie;
if (DatabaseWorker.LoginValidate(user.login))
{
Console.WriteLine("User ready");
Console.WriteLine(


quot;{user.password} {user.password.Trim().Length}");
DatabaseWorker.UserRegister(user);
var response = Encoding.UTF8.GetBytes(


quot;HTTP/1.1 301 Moved PermanentlynLocation: /@{user.login}nSet-Cookie: {user.cookie}; Expires={DateTime.Now.AddDays(2):R}; Secure; HttpOnlynn");
ClientStream.BeginWrite(response, 0, response.Length, WriteController.OnClientSend, null);
}
else
{
RazorController.ErrorLoader(401);
}
}
}
}

۽ اھو اھو آھي جيڪو ڊيٽابيس پروسيسنگ وانگر ڏسڻ ۾ اچي ٿو:

ڊيٽابيس

using ClearServer.Core.UserController;
using System;
using System.Data.Linq;
using System.Linq;

namespace ClearServer
{
    class DatabaseWorker
    {

        private readonly Table<User> users = null;
        private readonly DataContext DataBase = null;
        private const string connectionStr = @"путькбазе";

        public DatabaseWorker()
        {
            DataBase = new DataContext(connectionStr);
            users = DataBase.GetTable<User>();
        }

        public User UserAuth(User User)
        {
            try
            {
                var user = users.SingleOrDefault(t => t.login.ToLower() == User.login.ToLower() && t.password == User.password);
                if (user != null)
                    return user;
                else
                    return null;
            }
            catch (Exception)
            {
                return null;
            }

        }

        public void UserRegister(User user)
        {
            try
            {
                users.InsertOnSubmit(user);
                DataBase.SubmitChanges();
                Console.WriteLine(

quot;User{user.name} with id {user.uid} added");
foreach (var item in users)
{
Console.WriteLine(item.login + "n");
}
}
catch (Exception e)
{
Console.WriteLine(e);
}

}

public bool LoginValidate(string login)
{
if (users.Any(x => x.login.ToLower() == login.ToLower()))
{
Console.WriteLine("Login already exists");
return false;
}
return true;
}
public void UserUpdate(User user)
{
var UserToUpdate = users.FirstOrDefault(x => x.uid == user.uid);
UserToUpdate = user;
DataBase.SubmitChanges();
Console.WriteLine(


quot;User {UserToUpdate.name} with id {UserToUpdate.uid} updated");
foreach (var item in users)
{
Console.WriteLine(item.login + "n");
}
}
public User CookieValidate(string CookieInput)
{
User user = null;
try
{
user = users.SingleOrDefault(x => x.cookie == CookieInput);
}
catch
{
return null;
}
if (user != null) return user;
else return null;
}
public User FindUser(string login)
{
User user = null;
try
{
user = users.Single(x => x.login.ToLower() == login.ToLower());
if (user != null)
{
return user;
}
else
{
return null;
}
}
catch (Exception)
{
return null;
}
}
}
}


۽ سڀ ڪجھ ڪم ڪري ٿو گھڙي جو ڪم، اختيار ڏيڻ ۽ رجسٽريشن جو ڪم، سروس تائين رسائي لاءِ گھٽ ۾ گھٽ ڪارڪردگي اڳ ۾ ئي موجود آھي ۽ وقت اچي ويو آھي ايپليڪيشن لکڻ جو ۽ پوري شيءِ کي بنيادي ڪمن سان ڳنڍيو جنھن لاءِ سڀ ڪجھ ڪيو پيو وڃي.

باب 4. سائيڪل کي اڇلائڻ

ٻن پليٽ فارمن لاءِ ٻه ايپليڪيشنون لکڻ جي مزدوري جي خرچ کي گھٽائڻ لاءِ، مون فيصلو ڪيو ته Xamarin.Forms تي هڪ ڪراس پليٽ فارم ٺاهيو. ٻيهر، حقيقت جي مهرباني ته اهو C # ۾ آهي. هڪ ٽيسٽ ايپليڪيشن ٺاهيندي جيڪا صرف سرور ڏانهن ڊيٽا موڪلي ٿي، مون کي هڪ دلچسپ نقطو نظر آيو. هڪ ڊوائيس کان درخواست لاء، تفريح لاء، مون ان کي HttpClient تي لاڳو ڪيو ۽ ان کي HttpRequestMessage سرور ڏانهن موڪليو، جنهن ۾ json فارميٽ ۾ اختياري فارم مان ڊيٽا شامل آهي. خاص طور تي ڪنهن به شيء جي توقع کان سواء، مون سرور لاگ کوليو ۽ اتي ڏٺو ته ڊوائيس کان هڪ درخواست سڀني ڊيٽا سان گڏ. ٿورڙي بيوقوف، هر شيء جي آگاهي جيڪا گذريل 3 هفتن ۾ ڪيو ويو آهي هڪ خاموش شام ۾. موڪليل ڊيٽا جي درستگي کي جانچڻ لاءِ، مون HttpListner تي هڪ ٽيسٽ سرور گڏ ڪيو. ان تي اڳ ۾ ئي هڪ ٻي درخواست حاصل ڪرڻ کان پوء، مون ان کي ڪوڊ جي ٻن لائينن ۾ ڌار ڪيو ۽ فارم مان ڊيٽا جي KeyValuePair حاصل ڪئي. سوال کي پارس ڪندي ٻن لائينن تائين گھٽجي ويو.

مون وڌيڪ جاچ شروع ڪئي، ان جو ذڪر اڳ ۾ نه ڪيو ويو، پر پوئين سرور تي مون ويب ساکٽس تي ٺاهيل چيٽ پڻ لاڳو ڪيو. اهو تمام سٺو ڪم ڪيو، پر Tcp ذريعي رابطي جو اصول اداس هو؛ هڪ خطوط لاگ سان ٻن استعمال ڪندڙن جي رابطي کي قابليت سان تعمير ڪرڻ لاء تمام گهڻو غير ضروري ڪم ڪرڻو پيو. ھن ۾ ڪنيڪشن کي مٽائڻ لاءِ ھڪ درخواست پارس ڪرڻ ۽ RFC 6455 پروٽوڪول استعمال ڪندي جواب گڏ ڪرڻ شامل آھي. تنھنڪري، ٽيسٽ سرور ۾، مون ھڪڙو سادو ويب ساڪٽ ڪنيڪشن ٺاھڻ جو فيصلو ڪيو. صرف تفريح لاءِ.

چيٽ سان ڳنڍيو

 private static async void HandleWebsocket(HttpListenerContext context)
        {
            var socketContext = await context.AcceptWebSocketAsync(null);
            var socket = socketContext.WebSocket;
            Locker.EnterWriteLock();
            try
            {
                Clients.Add(socket);
            }
            finally
            {
                Locker.ExitWriteLock();
            }

            while (true)
            {
                var buffer = new ArraySegment<byte>(new byte[1024]);
                var result = await socket.ReceiveAsync(buffer, CancellationToken.None);
                var str = Encoding.Default.GetString(buffer);
                Console.WriteLine(str);

                for (int i = 0; i < Clients.Count; i++)
                {
                    WebSocket client = Clients[i];

                    try
                    {
                        if (client.State == WebSocketState.Open)
                        {
                            
                            await client.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
                        }
                    }
                    catch (ObjectDisposedException)
                    {
                        Locker.EnterWriteLock();
                        try
                        {
                            Clients.Remove(client);
                            i--;
                        }
                        finally
                        {
                            Locker.ExitWriteLock();
                        }
                    }
                }
            }
        }

۽ اهو ڪم ڪيو. سرور پاڻ ڪنيڪشن کي ترتيب ڏنو ۽ هڪ جوابي چيڪ ٺاهي. مون کي SSL ذريعي سرور جي رجسٽريشن الڳ الڳ ترتيب ڏيڻ جي ضرورت نه هئي؛ اهو ڪافي هو ته سسٽم اڳ ۾ ئي گهربل پورٽ تي هڪ سرٽيفڪيٽ نصب ڪيو هو.

ڊوائيس جي پاسي ۽ سائيٽ جي پاسي تي، ٻه ڪلائنٽ نياپا مٽائي، هي سڀ لاگ ان ڪيو ويو. سرور کي سست ڪرڻ لاء ڪو به وڏو parsers، هن جي ڪا به ضرورت نه هئي. جواب جو وقت 200ms کان 40-30ms تائين گھٽجي ويو آھي. ۽ مان صرف صحيح فيصلي تي آيو آهيان.

ترقي يافته سائيڪل بلڊنگ يا ڪلائنٽ-سرور ايپليڪيشن C# .Net فريم ورڪ جي بنياد تي

Tcp تي موجوده سرور تي عمل درآمد ڪريو ۽ Http جي تحت سڀڪنھن شيء کي ٻيهر لکو. هاڻي پروجيڪٽ redesign اسٽيج ۾ آهي، پر رابطي جي مڪمل طور تي مختلف اصولن جي مطابق. ڊوائيسز ۽ سائيٽ جي آپريشن کي هم وقت سازي ۽ ڊيبگ ڪيو ويو آهي ۽ هڪ عام تصور آهي، صرف فرق اهو آهي ته ڊوائيسز لاء HTML صفحا پيدا ڪرڻ جي ڪا ضرورت ناهي.

ٿڪل

"جيڪڏهن توهان کي فورڊ جي خبر ناهي، پاڻيء ۾ نه وڃو" مان سمجهان ٿو ته ڪم شروع ڪرڻ کان اڳ، مون کي وڌيڪ واضح طور تي بيان ڪيل مقصد ۽ مقصد هجڻ گهرجي، انهي سان گڏ ضروري ٽيڪنالاجيز ۽ طريقن جي مطالعي ۾ شامل ڪيو ويو آهي مختلف گراهڪن تي انهن جي عمل درآمد لاء. پروجيڪٽ اڳ ۾ ئي مڪمل ٿيڻ جي ويجهو آهي، پر شايد مان واپس اچي ان بابت ڳالهائيندس ته ڪيئن مون ڪجهه شيون ٻيهر محفوظ ڪيون. مون ترقي جي عمل دوران گهڻو ڪجهه سکيو، پر مستقبل ۾ سکڻ لاءِ اڃا به وڌيڪ آهي. جيڪڏهن توهان هن پري پڙهيو آهي، ائين ڪرڻ لاء توهان جي مهرباني.

جو ذريعو: www.habr.com