Adhartach rothaireachd no iarrtas neach-frithealaidh stèidhichte air C # .Net frèam

Clàrachadh

Thòisich e uile nuair a mhol co-obraiche dhomh seirbheis lìn bheag a chruthachadh. Bha còir aige a bhith rudeigin mar Tinder, ach airson an t-sluaigh IT. Tha an comas-gnìomh gu math sìmplidh, bidh thu a’ clàradh, a’ lìonadh ìomhaigh agus a’ gluasad air adhart chun phrìomh phuing, is e sin neach a lorg airson bruidhinn ris agus leudachadh air na ceanglaichean agad agus luchd-eòlais ùra a dhèanamh.

An seo feumaidh mi tarraing air ais agus beagan innse mum dheidhinn fhìn, gus am biodh e nas soilleire san àm ri teachd carson a ghabh mi ceumannan leasachaidh mar sin.

Aig an àm seo tha dreuchd Neach-ealain Teicnigeach agam ann an aon stiùidio geama, chaidh an t-eòlas prògramadh agam ann an C # a thogail a-mhàin air sgrìobhadh sgriobtaichean agus goireasan airson Unity agus, a bharrachd air an seo, cruthachadh plugins airson obair aig ìre ìosal le innealan Android. Cha robh mi fhathast air a dhol seachad air an t-saoghal bheag seo, agus an uairsin dh'èirich a leithid de chothrom.

Pàirt 1. Frame prototyping

Às deidh dhomh co-dhùnadh cò ris a bhiodh an t-seirbheis seo coltach, thòisich mi a’ coimhead airson roghainnean airson a bhuileachadh. Is e an rud as fhasa fuasgladh deiseil de sheòrsa air choreigin a lorg, air am faodar, mar chomhachag air cruinne, na meacanaig againn a tharraing agus an rud gu lèir a bhith fosgailte do chàineadh poblach.
Ach chan eil seo inntinneach, chan fhaca mi dùbhlan no mothachadh sam bith ann, agus mar sin thòisich mi a’ sgrùdadh theicneòlasan lìn agus dòighean air eadar-obrachadh leotha.

Thòisich mi ag ionnsachadh le bhith a’ coimhead air artaigilean agus sgrìobhainnean air C# .Net. An seo lorg mi diofar dhòighean air an obair a choileanadh. Tha mòran dhòighean ann airson eadar-obrachadh leis an lìonra, bho fhuasglaidhean làn-chuimseach leithid seirbheisean ASP.Net no Azure, gu eadar-obrachadh dìreach le ceanglaichean TcpHttp.

Às deidh dhomh a’ chiad oidhirp a dhèanamh le ASP, dhiùlt mi e sa bhad; nam bheachd-sa, b’ e co-dhùnadh ro dhoirbh a bha seo airson ar seirbheis. Cha chleachd sinn eadhon an treas cuid de chomasan an àrd-ùrlair seo, agus mar sin lean mi air adhart leis an rannsachadh agam. Bha an roghainn eadar TCP agus frithealaiche teachdaiche Http. An seo, air Habré, thàinig mi tarsainn air artaigil mu dheidhinn frithealaiche ioma-snàthainn, an dèidh dhomh a chruinneachadh agus a dhearbhadh, chuir mi romhpa fòcas sònraichte a dhèanamh air eadar-obrachadh le ceanglaichean TCP, airson adhbhar air choireigin bha mi den bheachd nach leigeadh http dhomh fuasgladh tar-àrd-ùrlar a chruthachadh.

Bha a’ chiad dreach den fhrithealaiche a’ toirt a-steach giollachd ceangail, a’ frithealadh susbaint duilleag lìn statach, agus a’ toirt a-steach stòr-dàta luchd-cleachdaidh. Agus an toiseach, chuir mi romham comas-gnìomh a thogail airson a bhith ag obair leis an làrach, gus am b’ urrainn dhomh giollachd an tagraidh a chuir ris air Android agus iOS nas fhaide air adhart.

Seo beagan còd
Am prìomh snàithlean a gheibh luchd-dèiligidh ann an lùb gun chrìoch:

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);
        }
    }
}

Neach-làimhseachaidh an neach-dèiligidh fhèin:

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();
}
}
}

Agus a’ chiad stòr-dàta a chaidh a thogail air SQL ionadail:

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}");
}
}
}
}
}

Mar a chì thu, chan eil mòran eadar-dhealaichte aig an dreach seo bhon fhear san artaigil. Gu dearbh, an seo chuir sinn dìreach luchdachadh de dhuilleagan bho phasgan air a ’choimpiutair agus stòr-dàta (nach robh, co-dhiù, ag obair san dreach seo air sgàth an ailtireachd ceangail ceàrr).

Caibideil 2. A 'sgrìobadh nan cuibhlichean

Às deidh dhomh deuchainn a dhèanamh air an fhrithealaiche, thàinig mi chun cho-dhùnadh gur e fuasgladh sàr-mhath a bhiodh seo (spoiler: Chan eil), airson ar seirbheis, agus mar sin thòisich am pròiseact a 'faighinn loidsig.
Ceum air cheum, thòisich modalan ùra a’ nochdadh agus leudaich comas-gnìomh an fhrithealaiche. Tha am frithealaiche air àrainn deuchainn agus crioptachadh ceangail SSL fhaighinn.

Beagan a bharrachd còd a’ toirt cunntas air loidsig an fhrithealaiche agus giollachd teachdaiche
Tionndadh ùraichte den fhrithealaiche anns a bheil cleachdadh teisteanais.

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();
        }
    }
}

Agus cuideachd neach-làimhseachaidh teachdaiche ùr le cead 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);
}

}
}

Ach leis gu bheil am frithealaiche a’ ruith a-mhàin air ceangal TCP, feumar modal a chruthachadh a dh’ aithnicheas co-theacs an iarrtais. Cho-dhùin mi gum biodh parser freagarrach an seo a bhriseas an t-iarrtas bhon neach-dèiligidh gu pàirtean fa leth leis am b’ urrainn dhomh eadar-obrachadh gus na freagairtean riatanach a thoirt don neach-dèiligidh.

Parser

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;
}
}
}

Is e a bhrìgh an t-iarrtas a bhriseadh gu pàirtean a’ cleachdadh abairtean cunbhalach. Bidh sinn a 'faighinn teachdaireachd bhon neach-dèiligidh, tagh a' chiad loidhne, anns a bheil an dòigh agus url iarraidh. An uairsin leugh sinn na cinn, a chuir sinn ann an sreath den fhoirm HeaderName = Susbaint, agus lorgaidh sinn cuideachd, ma tha sin ri fhaighinn, susbaint na chois (mar eisimpleir, querystring) a chuir sinn ann an sreath coltach ris cuideachd. A bharrachd air an sin, bidh am parser a’ faighinn a-mach a bheil an neach-dèiligidh gnàthach ùghdarraichte agus a ’stòradh an dàta aige. Tha hash ceadachaidh anns a h-uile iarrtas bho luchd-dèiligidh ùghdarraichte, a tha air a stòradh ann am briosgaidean, le taing dha seo tha e comasach tuilleadh loidsig obrachaidh a sgaradh airson an dà sheòrsa teachdaiche agus na freagairtean ceart a thoirt dhaibh.

Uill, feart beag, snog a b’ fhiach a chuir a-steach do mhodal air leth, tionndadh cheistean mar “site.com/@UserName” gu duilleagan cleachdaiche air an gineadh gu dinamach. Às deidh an iarrtas a ghiullachd, thig na modalan a leanas a-steach.

Caibideil 3. A 'stàladh a' chuibhle stiùiridh, lubrication na slabhraidh

Cho luath ‘s a tha am parser air an obair aige a chrìochnachadh, thig an inneal-làimhseachaidh a-steach, a’ toirt tuilleadh stiùiridh don t-seirbheisiche agus a ’roinn smachd ann an dà phàirt.

Inneal-làimhe sìmplidh

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);
            };
        }
    }
}

Gu dearbh, chan eil ann ach aon sgrùdadh airson cead neach-cleachdaidh, às deidh sin tòisichidh giollachd an iarrtais.

Luchd-riaghlaidh luchd-cleachdaidh
Mura h-eil an neach-cleachdaidh ùghdarraichte, tha an comas-gnìomh dha stèidhichte a-mhàin air taisbeanadh pròifilean luchd-cleachdaidh agus an uinneag clàraidh cead. Tha an còd airson neach-cleachdaidh ùghdarraichte a 'coimhead mun aon rud, agus mar sin chan eil mi a' faicinn adhbhar sam bith airson a dhùblachadh.

Cleachdaiche gun chead

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;

}

}

}
}

Agus gu dearbh, feumaidh an neach-cleachdaidh susbaint duilleag de sheòrsa air choreigin fhaighinn, mar sin airson freagairtean tha am modal a leanas ann, air a bheil uallach airson freagairt ri iarrtasan ghoireasan.

Sgrìobhadair Rianadair

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();
}
}
}

Ach gus a phròifil agus pròifilean luchd-cleachdaidh eile a shealltainn don neach-cleachdaidh, chuir mi romham RazorEngine a chleachdadh, no an àite pàirt dheth. Tha e cuideachd a’ gabhail a-steach a bhith a’ làimhseachadh iarrtasan neo-dhligheach agus a’ cur a-mach còd mearachd iomchaidh.

Rianadair Razor

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();
            }
        }
    }
}

Agus gu dearbh, gus dearbhadh luchd-cleachdaidh ùghdarraichte a bhith ag obair, tha feum air cead. Bidh am modal ceadachaidh ag eadar-obrachadh leis an stòr-dàta. Tha an dàta a gheibhear bho fhoirmean air an làrach air a pharsadh bhon cho-theacsa, tha an neach-cleachdaidh air a shàbhaladh agus mar thoradh air sin gheibh e briosgaidean agus cothrom air an t-seirbheis.

Modal ceadachaidh

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);
}
}
}
}

Agus seo cò ris a tha làimhseachadh stòr-dàta coltach:

Stòr-dàta

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;
}
}
}
}


Agus tha a h-uile càil ag obair mar obair-cloc, cead agus obair clàraidh, tha an comas-gnìomh as lugha airson faighinn chun t-seirbheis ann mu thràth agus tha an t-àm ann tagradh a sgrìobhadh agus an rud gu lèir a cheangal ri chèile leis na prìomh ghnìomhan airson a bheil a h-uile càil ga dhèanamh.

Caibideil 4. Tilgeil air falbh am baidhc

Gus cosgaisean saothair dà thagradh a sgrìobhadh airson dà àrd-ùrlar a lùghdachadh, chuir mi romham tar-ùrlar a dhèanamh air Xamarin.Forms. A-rithist, taing don fhìrinn gu bheil e ann an C #. Às deidh dhomh tagradh deuchainn a dhèanamh a bhios dìreach a’ cur dàta chun t-seirbheisiche, thàinig mi tarsainn air puing inntinneach. Airson iarrtas bho inneal, airson spòrs, chuir mi an gnìomh e air HttpClient agus chuir mi chun t-seirbheisiche HttpRequestMessage, anns a bheil dàta bhon fhoirm ceadachaidh ann an cruth json. Gun a bhith a 'sùileachadh rud sam bith gu sònraichte, dh' fhosgail mi log an fhrithealaiche agus chunnaic mi an sin iarrtas bhon inneal leis an dàta gu lèir. Beagan stupor, mothachadh air a h-uile càil a chaidh a dhèanamh thairis air na 3 seachdainean a dh’ fhalbh ann am feasgar languid. Gus sgrùdadh a dhèanamh air cruinneas an dàta a chaidh a chuir a-steach, chruinnich mi frithealaiche deuchainn air HttpListner. Às deidh dhomh iarrtas eile fhaighinn mu thràth, thug mi air falbh e ann an sreath no dhà de chòd agus fhuair mi KeyValuePair de dhàta bhon fhoirm. Chaidh parsadh na ceiste a lùghdachadh gu dà loidhne.

Thòisich mi a’ dèanamh tuilleadh deuchainn, cha deach iomradh a thoirt air na bu thràithe, ach air an t-seirbheisiche a bh’ ann roimhe chuir mi an gnìomh còmhradh a chaidh a thogail air websockets. Dh’ obraich e gu math, ach bha fìor phrionnsapal eadar-obrachadh tro Tcp dubhach; bha cus obair neo-riatanach ri dhèanamh gus eadar-obrachadh dà neach-cleachdaidh a thogail gu comasach le log conaltraidh. Tha seo a’ toirt a-steach a bhith a’ parsadh iarrtas airson an ceangal atharrachadh agus a’ cruinneachadh freagairt a’ cleachdadh protocol RFC 6455. Mar sin, anns an t-seirbheisiche deuchainn, chuir mi romham ceangal sìmplidh websocket a chruthachadh. Dìreach airson spòrs.

Ceangail ri cabadaich

 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();
                        }
                    }
                }
            }
        }

Agus dh'obraich e. Stèidhich am frithealaiche fhèin an ceangal agus chruthaich e iuchair freagairt. Cha robh agam eadhon ri clàradh frithealaiche a rèiteachadh air leth tro SSL; bha e gu leòr gun robh teisteanas aig an t-siostam mu thràth air a chuir a-steach air a’ phort a bha a dhìth.

Air taobh an uidheim agus air taobh na làraich, dh'atharraich dà neach-dèiligidh teachdaireachdan, chaidh seo uile a chlàradh. Cha robh parsairean mòra a 'slaodadh sìos an fhrithealaiche, cha robh feum air gin de seo. Tha an ùine freagairt air a dhol sìos bho 200ms gu 40-30ms. Agus thàinig mi chun an aon cho-dhùnadh ceart.

Adhartach rothaireachd no iarrtas neach-frithealaidh stèidhichte air C # .Net frèam

Tilg a-mach buileachadh an fhrithealaiche gnàthach air Tcp agus ath-sgrìobh a h-uile càil fo Http. A-nis tha am pròiseact aig ìre ath-dhealbhadh, ach a rèir prionnsapalan eadar-obrachaidh gu tur eadar-dhealaichte. Tha obrachadh innealan agus an làrach air an sioncronachadh agus air an dì-bhugachadh agus tha bun-bheachd cumanta aige, leis an aon eadar-dhealachadh nach eil feum air duilleagan HTML a chruthachadh airson innealan.

co-dhùnadh

"Mura h-eil thu eòlach air an fhadhail, na tèid dhan uisge" Tha mi a’ smaoineachadh, mus tòisich mi air an obair, gum bu chòir amasan agus cinn-uidhe a bhith air am mìneachadh nas soilleire a bhith agam, a bharrachd air sgrùdadh a dhèanamh air na teicneòlasan agus na dòighean riatanach airson an cur an gnìomh air diofar teachdaichean. Tha am pròiseact faisg air a bhith deiseil mu thràth, ach is dòcha gun till mi air ais a bhruidhinn air mar a shàbhail mi rudan sònraichte a-rithist. Dh’ ionnsaich mi tòrr tron ​​phròiseas leasachaidh, ach tha eadhon barrachd ri ionnsachadh san àm ri teachd. Ma tha thu air leughadh cho fada seo, tapadh leat airson sin a dhèanamh.

Source: www.habr.com