Avahiya bisîkletê ya pêşkeftî an serîlêdana xerîdar-server li ser bingeha çarçoweya C# .Net

entry

Hemî gava ku hevkarek pêşniyar kir ku ez karûbarek malperek piçûk biafirînim dest pê kir. Diviya bû ku ew tiştek mîna Tinder be, lê ji bo elaletê IT. Fonksiyonê zehf hêsan e, hûn qeyd dikin, profîlek dagirtin û derbasî xala sereke dibin, ango mirovek bibînin ku pê re biaxivin û têkiliyên xwe berfireh bikin û nasên nû çêbikin.

Li vir divê ez paşvekişînim û hinekî li ser xwe bibêjim, da ku di pêşerojê de zelaltir bibe ka çima min gavên weha di pêşveçûnê de avêtin.

Vê gavê ez di stûdyoyek lîstikê de pozîsyona Hunermendê Teknîkî digirim, ezmûna bernameya min a di C# de tenê li ser nivîsandina senaryo û karûbarên Unity-yê hatî çêkirin û, ji bilî vê, afirandina pêvekan ji bo xebata nizm bi cîhazên Android re. Min hîna ji vê dinyaya piçûk wêdetir neçûbû, û hingê fersendek weha derket holê.

Part 1. Frame prototyping

Piştî ku biryar da ku ev karûbar dê çawa be, min dest pê kir ku li vebijarkên ji bo bicîhkirinê bigerim. Tiştê herî hêsan dê ev be ku meriv cûreyek çareseriyek amade bibîne, ku li ser wê, mîna kewek li ser cîhanek, mekanîzmaya me were kişandin û hemî tişt li ber rexneya gelemperî were derxistin.
Lê ev ne balkêş e, min di wê de ti dijwariyek an jî hestek nedît, û ji ber vê yekê min dest bi xwendina teknolojiyên malperê û rêbazên danûstendina bi wan re kir.

Min bi dîtina gotar û belgeyên li ser C# .Net dest bi xwendinê kir. Li vir min awayên cûrbecûr dîtin ku peywirê temam bikim. Gelek mekanîzmayên danûstendina bi torê re hene, ji çareseriyên bêkêmasî yên mîna karûbarên ASP.Net an Azure, heya têkiliya rasterast bi girêdanên TcpHttp re.

Hewldana xwe ya yekem bi ASP re kir, min yekser ew red kir; bi dîtina min, ev ji bo xizmeta me biryarek pir dijwar bû. Em ê sêyeka kapasîteyên vê platformê jî bikar neynin, ji ber vê yekê min lêgerîna xwe domand. Hilbijartin di navbera TCP û Http-muwekîlê-server de bû. Li vir, li ser Habré, ez rastî gotarek hatim server multithreaded, piştî ku ew berhev kir û ceriband, min biryar da ku ez bi taybetî li ser danûstendina bi girêdanên TCP-ê re bisekinim, ji ber hin sedeman min fikirîn ku http dê nehêle ku ez çareseriyek cross-platform biafirînim.

Guhertoya yekem a serverê pêvajoyek pêwendiyê vedigire, naveroka rûpela malperê ya statîk pêşkêşî dike, û databasek bikarhêner tê de ye. Û ji bo destpêkê, min biryar da ku ji bo xebatê bi malperê re fonksiyonê ava bikim, da ku ez paşê karibim pêvajokirina serîlêdanê li ser Android û iOS zêde bikim.

Li vir hinek kod hene
Mijara sereke ku xerîdar di çerxek bêdawî de distîne:

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

Rêvebirê xerîdar bixwe:

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

Û yekem databasa ku li ser SQL-ya herêmî hatî çêkirin:

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

Wekî ku hûn dikarin bibînin, ev guherto ji ya di gotarê de hindik cûda dibe. Bi rastî, li vir me tenê barkirina rûpelan ji peldankek li ser komputerê û databasek zêde kir (ku, bi awayê, di vê guhertoyê de ji ber mîmariya girêdana çewt nexebitî).

Beşa 2. Çêkirina tekeran

Piştî ceribandina serverê, ez gihîştim wê encamê ku ev ê çareseriyek hêja be(spoiler: na), ji bo karûbarê me, ji ber vê yekê proje dest bi mentiqê kir.
Gav bi gav, modulên nû dest pê kirin û fonksiyona serverê berfireh bû. Pêşkêşkar domainek ceribandinê û şîfrekirina girêdana SSL-ê bi dest xistiye.

Kodek piçûktir ku mantiqa pêvajoya server û xerîdar diyar dike
Guhertoyek nûvekirî ya serverê ku tê de karanîna sertîfîkayê vedihewîne.

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

Û her weha rêveberek nû ya xerîdar bi destûrnameya 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);
}

}
}

Lê ji ber ku server bi taybetî li ser pêwendiyek TCP-ê dimeşîne, pêdivî ye ku modulek were afirandin ku dikare çarçoveya daxwazê ​​nas bike. Min biryar da ku parserek dê li vir maqûl be ku dê daxwaza xerîdar li beşên cihêreng bişkîne ku ez dikarim pê re têkilî bikim da ku bersivên pêwîst bidim xerîdar.

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

Esasê wê ev e ku bi karanîna bêjeyên birêkûpêk daxwazê ​​bike beş. Em ji xerîdar peyamek distînin, rêza yekem, ku rêbaz û url-ya daxwazê ​​vedihewîne, hilbijêrin. Dûv re em sernivîsan dixwînin, yên ku me di nav rêzek forma HeaderName=Naverok de dixwînin, û heke hebe, em naveroka pêvek (mînak, querystring) jî dibînin ku em jî di nav rêzek wusa de dihêlin. Wekî din, parser fêr dibe ka muwekîlê heyî rayedar e û daneyên xwe hilîne. Hemî daxwazên xerîdarên destûrdar haşek destûrnameyê dihewîne, ku di çerezan de tê hilanîn, bi saya vê yekê gengaz e ku meriv mantiqa xebitandinê ya din ji bo du celeb xerîdar veqetîne û bersivên rast bide wan.

Welê, taybetmendiyek piçûk, xweşik a ku hêjayî danîna modulek cihê ye, veguheztina pirsên mîna "site.com/@UserName" li rûpelên bikarhêner ên bi dînamîk têne hilberandin. Piştî pêkanîna daxwazê, modulên jêrîn têne lîstikê.

Beşa 3. Sazkirina çerxa rê, rûnkirina zincîrê

Hema ku parserê karê xwe qedand, hilber tê nav lîstikê, rêwerzên din dide serverê û kontrolê dike du beş.

Simple handler

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

Di rastiyê de, ji bo destûrnameya bikarhêner tenê yek kontrol heye, piştî ku pêvajoyek daxwazê ​​dest pê dike.

Kontrolkerên Client
Ger bikarhêner ne destûr be, wê hingê fonksiyona ji bo wî tenê li ser xuyangkirina profîlên bikarhêner û pencereya qeydkirina destûrnameyê ye. Koda ji bo bikarhênerek destûrdar bi heman rengî xuya dike, ji ber vê yekê ez sedemek dubare nabînim.

Bikarhêner bê destûr

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;

}

}

}
}

Û bê guman, bikarhêner pêdivî ye ku hin naveroka rûpelê werbigire, ji ber vê yekê ji bo bersivan modula jêrîn heye, ku berpirsiyarê bersivdana daxwazên çavkaniyê ye.

WriterController

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

Lê ji bo ku ez profîla xwe û profîlên bikarhênerên din nîşanî bikarhêner bidim, min biryar da ku RazorEngine, an bêtir beşek jê bikar bînim. Di heman demê de pêvajokirina daxwazên nederbasdar û derxistina kodek xeletiyek guncan jî dihewîne.

RazorController

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

Û bê guman, ji bo ku verastkirina bikarhênerên destûrdar bixebite, destûr hewce ye. Modula destûrnameyê bi databasê re têkilî dike. Daneyên ku ji formên li ser malperê hatine wergirtin ji çarçovê têne pars kirin, bikarhêner tê hilanîn û di berdêla wê de çerezan distîne û gihîştina karûbarê.

Modula Destûrkirinê

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

Û ev e ku pêvajoya databasê wekî xuya dike:

Database

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


Û her tişt mîna demjimêr, destûrname û xebata qeydkirinê dixebite, fonksiyona herî kêm ji bo gihîştina karûbarê jixwe heye û dem hatiye ku serîlêdanek binivîsin û hemî tişt bi fonksiyonên sereke yên ku her tişt ji bo wan tê kirin ve girêbidin.

Beşa 4. Avêtina duçerxê

Ji bo kêmkirina lêçûnên kedê yên nivîsandina du serlêdanan ji bo du platforman, min biryar da ku ez li ser Xamarin.Forms platformek xaç bikim. Dîsa, spas ji bo rastiya ku ew di C # de ye. Dema ku serîlêdanek ceribandinê çêkir ku tenê daneyan ji serverê re dişîne, ez rastî xalek balkêş hatim. Ji bo daxwazek ji amûrekê, ji bo kêfê, min ew li ser HttpClient bicîh kir û ji servera HttpRequestMessage re şand, ku daneyên ji forma destûrnameyê di formata json de vedihewîne. Bêyî ku ez bi taybetî li hêviya tiştekî bibim, min têketina serverê vekir û li wir daxwazek ji cîhazê bi hemî daneyan re dît. Xemgîniyek sivik, hay ji her tiştê ku di van 3 hefteyên borî de di êvarek zirav de hatî kirin. Ji bo ku rastbûna daneyên şandin kontrol bikim, min serverek ceribandinê li ser HttpListner kom kir. Piştî ku daxwazek din li ser wê wergirtibû, min ew di çend rêzikên kodê de ji hev veqetand û daneya KeyValuePair ji formê wergirt. Parskirina pirsê bû du rêz.

Min bêtir dest bi ceribandinê kir, ew berê nehatiye behs kirin, lê li ser servera berê jî min sohbetek ku li ser websocketan hatî çêkirin bicîh kir. Ew pir baş dixebitî, lê pir prensîba danûstendinê bi rêya Tcp xemgîn bû; pêdivî bû ku pir xebatek nepêwist were kirin da ku bi jêhatî têkiliya du bikarhêneran bi têketinek hevrêziyê re ava bike. Ev tê de parskirina daxwazek ji bo veguheztina girêdanê û berhevkirina bersivekê bi karanîna protokola RFC 6455. Ji ber vê yekê, di servera ceribandinê de, min biryar da ku girêdanek websocketek hêsan biafirînim. Tenê ji bo kêfê.

Girêdana chat

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

Û ew xebitî. Pêşkêşkar bixwe pêwendiyê mîheng kir û mifteyek bersivê çêkir. Tewra ne hewce bû ku ez qeydkirina serverê bi SSL-ê veqetandî mîheng bikim; bes bû ku pergalê jixwe sertîfîkayek li ser porta hewce sazkirî bû.

Li aliyê cîhazê û li aliyê malperê, du xerîdar mesajan pevguherîn, ev hemî hate tomar kirin. Ti parserên mezin serverê hêdî nakin, yek ji van ne hewce bû. Dema bersivê ji 200 ms daket 40-30 ms. Û ez hatim tenê biryara rast.

Avahiya bisîkletê ya pêşkeftî an serîlêdana xerîdar-server li ser bingeha çarçoweya C# .Net

Pêkanîna servera heyî ya li ser Tcp bavêjin û her tiştî di bin Http de ji nû ve binivîsin. Naha proje di qonaxa nûsazkirinê de ye, lê li gorî prensîbên bi tevahî cûda yên danûstendinê. Xebata alav û malper hevdem û debugkirî ye û têgehek hevpar heye, bi tenê cûdahiya wê ew e ku hewcedariya çêkirina rûpelên HTML-ê ji bo cîhazan tune.

encamê

"Heke hûn bi fordê nizanin, neçin nav avê" Ez difikirim ku berî ku ez dest bi xebatê bikim, divê ez armanc û mebestên zelaltir diyar bikim, û her weha di lêkolîna teknolojiyên pêwîst û rêbazên ji bo pêkanîna wan li ser xerîdarên cihêreng de bigerim. Proje jixwe nêzîkê qedandinê ye, lê dibe ku ez vegerim ku biaxivim ka min çawa hin tiştan dîsa xilas kir. Di pêvajoya pêşkeftinê de ez gelek tişt fêr bûm, lê di pêşerojê de hîn bêtir jî heye. Ger we heya niha xwendibe, spas ji bo kirina we.

Source: www.habr.com