Feidhmchlár chun cinn rothaíochta nó freastalaí cliant bunaithe ar chreat C # .Net

Iontráil

Thosaigh sé ar fad nuair a mhol comhghleacaí dom seirbhís bheag gréasáin a chruthú. Bhí sé ceaptha a bheith rud éigin cosúil le Tinder, ach le haghaidh an slua IT. Tá an fheidhmiúlacht thar a bheith simplí, cláraíonn tú, líonann tú próifíl agus bogann tú ar aghaidh go dtí an príomhphointe, is é sin duine a aimsiú chun labhairt leis agus do naisc a leathnú agus lucht aitheantais nua a dhéanamh.

Ní mór dom cúlú a dhéanamh anseo agus beagán a insint fúm féin, ionas go mbeadh sé níos soiléire amach anseo cén fáth ar ghlac mé céimeanna forbartha den sórt sin.

I láthair na huaire tá post mar Ealaíontóir Teicniúil agam i stiúideo cluiche amháin, níor tógadh mo thaithí ríomhchlárúcháin i C# ach ar scripteanna agus fóntais a scríobh le haghaidh Unity agus, ina theannta sin, forlíontáin a chruthú le haghaidh obair ar leibhéal íseal le gléasanna Android. Ní raibh mé tar éis dul níos faide ná an saol beag seo go fóill, agus ansin d'éirigh an deis sin.

Cuid 1. Fréamhshamhail fráma

Tar éis dom a chinneadh conas a bheadh ​​an tseirbhís seo, thosaigh mé ag lorg roghanna le haghaidh cur i bhfeidhm. Is é an rud is éasca ná réiteach réidh de chineál éigin a fháil, ar a bhféadfar, cosúil le ulchabhán ar chruinneog, ár meicnic a tharraingt agus an rud ar fad a nochtadh do cháineadh poiblí.
Ach níl sé seo suimiúil, ní fhaca mé aon dúshlán nó ciall ann, agus mar sin thosaigh mé ag déanamh staidéir ar theicneolaíochtaí gréasáin agus modhanna idirghníomhú leo.

Thosaigh mé ag staidéar trí bhreathnú ar ailt agus doiciméadú ar C# .Net. Anseo fuair mé bealaí éagsúla chun an tasc a chríochnú. Tá go leor meicníochtaí ann chun idirghníomhú leis an líonra, ó réitigh lán-chuimsitheach cosúil le seirbhísí ASP.Net nó Azure, go dtí idirghníomhú díreach le naisc TcpHttp.

Tar éis dom mo chéad iarracht a dhéanamh le ASP, dhiúltaigh mé láithreach é; i mo thuairim, ba chinneadh ró-dheacair é seo dár seirbhís. Ní úsáidfimid fiú an tríú cuid de chumais an ardáin seo, mar sin lean mé ar aghaidh le mo chuardach. Bhí an rogha idir cliant-freastalaí TCP agus Http. Anseo, ar Habré, tháinig mé trasna ar alt faoi freastalaí ilshnáithe, tar éis é a bhailiú agus a thástáil, chinn mé díriú go sonrach ar idirghníomhaíocht le naisc TCP, ar chúis éigin shíl mé nach gceadódh http dom réiteach tras-ardán a chruthú.

Chuimsigh an chéad leagan den fhreastalaí próiseáil naisc, seirbheáladh ábhar leathanach gréasáin statach, agus chuimsigh sé bunachar sonraí úsáideoirí. Agus ar dtús, chinn mé feidhmiúlacht a thógáil le haghaidh oibriú leis an suíomh, ionas go bhféadfainn próiseáil an fheidhmchláir a chur leis ar Android agus iOS.

Seo roinnt cód
An príomh-snáithe ag fáil cliaint i lúb gan teorainn:

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

Láimhseálaí an chliaint fé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 an chéad bhunachar sonraí tógtha ar SQL áitiúil:

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 fheiceann tú, is beag difríocht atá idir an leagan seo agus an ceann san alt. Go deimhin, anseo chuir muid díreach luchtú na leathanaigh ó fhillteán ar an ríomhaire agus bunachar sonraí (nach bhfuil, dála an scéil, ag obair sa leagan seo mar gheall ar an ailtireacht nasc mícheart).

Caibidil 2. Scriú na rothaí

Tar éis dom an freastalaí a thástáil, tháinig mé ar an tátal gur réiteach den scoth a bheadh ​​anseo (spoiler: Níl), le haghaidh ár seirbhís, mar sin thosaigh an tionscadal a fháil loighic.
Céim ar chéim, thosaigh modúil nua le feiceáil agus leathnaigh feidhmiúlacht an fhreastalaí. Tá fearann ​​tástála agus criptiúchán naisc SSL faighte ag an bhfreastalaí.

Cód beagán níos mó ag cur síos ar an loighic an fhreastalaí agus próiseála cliant
Leagan nuashonraithe den fhreastalaí a chuimsíonn úsáid deimhnithe.

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 freisin láimhseálaí cliant nua le húdarú 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 ós rud é go ritheann an freastalaí go heisiach ar nasc TCP, is gá modúl a chruthú a d'fhéadfadh comhthéacs an iarratais a aithint. Chinn mé go mbeadh parsálaí oiriúnach anseo a bhrisfeadh an t-iarratas ón gcliant ina chodanna ar leith a bhféadfainn idirghníomhú leo chun na freagraí riachtanacha a thabhairt don chliant.

parsálaí

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 é a bunúsach an t-iarratas a bhriseadh ina chodanna ag baint úsáide as nathanna rialta. Faighimid teachtaireacht ón gcliant, roghnaigh an chéad líne, ina bhfuil an modh agus iarr url. Ansin léimid na ceannteidil, a chuireamar isteach i sraith den fhoirm HeaderName=Content, agus aimsímid freisin, más ann dó, ábhar a théann leis (mar shampla, querystring) a chuireamar isteach in eagar comhchosúil freisin. Ina theannta sin, faigheann an parsálaí amach an bhfuil an cliant reatha údaraithe agus stórálann sé a chuid sonraí. Tá hash údaraithe i ngach iarratas ó chliaint údaraithe, a stóráiltear i bhfianáin, a bhuí leis seo is féidir loighic oibriúcháin bhreise a scaradh don dá chineál cliant agus na freagraí cearta a thabhairt dóibh.

Bhuel, gné beag deas arbh fhiú é a chur isteach i modúl ar leith, tiontú ceisteanna ar nós “site.com/@UserName” ina leathanaigh úsáideora ginte go dinimiciúil. Tar éis an t-iarratas a phróiseáil, tagann na modúil seo a leanas i bhfeidhm.

Caibidil 3. Suiteáil an roth stiúrtha, lubrication an slabhra

Chomh luath agus a bhíonn a chuid oibre críochnaithe ag an bparsálaí, tagann an láimhseálaí i bhfeidhm, ag tabhairt treoracha breise don fhreastalaí agus ag roinnt an rialaithe ina dhá chuid.

Láimhseálaí simplí

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

Go deimhin, níl ach seiceáil amháin ar údarú úsáideora, agus ina dhiaidh sin cuirtear tús le próiseáil an iarratais.

Rialaitheoirí cliant
Mura bhfuil an t-úsáideoir údaraithe, níl an fheidhmiúlacht dó bunaithe ach ar thaispeáint próifílí úsáideora agus ar fhuinneog clárúcháin an údaraithe. Breathnaíonn an cód d'úsáideoir údaraithe mar an gcéanna, mar sin ní fheicim aon chúis lena mhacasamhlú.

Úsáideoir neamhúdaraithe

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 ar ndóigh, ní mór don úsáideoir ábhar leathanach de chineál éigin a fháil, mar sin le haghaidh freagraí tá an modúl seo a leanas, atá freagrach as freagra a thabhairt ar iarratais acmhainne.

Rialaitheoir Scríbhneora

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 chun a phróifíl agus próifílí úsáideoirí eile a thaispeáint don úsáideoir, chinn mé RazorEngine a úsáid, nó in áit cuid de. Áiríonn sé freisin iarratais neamhbhailí a phróiseáil agus cód earráide cuí a eisiúint.

Rialaitheoir 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 ar ndóigh, chun go n-oibreoidh úsáideoirí údaraithe a fhíorú, tá gá le húdarú. Idirghníomhaíonn an modúl údaraithe leis an mbunachar sonraí. Déantar na sonraí a fhaightear ó fhoirmeacha ar an láithreán a pharsáil ón gcomhthéacs, sábháltar an t-úsáideoir agus mar chúiteamh faigheann sé fianáin agus rochtain ar an tseirbhís.

Modúl údaraithe

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 is é seo an chuma atá ar phróiseáil bunachar sonraí:

Bunachar Sonraí

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 oibríonn gach rud mar obair chlog, údarú agus obair chlárúcháin, tá an fheidhmiúlacht íosta chun rochtain a fháil ar an tseirbhís ann cheana féin agus tá an t-am tagtha chun iarratas a scríobh agus an rud ar fad a cheangal le chéile leis na príomhfheidhmeanna a bhfuil gach rud á dhéanamh ina leith.

Caibidil 4. An rothar a chaitheamh

Chun na costais saothair a bhaineann le dhá iarratas a scríobh ar dhá ardán a laghdú, chinn mé tras-ardán a dhéanamh ar Xamarin.Forms. Arís, a bhuíochas leis an bhfíric go bhfuil sé i C #. Tar éis iarratas tástála a dhéanamh a sheolann sonraí chuig an bhfreastalaí go simplí, tháinig mé trasna ar phointe suimiúil. Ar iarratas ó ghléas, le haghaidh spraoi, chuir mé i bhfeidhm é ar HttpClient agus sheol mé chuig an bhfreastalaí HttpRequestMessage é, ina bhfuil sonraí ón bhfoirm údaraithe i bhformáid json. Gan a bheith ag súil go háirithe le rud ar bith, d'oscail mé logáil an fhreastalaí agus chonaic mé ann iarratas ón bhfeiste leis na sonraí go léir. Stupor beag, feasacht ar gach rud atá déanta le 3 seachtaine anuas i tráthnóna languid. Chun cruinneas na sonraí seolta a sheiceáil, chuir mé freastalaí tástála le chéile ar HttpListner. Tar éis dom iarratas eile a fháil air cheana féin, thóg mé as a chéile é i gcúpla líne de chód agus fuair mé KeyValuePair sonraí ón bhfoirm. Laghdaíodh an cheist a pharsáil go dhá líne.

Thosaigh mé ag tástáil a thuilleadh, níor luadh níos luaithe é, ach ar an bhfreastalaí roimhe seo chuir mé comhrá a tógadh ar websockets i bhfeidhm freisin. D’oibrigh sé go maith, ach bhí prionsabal na hidirghníomhaíochta trí Tcp dubhach; b’éigean an iomarca oibre gan ghá a dhéanamh chun idirghníomhú beirt úsáideoir le loga comhfhreagrais a thógáil go hinniúil. Áirítear leis seo iarratas chun an nasc a athrú a pharsáil agus freagra a bhailiú ag baint úsáide as prótacal RFC 6455. Dá bhrí sin, sa fhreastalaí tástála, chinn mé nasc simplí websocket a chruthú. Díreach le haghaidh spraoi.

Ceangail le comhrá

 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 d'oibrigh sé. Rinne an freastalaí féin an nasc a chumrú agus ghin sé eochair freagartha. Ní raibh orm fiú clárú freastalaí a chumrú ar leithligh trí SSL; ba leor go raibh teastas suiteáilte cheana féin ag an gcóras ar an bport riachtanach.

Ar thaobh na feiste agus ar thaobh an tsuímh, mhalartaíodh dhá chliaint teachtaireachtaí, logáilte seo go léir. Níor chuir aon pharsálaí ollmhóra moill ar an bhfreastalaí, níor ghá aon cheann de seo. Tá am freagartha laghdaithe ó 200ms go 40-30ms. Agus tháinig mé ar an gcinneadh ceart amháin.

Feidhmchlár chun cinn rothaíochta nó freastalaí cliant bunaithe ar chreat C # .Net

Caith amach an cur i bhfeidhm freastalaí reatha ar Tcp agus athscríobh gach rud faoi Http. Anois tá an tionscadal ag an gcéim athdhearadh, ach de réir prionsabail idirghníomhaíochta go hiomlán difriúil. Déantar oibriú na ngléasanna agus an tsuímh a shioncronú agus a dhífhabhtú agus tá coincheap coiteann ann, agus is é an t-aon difríocht amháin ná nach gá leathanaigh HTML a ghiniúint le haghaidh feistí.

Aschur

“Mura bhfuil aithne agat ar an áth, ná téigh isteach san uisce” I mo thuairimse, sula dtosóidh mé ag obair, ba chóir go mbeadh spriocanna agus cuspóirí sainmhínithe níos soiléire agam, chomh maith le staidéar a dhéanamh ar na teicneolaíochtaí agus na modhanna is gá chun iad a chur i bhfeidhm ar chliaint éagsúla. Tá an tionscadal beagnach críochnaithe cheana féin, ach b’fhéidir go dtiocfaidh mé ar ais chun labhairt faoi conas a shábháil mé rudaí áirithe arís. D'fhoghlaim mé go leor le linn an phróisis forbartha, ach tá níos mó fós le foghlaim amach anseo. Má tá léite agat go dtí seo, go raibh maith agat as é sin a dhéanamh.

Foinse: will.com