Uhlelo lokusebenza lokuhamba ngebhayisikili oluthuthukisiwe noma lweseva yeklayenti olusekelwe kuhlaka lwe-C# .Net

entry

Konke kwaqala lapho engisebenza naye ephakamisa ukuthi ngenze insizakalo encane yewebhu. Bekufanele kube yinto efana ne-tinder, kodwa ye-IT hangout. Ukusebenza kulula kakhulu, ubhalisa, ugcwalise iphrofayili bese udlulela ephuzwini eliyinhloko, okungukuthi, ukuthola umuntu oxhumana naye nokwandisa ukuxhumana kwakho nokwenza abantu abasha obajwayele.

Lapha kufanele ngihlehlise futhi ngitshele kancane ngami, ukuze esikhathini esizayo kuzocaca ukuthi kungani ngathatha izinyathelo ezinjalo ekuthuthukisweni.

Okwamanje ngibambe isikhundla sokuba Ingcweti Yezobuchwepheshe kusitudiyo segeyimu, ulwazi lwami lokuhlela lwe-C# lwalusekelwe kuphela ekubhaleni izikripthi nezinsiza ze-Unity futhi, ngaphezu kwalokhu, ukudala ama-plugin omsebenzi wezinga eliphansi ngamadivayisi we-android. Ngaphandle kwaleli zwe, angikakhethi futhi ngivule ithuba elinjalo.

Ingxenye 1. I-Frame Prototyping

Ngemva kokunquma ukuthi le sevisi izoba njani, ngaqala ukubheka izinketho zokuqalisa. Indlela elula kungaba ukuthola uhlobo oluthile lwesixazululo esenziwe ngomumo, lapho, njengesikhova embulungeni, ungakwazi ukudonsa imishini yethu futhi wendlale yonke into ukuze umphakathi usole.
Kodwa lokhu akuthakazelisi, angizange ngibone noma iyiphi inselele nomqondo kulokhu, ngakho-ke ngaqala ukufunda ubuchwepheshe bewebhu nezindlela zokuxhumana nabo.

Ucwaningo luqale ngokubuka izindatshana kanye nemibhalo ku-C # .Net. Lapha ngathola izindlela ezihlukahlukene zokufeza umsebenzi. Kunezindlela eziningi zokusebenzelana nenethiwekhi, kusukela kuzixazululo ezigcwele njenge-ASP.Net noma izinsizakalo ze-Azure, ukuqondisa ukuxhumana nokuxhumana kwe-TcpHttp.

Ngemva kokwenza umzamo wokuqala nge-ASP, ngayikhansela ngokushesha, ngokubona kwami ​​kwakunzima kakhulu isinqumo senkonzo yethu. Ngeke sisebenzise ngisho nengxenye yesithathu yamakhono ale nkundla, ngakho ngiqhubekile nokusesha kwami. Kuvele ukukhetha phakathi kwe-TCP ne-Http client-server. Lapha, ku-HabrΓ©, ngihlangane nesihloko esimayelana iseva enemicu eminingi, ngemva kokuqoqa nokuhlola ukuthi yikuphi, nganquma ukugxila ekusebenzisaneni nokuxhumeka kwe-TCP, ngesizathu esithile ngacabanga ukuthi i-http ngeke ingivumele ukuthi ngidale isisombululo se-cross-platform.

Inguqulo yokuqala yesiphakeli yayihlanganisa ukuphatha ukuxhumana, ukunikeza okuqukethwe kwekhasi lewebhu elimile, kuhlanganise nesizindalwazi somsebenzisi. Futhi okokuqala, nginqume ukwakha umsebenzi wokusebenza nesayithi, ukuze kamuva ngikwazi ukubopha ukucubungula uhlelo lokusebenza ku-android nama-ios lapha.

Nansi ikhodi ethile
Uchungechunge oluyinhloko olwamukela amaklayenti ngendlela engapheli:

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

Isiphathi seklayenti ngokwaso:

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

Futhi i-database yokuqala eyakhelwe ku-SQL yendawo:

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

Njengoba ubona, le nguqulo ihluke kancane kuleyo ekulesi sihloko. Eqinisweni, ukulayishwa kuphela kwamakhasi avela kufolda kukhompyutha kanye ne-database yengezwe lapha (okuyinto, ngendlela, engazange isebenze kule nguqulo, ngenxa yezakhiwo zokuxhuma okungalungile).

Isahluko 2

Ngemva kokuhlola iseva, ngifinyelele esiphethweni sokuthi lokhu kungaba yisixazululo esihle (spoiler: cha), ngenkonzo yethu, ngakho-ke iphrojekthi yaqala ukuthola ingqondo.
Isinyathelo ngesinyathelo, amamojula amasha aqala ukuvela futhi ukusebenza kweseva kwakhula. Iseva inesizinda sokuhlola kanye nokubethela kokuxhumeka kwe-ssl.

Ikhodi ethe xaxa echaza i-logic yeseva nokucutshungulwa kwamaklayenti
Inguqulo ebuyekeziwe yeseva, okuhlanganisa ukusetshenziswa kwesitifiketi.

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

Kanye nesiphathi seklayenti esisha esigunyazwe nge-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);
}

}
}

Kodwa njengoba iseva isebenza ngokukhethekile ekuxhumekeni kwe-TCP, kuyadingeka ukwakha imojuli engabona umongo wesicelo. Nginqume ukuthi umhlahleli ufanelekile lapha ozohlukanisa isicelo seklayenti sibe izingxenye ezihlukene engingakwazi ukuxhumana nazo ukuze nginikeze iklayenti izimpendulo ezidingekayo.

umhlahleli

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

Ingqikithi yayo itholakala eqinisweni lokuthi ngosizo lwezinkulumo ezivamile ukuphula isicelo sibe izingxenye. Sithola umlayezo ovela kuklayenti, khetha umugqa wokuqala, oqukethe indlela kanye ne-url yokucela. Bese sifunda izihloko, esizishayela ohlwini lwefomu elithi HeaderName = Content, futhi sithola, uma kukhona, okuqukethwe okuhambisanayo (isibonelo, i-querystring) esiphinde sikushayele kuhlu olufanayo. Ngaphezu kwalokho, umhlaseli uthola ukuthi iklayenti lamanje ligunyaziwe futhi lilondoloze idatha yalo. Zonke izicelo ezivela kumakhasimende agunyaziwe ziqukethe i-hashi yokugunyazwa, egcinwa kumakhukhi, ngakho-ke kungenzeka ukuhlukanisa umqondo womsebenzi wezinhlobo ezimbili zamaklayenti futhi uwanikeze izimpendulo ezifanele.

Nokho, isici esincane, esihle okufanele sithuthelwe kumojuli ehlukile, siguqule izicelo ezifana ne-"site.com/@UserName" zibe amakhasi abasebenzisi akhiqizwa ngamandla. Ngemva kokucubungula isicelo, amamojula alandelayo aqala ukusebenza.

Isahluko 3. Ukufaka isibambo, ukugcoba iketango

Lapho nje umhlahleli usuqedile, isibambi siyangena, sinikeze iziyalezo ezengeziwe kuseva futhi sihlukanise ukulawula sibe izingxenye ezimbili.

isibambi esilula

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

Eqinisweni, kunesheke elilodwa kuphela lokugunyazwa komsebenzisi, ngemva kwalokho ukucubungula isicelo kuqala.

Abalawuli Beklayenti
Uma umsebenzisi engagunyaziwe, khona-ke kuye ukusebenza kusekelwe kuphela ekubonisweni kwamaphrofayili womsebenzisi kanye nefasitela lokubhalisa lokugunyazwa. Ikhodi yomsebenzisi ogunyaziwe icishe ifane, ngakho-ke angisiboni isizathu sokuyiphinda.

Umsebenzisi ongagunyaziwe

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;

}

}

}
}

Futhi-ke, umsebenzisi kufanele athole okuqukethwe kwamakhasi, ngakho-ke izimpendulo kunemojula elandelayo, enesibopho sokuphendula isicelo sezinsiza.

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

Kodwa ukuze ngibonise umsebenzisi iphrofayela yakhe kanye namaphrofayili abanye abasebenzisi, nginqume ukusebenzisa i-RazorEngine, noma kunalokho ingxenye yayo. Kuhlanganisa nokusingatha izicelo ezimbi kanye nokukhipha ikhodi yephutha efanele.

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

Futhi-ke, ukuze ukuqinisekiswa kwabasebenzisi abagunyaziwe kusebenze, ukugunyazwa kuyadingeka. Imojula yokugunyazwa isebenzisana nesizindalwazi. Idatha etholwe kumafomu akusayithi icutshungulwa kusuka kumongo, umsebenzisi uyagcinwa futhi uthola amakhukhi kanye nokufinyelela kusevisi njengembuyiselo.

Imojula yokugunyazwa

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

Futhi nansi indlela i-database ebukeka ngayo:

Isizindalwazi

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


Futhi yonke into isebenza njengewashi, ukugunyazwa kanye nomsebenzi wokubhalisa, ukusebenza okuncane kokufinyelela enkonzweni sekuvele kutholakala futhi sekuyisikhathi sokubhala isicelo futhi ubophe yonke into ngemisebenzi eyinhloko okwenziwa ngayo konke.

Isahluko 4

Ukunciphisa izindleko zabasebenzi zokubhala izicelo ezimbili zamapulatifomu amabili, nginqume ukwenza i-cross-platform ku-Xamarin.Amafomu. Futhi, sibonga iqiniso lokuthi iku-C#. Ngemva kokwenza isicelo sokuhlola esivele sithumele idatha kuseva, ngigijimele emzuzwini owodwa othokozisayo. Ngesicelo esivela kudivayisi, ukuze ngizijabulise, ngisisebenzise ku-HttpClient futhi ngayiphonsa kuseva i-HttpRequestMessage equkethe idatha evela kufomu lokugunyaza ngefomethi ye-json. Ngaphandle kokulindela okuthile ngokukhethekile, ngivule ilogi yeseva futhi ngabona isicelo esivela kudivayisi enayo yonke idatha lapho. I-stupor elula, ukuqwashisa ngakho konke okwenziwe emasontweni angu-3 adlule obusuku obunzima. Ukuhlola ukulunga kwedatha ethunyelwe, ngihlanganise iseva yokuhlola ku-HttpListner. Ngemva kokuthola isicelo esilandelayo kakade kuso, ngisihlukanise emigqeni embalwa yekhodi, ngathola idatha ye-KeyValuePair efomini. Ukuhlaziya umbuzo kwehliswe kwaba imigqa emibili.

Ngaqala ukuhlola ngokuqhubekayo, akuzange kukhulunywe ngakho ngaphambili, kodwa kuseva yangaphambilini ngisasebenzisa ingxoxo eyakhelwe kuma-websockets. Isebenze kahle kakhulu, kodwa wona kanye umgomo wokusebenzelana nge-Tcp wawudabukisa, kwakudingeka kukhiqizwe okwengeziwe okwengeziwe ukuze kwakhiwe kahle ukuxhumana kwabasebenzisi ababili ngokungena kwezincwadi. Lokhu kuhlanganisa ukudlulisa isicelo sokushintsha uxhumano nokuqoqa impendulo kusetshenziswa iphrothokholi ye-RFC 6455. Ngakho-ke, kuseva yokuhlola, nginqume ukudala uxhumano olulula lwe-websocket. Kuphela ngenxa yentshisekelo.

Uxhumano lwengxoxo

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

Futhi kwasebenza. Iseva ngokwayo imise uxhumano, yakha ukhiye wokuphendula. Angizange ngize ngilungise ngokwehlukana ukubhaliswa kweseva nge-ssl, kwanele ukuthi uhlelo seluvele lunesitifiketi esifakwe echwebeni elidingekayo.

Ohlangothini lwedivayisi nasohlangothini lwesayithi, amaklayenti amabili ashintshana ngemiyalezo, konke lokhu kungeniwe. Abekho abahlaluli abakhulu abanciphisa iseva, akukho kulokhu obekudingeka. Isikhathi sokuphendula sincishisiwe sisuka ku-200ms saya ku-40-30ms. Futhi ngafinyelela esinqumweni esifanele kuphela.

Uhlelo lokusebenza lokuhamba ngebhayisikili oluthuthukisiwe noma lweseva yeklayenti olusekelwe kuhlaka lwe-C# .Net

Lahla ukuqaliswa kweseva kwamanje ku-Tcp bese ubhala kabusha yonke into ngaphansi kwe-Http. Manje iphrojekthi isezingeni lokuklama kabusha, kodwa ngokwezimiso ezihluke ngokuphelele zokusebenzisana. Ukusebenza kwamadivayisi kanye nesayithi kuyavunyelaniswa futhi kususwe iphutha futhi kunomqondo ofanayo, okunomehluko kuphela wokuthi amadivaysi awadingi ukukhiqiza amakhasi e-html.

isiphetho

"Ukungazi ifodi, ungalifaki ikhanda lakho emanzini" Ngicabanga ukuthi, ngaphambi kokuqala umsebenzi, kufanele ngabe ngizichaze ngokucacile izinjongo nezinjongo, futhi ngijule ocwaningweni lobuchwepheshe obudingekayo nezindlela zokuqaliswa kwazo kumakhasimende ahlukahlukene. Iphrojekthi isivele isizophothulwa, kodwa mhlawumbe ngizobuya ngizokhuluma ngokuthi ngizilungise kanjani izinto ezithile futhi. Ngifunde okuningi ngesikhathi sokuthuthukiswa, kodwa kuningi okufanele ngikufunde esikhathini esizayo. Uma ufunde kuze kube manje, ngiyabonga ngokufunda.

Source: www.habr.com