entry
Nagsugod ang tanan sa dihang gisugyot sa usa ka kauban nga maghimo ako usa ka gamay nga serbisyo sa web. Kini unta sama sa usa ka tinder, apan alang sa IT hangout. Ang pag-andar yano ra, nagparehistro ka, nagpuno sa usa ka profile ug nagpadayon sa panguna nga punto, nga mao, pagpangita sa usa ka interlocutor ug pagpalapad sa imong mga koneksyon ug paghimo bag-ong mga kaila.
Dinhi kinahanglan ko nga maglikay ug magsulti gamay bahin sa akong kaugalingon, aron sa umaabot mas klaro kung ngano nga gihimo nako ang ingon nga mga lakang sa pag-uswag.
Sa higayon nga akong gihuptan ang posisyon sa usa ka Teknikal nga Artist sa usa ka studio sa dula, ang akong kasinatian sa C # programming gibase lamang sa pagsulat sa mga script ug mga gamit alang sa Unity ug, dugang pa niini, paghimo og mga plugins alang sa ubos nga lebel nga trabaho sa mga android device. Sa gawas niining kalibutana, wala pa ako makapili ug unya nakakaplag sa ingon nga oportunidad.
Bahin 1. Frame Prototyping
Nakadesisyon kung unsa kini nga serbisyo, nagsugod ako sa pagpangita alang sa mga kapilian alang sa pagpatuman. Ang labing kadali nga paagi mao ang pagpangita sa usa ka matang sa andam nga solusyon, diin, sama sa usa ka bukaw sa usa ka globo, mahimo nimong ibira ang among mga mekaniko ug ibutang ang tibuuk nga butang alang sa pagsaway sa publiko.
Apan dili kini makapaikag, wala koy nakita nga hagit ug pagbati niini, ug busa nagsugod ako sa pagtuon sa mga teknolohiya sa web ug mga pamaagi sa pagpakig-uban kanila.
Ang pagtuon nagsugod pinaagi sa pagtan-aw sa mga artikulo ug dokumentasyon sa C # .Net. Dinhi nakit-an nako ang lainlaing mga paagi aron matuman ang buluhaton. Adunay daghang mga mekanismo sa pagpakig-uban sa network, gikan sa hingpit nga mga solusyon sama sa ASP.Net o Azure nga mga serbisyo, ngadto sa direktang interaksyon sa mga koneksyon sa TcpHttp.
Nahimo ang una nga pagsulay sa ASP, gikansela dayon nako kini, sa akong opinyon lisud kaayo ang usa ka desisyon alang sa among serbisyo. Dili namo gamiton bisan ang ikatulo nga bahin sa mga kapabilidad niini nga plataporma, mao nga gipadayon nako ang akong pagpangita. Ang pagpili mitungha tali sa TCP ug Http client-server. Dinhi, sa HabrΓ©, nakit-an nako ang usa ka artikulo bahin sa , nga nakolekta ug nasulayan nga, nakahukom ko nga mag-focus sa pagpakig-uban sa mga koneksyon sa TCP, sa pipila ka rason naghunahuna ko nga ang http dili motugot kanako sa paghimo og cross-platform nga solusyon.
Ang unang bersyon sa server naglakip sa pagdumala sa mga koneksyon, pag-alagad sa static nga web page content, ug lakip ang user database. Ug alang sa mga nagsugod, nakahukom ko nga magtukod usa ka functional alang sa pagtrabaho kauban ang site, aron sa ulahi mahimo nako ihigot ang pagproseso sa aplikasyon sa android ug ios dinhi.
Ania ang pipila ka code
Ang nag-unang thread nga nagdawat sa mga kliyente sa usa ka walay katapusan nga loop:
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);
}
}
}
Ang tigdumala sa kliyente mismo:
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();
}
}
}
Ug ang unang database nga gitukod sa lokal nga SQL:using System; using System.Data.Linq; namespace ClearServer { class DatabaseWorker { private static DatabaseWorker instance; public static DatabaseWorker GetInstance { get { if (instance == null) instance = new DatabaseWorker(); return instance; } } private DatabaseWorker() { string connectionStr = databasePath; using (DataContext db = new DataContext(connectionStr)) { Table<User> users = db.GetTable<User>(); foreach (var item in users) { Console.WriteLine(quot;{item.login} {item.password}");
}
}
}
}
}
Sama sa imong makita, kini nga bersyon lahi kaayo sa usa sa artikulo. Sa tinuud, ang pagkarga lamang sa mga panid gikan sa usa ka folder sa kompyuter ug ang database ang gidugang dinhi (nga, sa tinuud, wala molihok sa kini nga bersyon, tungod sa dili husto nga arkitektura sa koneksyon).Kapitulo 2
Pagkahuman sa pagsulay sa server, nakahinapos ako nga kini usa ka maayong solusyon (spoiler: dili), alang sa among serbisyo, mao nga ang proyekto nagsugod sa pag-angkon og lohika.
Hinay-hinay, nagsugod pagtungha ang mga bag-ong module ug milapad ang gamit sa server. Nakakuha ang server og test domain ug Ssl pag-encrypt sa koneksyon.Usa ka gamay nga code nga naghulagway sa lohika sa server ug sa pagproseso sa mga kliyente
Usa ka updated nga bersyon sa server, lakip ang paggamit sa usa ka sertipiko.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(); } } }Ingon usab usa ka bag-ong tigdumala sa kliyente nga adunay pagtugot pinaagi sa 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);
}}
}
Apan tungod kay ang server nagtrabaho lamang sa usa ka koneksyon sa TCP, gikinahanglan ang paghimo og module nga makaila sa konteksto sa hangyo. Nakahukom ko nga ang usa ka parser angay dinhi nga magbungkag sa hangyo gikan sa kliyente ngadto sa lain nga mga bahin diin ako makig-uban aron mahatagan ang kliyente sa gikinahanglan nga mga tubag.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;
}
}
}
Ang diwa niini anaa sa kamatuoran nga sa tabang sa regular nga mga ekspresyon sa pagbungkag sa hangyo ngadto sa mga bahin. Nakadawat kami usa ka mensahe gikan sa kliyente, pilia ang una nga linya, nga adunay sulud nga pamaagi ug gihangyo ang url. Dayon atong basahon ang mga ulohan, nga atong gisakyan ngadto sa usa ka han-ay sa porma nga HeaderName = Content, ug pangitaon usab, kon aduna man, ang kauban nga sulod (pananglitan, querystring) nga atong gimaneho usab ngadto sa susamang han-ay. Dugang pa, nahibal-an sa parser kung gitugutan ang kasamtangan nga kliyente ug gitipigan ang iyang datos. Ang tanan nga mga hangyo gikan sa awtorisado nga mga kliyente adunay usa ka awtorisasyon nga hash, nga gitipigan sa mga cookies, salamat nga posible nga mabulag ang dugang nga lohika sa trabaho alang sa duha nga mga lahi sa mga kliyente ug hatagan sila sa husto nga mga tubag.Aw, usa ka gamay, nindot nga bahin nga kinahanglan ibalhin sa usa ka bulag nga module, pag-convert sa mga hangyo sama sa "site.com/@UserName" ngadto sa dinamikong nahimo nga mga panid sa gumagamit. Human sa pagproseso sa hangyo, ang mosunod nga mga modulo magsugod.
Kapitulo 3. Pag-instalar sa handlebar, pag-lubricate sa kadena
Sa diha nga ang parser nahuman, ang handler moabut sa pagdula, nga naghatag dugang nga mga panudlo sa server ug nagbahin sa kontrol sa duha ka bahin.
simple nga 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); }; } } }Sa tinuud, adunay usa ra nga tseke alang sa pagtugot sa tiggamit, pagkahuman magsugod ang pagproseso sa hangyo.
Mga Kontroler sa Kliyente
Kung ang tiggamit dili awtorisado, nan alang kaniya ang pag-andar gibase lamang sa pagpakita sa mga profile sa tiggamit ug sa bintana sa pagparehistro sa pagtugot. Ang kodigo alang sa usa ka awtorisado nga tiggamit parehas ra tan-awon, mao nga wala akoy nakita nga hinungdan nga doblehon kini.Dili awtorisado nga tiggamit
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;}
}
}
}
Ug siyempre, ang user kinahanglan nga makadawat sa pipila ka mga sulod sa mga panid, mao nga alang sa mga tubag adunay mosunod nga module, nga mao ang responsable sa pagtubag sa usa ka hangyo alang sa mga kapanguhaan.MagsusulatController
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":
returnquot;{Header} text/html";
case ".css":
returnquot;{Header} text/css";
case ".js":
returnquot;{Header} text/javascript";
case ".jpg":
case ".jpeg":
case ".png":
case ".gif":
returnquot;{Header} image/{extension}";
default:
if (extension.Length > 1)
{
returnquot;{Header} application/" + extension.Substring(1);
}
else
{
returnquot;{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();
}
}
}
Apan aron ipakita sa tiggamit ang iyang profile ug mga profile sa ubang mga tiggamit, nakahukom ko nga gamiton ang RazorEngine, o bahin niini. Naglakip usab kini sa pagdumala sa dili maayo nga mga hangyo ug pag-isyu sa angay nga error code.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(); } } } }Ug siyempre, aron ang pag-verify sa mga awtorisado nga tiggamit magtrabaho, gikinahanglan ang pagtugot. Ang module sa pagtugot nakig-uban sa database. Ang datos nga nadawat gikan sa mga porma sa site gi-parse gikan sa konteksto, ang tiggamit maluwas ug makadawat og cookies ug pag-access sa serbisyo isip balos.
Module sa pagtugot
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);
}
}
}
}
Ug ingon niini ang hitsura sa database: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;
}
}
}
}
Ug ang tanan molihok sama sa orasan, awtorisasyon ug pagrehistro nga trabaho, ang minimum nga pag-andar sa pag-access sa serbisyo magamit na ug oras na aron magsulat usa ka aplikasyon ug ihigot ang tibuuk nga butang sa mga nag-unang gimbuhaton diin nahimo ang tanan.Kapitulo 4
Aron makunhuran ang gasto sa pagtrabaho sa pagsulat sa duha ka aplikasyon alang sa duha ka platform, nakahukom ko nga maghimo usa ka cross-platform sa Xamarin.Forms. Pag-usab, salamat sa kamatuoran nga kini anaa sa C #. Ang paghimo sa usa ka aplikasyon sa pagsulay nga nagpadala ra sa datos sa server, nakadagan ako sa usa ka makapaikag nga higayon. Alang sa usa ka hangyo gikan sa aparato, alang sa kalingawan, gipatuman ko kini sa HttpClient ug gilabay kini sa server nga HttpRequestMessage nga adunay sulud nga datos gikan sa porma sa pagtugot sa format nga json. Sa walay pagpaabut sa bisan unsa nga partikular, akong giablihan ang server log ug nakakita sa usa ka hangyo gikan sa device uban sa tanan nga mga data didto. Gaan nga pagkabuang, kaamgohan sa tanan nga nahimo sa miaging 3 ka semana sa luya nga gabii. Aron masusi ang pagkahusto sa gipadala nga datos, nag-assemble ko og test server sa HttpListner. Pagkadawat sa sunod nga hangyo nga naa na niini, gilain ko kini sa usa ka pares nga linya sa code, nakuha ang datos sa KeyValuePair gikan sa porma. Ang pag-parse sa pangutana gikunhoran ngadto sa duha ka linya.
Nagsugod ako sa pagsulay sa dugang, wala kini gihisgutan kaniadto, apan sa miaging server gipatuman gihapon nako ang usa ka chat nga gitukod sa mga websocket. Nagtrabaho kini og maayo, apan ang prinsipyo sa interaksyon pinaagi sa Tcp makapaguol, sobra nga sobra ang kinahanglan nga himoon aron sa husto nga pagtukod sa interaksyon sa duha ka tiggamit sa pag-log sa mga sulat. Naglakip kini sa pag-parse sa usa ka hangyo alang sa pagbalhin sa koneksyon ug pagkolekta sa usa ka tubag gamit ang protocol sa RFC 6455. Busa, sa test server, nakahukom ko nga maghimo og yano nga koneksyon sa websocket. Puro alang sa interes.
Koneksyon sa 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(); } } } } }Ug kini nagtrabaho. Ang server mismo ang nagpahimutang sa koneksyon, nakamugna og tubag nga yawe. Dili ko kinahanglan nga maglainlain ang pag-configure sa pagrehistro sa server pinaagi sa ssl, igo na nga ang sistema adunay usa ka sertipiko nga na-install sa gikinahanglan nga pantalan.
Sa kilid sa device ug sa kilid sa site, duha ka kliyente ang nagbayloay og mga mensahe, kining tanan na-log. Walay dagkong mga parser nga nagpahinay sa server, walay bisan usa niini ang gikinahanglan. Ang oras sa pagtubag gikunhoran gikan sa 200ms ngadto sa 40-30ms. Ug nakaabot ko sa bugtong husto nga desisyon.
Ilabay ang kasamtangan nga pagpatuman sa server sa Tcp ug isulat pag-usab ang tanan ubos sa Http. Karon ang proyekto naa sa yugto sa pagdesinyo pag-usab, apan sumala sa hingpit nga lainlaing mga prinsipyo sa interaksyon. Ang operasyon sa mga himan ug sa site gi-synchronize ug gi-debug ug adunay komon nga konsepto, nga adunay bugtong kalainan nga ang mga himan dili kinahanglan nga makamugna og mga panid sa html.
konklusyon
"Wala nahibal-an ang ford, ayaw itulod ang imong ulo sa tubig" Sa akong hunahuna, sa wala pa magsugod ang trabaho, kinahanglan nako nga mas tin-aw nga gihubit ang mga katuyoan ug katuyoan, ingon man usab sa pagsusi sa mga kinahanglanon nga teknolohiya ug pamaagi alang sa ilang pagpatuman sa lainlaing mga kliyente. Ang proyekto hapit na mahuman, apan tingali mobalik ako aron hisgutan kung giunsa nako pag-usab ang pipila ka mga butang. Daghan kog nakat-onan atol sa proseso sa pag-uswag, apan daghan pa ang angayng makat-unan sa umaabot. Kung nakabasa ka hangtod karon, salamat sa pagbasa.
Source: www.habr.com

