I study Rust: How I made UDP chat with Azul

I study Rust: How I made UDP chat with Azul Snake
. I tried cycles, collections, working with 3D Three.rs . I learned about ggez and Amethyst . This time I tried to make a client and server for a chat. For GUI used 3r3155. Azul 3r3673. . Just watched Conrod , Yew and 3r3354. Orbtk
. I tried multithreading, channels and working with the network. I took into account the mistakes of the previous article and tried to make this more detailed. For details, welcome under cat. Sources running on Windows 10 x64 3r31078.  3r31088. 3r31078.  3r31088. For network communication, I used UDP because I want to make my next project using this protocol and wanted to practice with it here. For the GUI, I quickly googled projects on Rust, looked at the basic examples for them, and I was hooked on Azul because it uses the Document Object Model and a style engine similar to CSS, and for a long time I was engaged in web development. In general, I chose the Framework subjectively. It is, for now, in deep alpha: scrolling does not work, input focus does not work, there is no cursor. In order to enter data into the text field, you need to hover the mouse on it and hold it right above it while typing. 3r3335. Read more 3r367. Actually, the most part of the article is the comments to the code. 3r31078.  3r31088. 3r31078.  3r31088. 3r31080. Azul 3r31081. GUI framework using functional style, DOM, CSS. Your interface consists of a root element, which has many descendants, which can have their own descendants such as, for example, in HTML and XML. The entire interface is created based on data from a single DataModel. In it all data is transferred to the view If anyone is familiar with ASP.NET, then Azul and its DataModel are like Razor and its ViewModel. Like HTML, you can bind functions to DOM element events. You can stylize elements using the CSS framework. This is not the same CSS as in HTML, but very similar to it. There is also a two-way binding like in Angular or MVVM in WPF, UWP. Read more at https://azul.rs/ . 3r31078.  3r31088. 3r31078.  3r31088. 3r31080. A brief overview of the other frameworks
 3r31088. 3r33939. Orbtk - Almost the same as Azul and also in deep alpha 3r3393919.  3r31088. 3r33939. Conrod - 3r361. Video
You can create cross-platform desktop applications. 3r3393919  3r31088. 3r33939. 3r366. Yew
- WebAssembly and similar to React. For web development. 3r3393919  3r31088.
3r31078.  3r31088. 3r31078.  3r31088. 3r31080. Customer

A structure in which helper functions are grouped to read and write to a 3r3-3971 socket. 3r33939. 3r33850. struct ChatService {}
3r31088. impl ChatService {
//1
fn read_data (socket: & Option
) -> Option 3r???. {
//2
let mut buf =[0u8; 4096]; 3r31088. match socket {
Some (s) => {
//3 3r31088. match s.recv (& mut buf) {
//4
Ok (count) => Some (String :: from_utf8 (buf[count].Into ())
.Expect ("can't parse to String")),
Err (e) => {
//5
println! ("Error {}", e); 3r31088. None
}
}
}
_ => None,
}
}
//6 3r31088. fn send_to_socket (message: String, socket: & Option
) {
match socket {
//7
Some (s) => {s.send (message.as_bytes ()). Expect ("can't send");}
_ => return,
}
}
}
3r31073.
 3r31088. 3r33939. We read data from socket
 3r31088. 3r33939. A buffer for data that will be read from the socket. 3r3393919  3r31088. 3r33939. Blocking call Here, the thread of execution stops until the data is read or timeout occurs. 3r3393919  3r31088. 3r33939. Get the string from the byte array in UTF8. 3r3393919  3r31088. 3r33939. We get here if the connection is broken by timeout or another error has occurred. 3r3393919  3r31088. 3r33939. Sends a string to the socket. 3r3393919  3r31088. 3r33939. We convert the string to bytes in UTF8 encoding and send data to the socket. Writing data to a socket is not blocking, i.e. The execution thread will continue its work. If the data could not be sent, then we interrupt the program with the message “can't send”. 3r3393919  3r31088. 3r? 3921. 3r31078.  3r31088.
A structure that groups functions for handling user-generated events and changes to our DataModel

3r33939. 3r33850. struct controllerler {r3r31088} //1
const TIMEOUT_IN_MILLIS: u64 = 2000; 3r31088. 3r31088. impl controller[
//2
fn send_pressed (app_state: & mut azul :: prelude :: AppState , _event: azul :: prelude :: WindowEvent ) -> azul :: prelude :: UpdateScreen {
//3 3r31088. let data = app_state.data.lock (). unwrap (); 3r31088. //4
let message = data.messaging_model.text_input_state.text.clone (); 3r31088. data.messaging_model.text_input_state.text = "" .into (); 3r31088. //5
ChatService :: send_to_socket (message, & data.messaging_model.socket); 3r31088. //6 3r31088. azul :: prelude :: UpdateScreen :: Redraw
}
//7
fn login_pressed (app_state: & mut azul :: prelude :: AppState , _event: azul :: prelude :: WindowEvent ) -> azul :: prelude :: UpdateScreen {
//8
use std :: time :: Duration; 3r31088. //9 3r31088. if let some (ref _s) = app_state.data.clone (). lock (). unwrap (). messaging_model.socket {
return azul :: prelude :: UpdateScreen :: DontRedraw; 3r31088.}
//10 3r31088. app_state.add_task (Controller :: read_from_socket_async, &[]); 3r31088. //11 app_state.add_daemon (azul :: prelude :: Daemon :: unique (azul :: prelude :: DaemonCallback (Controller :: redraw_daemon))); 3r31088. //12 r3r31088. let mut data = app_state.data.lock (). unwrap (); 3r31088. //13 3r31088. let local_address = format! ("???.1: {}", data.login_model.port_input.text.clone (). trim ()); 3r31088. //14 3r31088. let socket = UdpSocket :: bind (& local_address)
.expect (format! ("can't bind socket to {}", local_address) .as_str ()); 3r31088. //15 3r31088. let remote_address = data.login_model.address_input.text.clone (). trim (). to_string (); 3r31088. //16 3r31088. socket.connect (& remote_address)
.expect (format! ("can't connect to {}", & remote_address) .as_str ()); 3r31088. //17 3r31088. socket.set_read_timeout (Some (Duration :: from_millis (TIMEOUT_IN_MILLIS)))
.expect ("can't set time to read"); 3r31088. //18 3r31088. data.logged_in = true; 3r31088. //19 3r31088. data.messaging_model.socket = Option :: Some (socket); 3r31088. //20
azul :: prelude :: UpdateScreen :: Redraw
}
//21
fn read_from_socket_async (app_dаta: Arc
) {
//22 3r31088. let socket = Controller :: get_socket (app_data.clone ()); 3r31088. loop {3r31088. //23 3r31088. if let some (message) = ChatService :: read_data (& socket) {
//24 3r31088. app_data.modify (| state | {
//25
state.messaging_model.has_new_message = true;
//26 3r31088. state.messaging_model.messages.push (message);
) 3r31088.}
}
}
//27 3r31088. fn redraw_daemon (state: & mut ChatDataModel, _repres: & mut azul :: prelude :: Apprepres) -> (azul :: prelude :: UpdateScreen, azul :: prelude :: TerminateDaemon) {
//28 3r31088. if state.messaging_model.has_new_message {
state.messaging_model.has_new_message = false; 3r31088. (azul :: prelude :: UpdateScreen :: Redraw, azul :: prelude :: TerminateDaemon :: Continue)
} else {
(azul :: prelude :: UpdateScreen :: DontRedraw, azul :: prelude :: TerminateDaemon :: Continue)
}
}
//29 3r31088. fn get_socket (app_dаta: Arc 3r33232. Option 3r3-3595. {3r310103. //30 3r31088. let ref_model = & (app_data.lock (). unwrap (). messaging_model.socket);
//31 3r3r.???.???.???.???.??? .Some (s) => Some (s.try_clone (). Unwrap ()),
_ => None
} 3r31088.}
}
3r31072. 3r3r103 .
 3r31088. 3r33939. Timeout in milliseconds, after which the blocking read operation from the socket will be interrupted. 3r3393919  3r31088. 3r33939. The function works when the user wants to send a new message to the server. 3r3393919  3r31088. 3r33939. We get possession of mutex with our data model. This blocks the interface redraw stream until the mutex is released. 3r3393919  3r31088. 3r33939. Make a copy of the text entered by the user to pass it on and clear the text entry field. 3r3393919  3r31088. 3r33939. We send the message. 3r3393919  3r31088. 3r33939. We inform the Framework that after processing this event you need to redraw the interface. 3r3393919  3r31088. 3r33939. The function works when the user wants to connect to the server. 3r3393919  3r31088. 3r33939. We connect the structure to represent the length of time from the standard library. 3r3393919  3r31088. 3r33939. If we are already connected to the server, then we stop the execution of the function by telling the Framework that there is no need to redraw the interface. 3r3393919  3r31088. 3r33939. Add a task that will be executed asynchronously in a stream from the thread pool of the Azul Framework. Accessing the mutex with the data model blocks updating the UI until the mutex is released. 3r3393919  3r31088. 3r33939. Add a recurring task that runs in the main thread. Any lengthy computation in this daemon blocks interface updates. 3r3393919  3r31088. 3r33939. We get in possession muteks. 3r3393919  3r31088. 3r33939. We read the port entered by the user and create a local address based on it, we will listen. 3r3393919  3r31088. 3r33939. Create a UDP socket that reads packets arriving at the local address. 3r3393919  3r31088. 3r33939. We read the server address entered by the user. 3r3393919  3r31088. 3r33939. We tell our UDP socket to read packets only from this server. 3r3393919  3r31088. 3r33939. Set the timeout for a read operation from the socket. Writing to the socket occurs without waiting, i.e. we just write the data and notThere’s nothing, and a read operation from the socket blocks the stream and waits for data to be read. If you do not set the timeout, the read operation from the socket will wait indefinitely. 3r3393919  3r31088. 3r33939. We set the flag indicating that the user has already connected to the server. 3r3393919  3r31088. 3r33939. We transfer to the data model the created socket. 3r3393919  3r31088. 3r33939. We inform the Framework that after processing this event you need to redraw the interface. 3r3393919  3r31088. 3r33939. An asynchronous operation that runs in the thread pool of the Azul Framework. 3r3393919  3r31088. 3r33939. Get a copy of the socket from our data model. 3r3393919  3r31088. 3r33939. We are trying to read data from the socket. If you do not make a copy of the socket and directly wait here, until a message comes from the socket, which is in the mutex in our data model, then the whole interface will stop updating until we release the mutex. 3r3393919  3r31088. 3r33939. If we receive a message, then we change our data model. The modification does the same as lock (). Unwrap (), passing the result to the lambda and releasing the mutex after the lambda code ends. 3r3393919  3r31088. 3r33939. Set the flag, indicating that we have a new message. 3r3393919  3r31088. 3r33939. Add a message to the array of all chat messages. 3r3393919  3r31088. 3r33939. Repeated synchronous operation running in the main thread. 3r3393919  3r31088. 3r33939. If we have a new message, then we inform the Framework that we need to redraw the interface from scratch and continue the work of this daemon; otherwise, we will not draw the interface from the beginning, but we still call this Function in the next cycle. 3r3393919  3r31088. 3r33939. Creates a copy of our socket in order not to keep the mutex locked with our data model. 3r3393919  3r31088. 3r33939. We get ownership of the mutex and get a reference to the socket. 3r3393919  3r31088. 3r33939. Create a copy of the socket. Mutex will be released automatically when exiting the Function. 3r3393919  3r31088. 3r? 3921. 3r31078.  3r31088.

Asynchronous data processing and daemons in Azul

3r33939. 3r33850. //Problem - blocks UI :(
Fn start_connection (app_state: & mut AppState
, _Event: WindowEvent
) -> UpdateScreen {
//Add the asynchronous task 3rr1?032.
//Add the daemon
App_state.add_daemon (Daemon :: unique (DaemonCallback (start_daemon)));
UpdateScreen :: Redraw
}
3r31088. -> (UpdateScreen, TerminateDaemon) {
//Blocks the UI for ten seconds
Thread :: sleep (Duration :: from_secs (10));
State.counter + = 10000; 3r3r1088. (UpdateScreen :: Redraw, TerminateDaemon :: Continue)
}
Fn start_async_task (app_dаta: Arc
) {
//simulate slow load
App_data.modify (rein) //Blocks the UI for ten seconds
Thread :: sleep (Duration :: from_secs (10)); 3r31088. state.counter + = 1?000; 3r31088.}); 3r31088.}
3r31073. 3r31078.  3r31088. The daemon is always executed in the main thread, so blocking is inevitable there. With an asynchronous task, if you do, for example, there will be no lock for 10 seconds. 3r31078.  3r31088. 3r33939. 3r33850. fn start_async_task (app_dаta: Arc
) {
//Do not block the UI. We expect asynchronously. 3r31088. thread :: sleep (Duration :: from_secs (10)); 3r31088. app_data.modify (| state | {
state.counter + = 10000;
}); 3r31088.}
3r31073. 3r31078.  3r31088. The modify function calls lock () on the mutex with the data model, therefore it blocks the update of the interface during its execution. 3r31078.  3r31088. 3r31078.  3r31088.

Our styles are 3r3393971. 3r33939. 3r33850. const CUSTOM_CSS: & str = "
.row {height: 50px;}
.orange {
background:. linear-gradient (to bottom, # f6913? # f37335);
font-color: white;
border. -bottom: 1px solid # 8d8d8d;
} "; 3r31088. 3r31073. 3r31078.  3r31088.
Actually, Functions for creating our DOM for displaying it to the user. 3r33971. 3r33939. 3r33850. impl azul :: prelude :: Layout for ChatDataModel {
//1
fn layout (& self, info: azul :: prelude :: WindowInfo
) -> azul :: prelude :: Dom
{
//2
if self.logged_in {
self.chat_form (info)
} else {
self.login_form (info)
}
}
}
3r31088. impl ChatDataModel {
//3 3r31088. fn login_form (& self, info: azul :: prelude :: WindowInfo
) -> azul :: prelude :: Dom
{
//4
let button = azul :: widgets :: button :: Button :: with_label ("Login")
//5
.dom ()
//6 3r31088. .with_class ("row")
//7
.with_class ("orange")
//8
.with_callback (
azul :: prelude :: On :: MouseUp,
azul :: prelude :: Callback (Controller :: login_pressed)); 3r31088. 3r31088. //9 3r31088. let port_label = azul :: widgets :: label :: Label :: new ("Enter port to listen:")
.dom ()
.with_class ("row"); 3r31088. //10 3r31088. let port = azul :: widgets :: text_input :: TextInput :: new ()
//11 3r31088. .bind (info.window, & self.login_model.port_input, & self)
.dom (& self.login_model.port_input)
.with_class ("row"); 3r31088. 3r31088. //9 3r31088. let address_label = azul :: widgets :: label :: Label :: new ("Enter server address:")
.dom ()
.with_class ("row"); 3r31088. 3r31088. //10 3r31088. let address = azul :: widgets :: text_input :: TextInput :: new ()
//11 3r31088. .bind (info.window, & self.login_model.address_input, & self)
.dom (& self.login_model.address_input)
.with_class ("row"); 3r31088. 3r31088. //12 r3r31088. azul :: prelude :: dom :: new (azul :: prelude :: nodetyp :: div)
.with_child (port_label)
.with_child (port)
.with_child (address_label)
.with_child (address)
.with_child (button)
}
3r31088. //13 3r31088. fn chat_form (& self, info: azul :: prelude :: WindowInfo
) -> azul :: prelude :: Dom
{
//14 3r31088. let button = azul :: widgets :: button :: Button :: with_label ("Send")
.dom ()
.with_class ("row")
.with_class ("orange")
.with_callback (azul :: prelude :: On :: MouseUp, azul :: prelude :: Callback (Controller :: send_pressed)); 3r31088. //15 3r31088. let text = azul :: widgets :: text_input :: TextInput :: new ()
.bind (info.window, & self.messaging_model.text_input_state, & self)
.dom (& self.messaging_model.text_input_state)
.with_class ("row"); 3r31088. //12 r3r31088. let mut dom = azul :: prelude :: dom :: new (azul :: prelude :: nodetyp :: div)
.with_child (text)
.with_child (button); 3r31088. //16 3r31088. for i in & self.messaging_model.messages {
dom.add_child (azul :: widgets :: label :: Label :: new (i.clone ()). dom (). with_class ("row")); 3r31088.}
dom 3r31088.}
}
3r31073.
 3r31088. 3r33939. The function that creates the final DOM, and is called whenever the interface needs to be redrawn. 3r3393919  3r31088. 3r33939. If we are already connected to the server, then we show the form for sending and reading messages, otherwise we display the form for connecting to the server. 3r3393919  3r31088. 3r33939. Creates a form to enter data required to connect to the server. 3r3393919  3r31088. 3r33939. Create a button labeled Login. 3r3393919  3r31088. 3r33939. Convert it to a DOM object. 3r3393919  3r31088. 3r33939. Add a row class to it. 3r3393919  3r31088. 3r33939. Add css class orange to it. 3r3393919  3r31088. 3r33939. Add an event handler to click on the button. 3r3393919  3r31088. 3r33939. Create a text label with the text to display to the user and the css class row. 3r3393919  3r31088. 3r33939. Create a text field for entering text with text from the properties of our model and the css class row. 3r3393919  3r31088. 3r33939. Bind the text field to the property of our DataModel. This is a two-way binding. Now editing TextInput automatically changes the text in the property of our model and the reverse is also true. If we change the text in our model, the text in TextInput will change. 3r3393919  3r31088. 3r33939. Create a root DOM element in which we put our UI elements. 3r3393919  3r31088. 3r33939. Creates a form for sending and reading messages. 3r3393919  3r31088. 3r33939. Create a button with the text "Send" and css classes "row", "orange" and an event handler when it is clicked. 3r3393919  3r31088. 3r33939. Create a text entry field with two-way binding with the property of the model self.messaging_model.text_input_state and the css class “row”. 3r3393919  3r31088. 3r33939. Add text labels that display messages that were written in the chat. 3r3393919  3r31088. 3r? 3921. 3r31078.  3r31088.
Our model that stores the state of our interface. 3r33971. The Azul documentation says that it should store all application data, including the connection to the database, so I put a UDP socket in it. 3r33939. 3r33850. //1
#[derive(Debug)]3r31088. //2
struct ChatDataModel {
//3 3r31088. logged_in: bool,
//4
messaging_model: MessagingDataModel,
//5
login_model: LoginDataModel,
}
3r31088. #[derive(Debug, Default)]3r31088. struct LoginDataModel {
//6 3r31088. port_input: azul :: widgets :: text_input :: TextInputState,
//7
address_input: azul :: widgets :: text_input :: TextInputState,
}
3r31088. #[derive(Debug)]3r31088. struct MessagingDataModel {
//8
text_input_state: azul :: widgets :: text_input :: TextInputState,
//9 3r31088. messages: Vec
, 3r31088. //10 3r31088. socket: Option
, 3r31088. //11 3r31088. has_new_message: bool,
}
3r31073.
 3r31088. 3r33939. This will allow us to display our structure as a string in a pattern of the form {:?}
 3r31088. 3r33939. Our data model. In order to be able to use it in Azul. She must implement the treit Layout. 3r3393919  3r31088. 3r33939. Flag to check if the user is connected to the server or not. 3r3393919  3r31088. 3r33939. Model for displaying the form for sending messages to the server and saving messages received from the server 3r3393919  3r31088. 3r33939. Model to display the form to connect to the server. 3r3393919  3r31088. 3r33939. The port that the user entered. We will listen to it with our socket. 3r3393919  3r31088. 3r33939. The address of the server that the user entered. We will connect to it. 3r3393919  3r31088. 3r33939. User message. We will send it to the server. 3r3393919  3r31088. 3r33939. The message array that came from the server. 3r3393919  3r31088. 3r33939. The socket through which we communicate with the server.3r3393919  3r31088. 3r33939. Flag to check if we received a new message from the server. 3r3393919  3r31088. 3r? 3921. 3r31078.  3r31088.
And finally, the main entry point into the application. Starts a loop from GUI drawing and user input processing. 3r33971. 3r33939. 3r33850. pub fn run () {
//1
let app = azul :: prelude :: app :: new (ChatDataModel {
logged_in: false,
messaging_model: MessagingDataModel {
text_input_state: azul :: widgets :: text_input :: TextInputState :: new (""),
Messages: Vec :: new (),
Socket: None,
Has_new_message: false,
},
Login_model: LoginDataModel :: default (),
: default ()); 3r31088. //2
let mut style = azul :: prelude :: css :: native (); 3r31088. //3 3r31088. style.merge (azul :: prelude :: css :: from_str (CUSTOM_CSS) .unwrap ()); 3r31088. //4
let window = azul :: prelude :: window :: new (azul :: prelude :: windowCreateOptions :: default (), style) .unwrap (); 3r31088. //5
app.run (window) .unwrap (); 3r31088.}
3r31073.
 3r31088. 3r33939. Create an application with starting data. 3r3393919  3r31088. 3r33939. Styles used by the application by default. 3r3393919  3r31088. 3r33939. Add our own styles to them. 3r3393919  3r31088. 3r33939. Create a window that will display our application. 3r3393919  3r31088. 3r33939. Run the application in this window. 3r3393919  3r31088. 3r? 3921. 3r31078.  3r31088. 3r31078.  3r31088. 3r31080. Server 3r31081.
The main entry point to the app is 3r3393971. Here we usually have a console application. 3r33939. 3r33850. pub fn run () {
//1
let socket = create_socket (); 3r31088. //2
let (sx, rx) = mpsc :: channel (); 3r31088. //3 3r31088. start_sender_thread (rx, socket.try_clone (). unwrap ()); 3r31088. loop {3r31088. //4
sx.send (read_data (& socket)). unwrap (); 3r31088.}
}
3r31073.
 3r31088. 3r33939. Create a socket. 3r3393919  3r31088. 3r33939. Create a one-way channel with one sx message sender and multiple rx recipients. 3r3393919  3r31088. 3r33939. We start sending messages to all recipients in a separate thread. 3r3393919  3r31088. 3r33939. We read data from the socket and send it to the stream that sends messages to clients connected to the server. 3r3393919  3r31088. 3r? 3921. 3r31078.  3r31088.
The function to create a stream to send messages to customers

3r33939. 3r33850. fn start_sender_thread (rx: mpsc :: Receiver <(Vec , SocketAddr)>, socket: UdpSocket) {
//1
thread :: spawn (move || {
//2
let mut addresses = Vec ::
:: new ();
//3
loop {
//4
let (bytes , pre) = rx.recv (). unwrap ();
//5
if! addresses.contains (& pre) {
println! ("{} connected to server", pre);
pre. push (pre.clone ());
}
//6
let result = String :: from_utf8 (bytes)
.expect ("can't parse to String") 3r3r8810. .trim ()
.to_string ();
println! ("received {} from {}", result, pre);
//7
let message = format! ((FROM: {} MESSAGE: {} ", pre , result); 3r31088. Let data_to_send = message.as_bytes ();
//8
addresses
.iter ()
.for_each (| s | {
//9
socket.send_to (data_to_send, s)
//10
.expect (format! ("can't send to {}", pre) .as_str ( )); 3r31088.}); 3r31088.}
}); 3r31088.}
3r31073.
 3r31088. 3r33939. Launch a new thread. move means that variables are taken over by lambda and flow, respectively. More specifically, our new thread will “swallow” the rx and socket variables. 3r3393919  3r31088. 3r33939. The collection of addresses, the clients connected to us. We will send all our messages to all of them. In general, in a real project, it would be necessary to do the processing of disconnecting the client from us and removing its address from this array. 3r3393919  3r31088. 3r33939. Run an infinite loop. 3r3393919  3r31088. 3r33939. We read data from the channel. Here the stream will be blocked until new data arrives. 3r3393919  3r31088. 3r33939. If this address is not in our array, then add it there. 3r3393919  3r31088. 3r33939. We decode the UTF8 string from the byte array. 3r3393919  3r31088. 3r33939. We create an array of bytes that we are going to send to all our clients. 3r3393919  3r31088. 3r33939. We pass through the collection of addresses and send the data to each. 3r3393919  3r31088. 3r33939. The write operation in the UDP socket is non-blocking, so here the Function will not wait until the message arrives at the receiver and is executed almost instantly. 3r3393919  3r31088. 3r33939. expect in case of an error will make an emergency exit from the program with the specified message. 3r3393919  3r31088. 3r? 3921. 3r31078.  3r31088.

The function creates a socket based on user input. 3r33971. 3r33939. 3r33850. const TIMEOUT_IN_MILLIS: u64 = 2000; 3r31088. 3r31088. fn create_socket () -> UdpSocket {
println! ("Enter port to listen"); 3r31088. //1
let local_port: String = read! ("{} n"); 3r31088. let local_address = format! ("???.1: {}", local_port.trim ()); 3r31088. println! ("server address {}", & local_address); 3r31088. //2
let socket = UdpSocket :: bind (& local_address.trim ())
.expect (format! ("can't bind socket to {}", & local_address) .as_str ()); 3r31088. //3 3r31088. socket.set_read_timeout (Some (Duration :: from_millis (TIMEOUT_IN_MILLIS)))
.expect ("can't set time to read"); 3r31088. //4
socket
}
3r31073.
 3r31088. 3r33939. We read the port that our server will listen to and create a local server address based on it. 3r3393919  3r31088. 3r33939. Create a UDP socket listening on this address. 3r3393919  3r31088. 3r33939. Set the timeout for the read operation. The read operation is blocking and it will block the stream until new data arrives or timeout occurs. 3r3393919  3r31088. 3r33939. We return the created socket from the function. 3r3393919  3r31088. 3r33939. The function reads data from the socket and returns it along with the sender's address. 3r3393919  3r31088. 3r? 3921. 3r31078.  3r31088.
Function to read data from the socket

3r33939. 3r33850. fn read_data (socket: & UdpSocket) -> (Vec
, SocketAddr) {
//1
let mut buf =[0u8; 4096]; 3r31088. //2
loop {3r31088. match socket.recv_from (& mut buf) {
//3 3r31088. Ok ((count, address)) => {
//4
return (buf[count].into (), address); 3r31088.}
//5
Err (e) => {
println! ("Error {}", e); 3r31088. continue; 3r31088.}
}; 3r31088.}
}
3r31073.
 3r31088. 3r33939. Buffer - a place where we will read the data. 3r3393919  3r31088. 3r33939. Starts a loop that will run until valid data has been read. 3r3393919  3r31088. 3r33939. We get the number of bytes read and the sender's address. 3r3393919  3r31088. 3r33939. We make a slice of the array from its beginning to the quantities read bytes and convert it into a vector of bytes. 3r3393919  3r31088. 3r33939. If there is a timeout or other error, then go to the next iteration of the cycle. 3r3393919  3r31088. 3r? 3921. 3r31078.  3r31088. 3r31080. Pro layers in the app 3r31081. 3r39595.
Oftop: A small educational program for the two Junas at work. I decided to post here, can someone come in handy. Joona Sharpisty poet examples in C # and talking about ASP.NET is [/b]
So, there was nothing to do, it was in the evening, and I decided to write a small educational program for Artyom and Victor. Here we go. 3r31078.  3r31088. Actually, I added it here because I can only write articles once a week, but I already have some material and next week I wanted to upload something else. 3r31078.  3r31088. Usually, the application is divided into layers. In each layer there are objects that implement the behavior characteristic of the layer in which they are located. So. Here are the layers. 3r31078.  3r31088. 3r31078.  3r31088.
 3r31088. 3r33939. Presentation layer 3r3393919  3r31088. 3r33939. Business logic layer. 3r3393919  3r31088. 3r33939. Data access layer 3r3393919  3r31088. 3r33939. Entities (User, Animal, etc.)
 3r31088. 3r? 3921. 3r31078.  3r31088. Each layer can contain its DTO and completely arbitrary classes with arbitrary methods. The main thing is that they perform the functionality associated with the layer in which they are located. In simple applications, some of the layers may be missing. For example, the presentation layer can be implemented through the MVC, MVP, MVVM pattern. That is absolutely not necessary. The main thing is that the classes that are in this layer implement the functionality assigned to the layer. Remember, patterns and architecture are only guidelines, not instructions. The pattern and architecture is not a law, it is a tip. And so, let's look at each layer on the example of a standard ASP.NET application using the standard Entity Framework. 3r31078.  3r31088. 3r31078.  3r31088.

Layer

view. We have MVC here. This is the layer that provides user interaction. Commands come here and these users get from here. Not necessarily people, if we have an API, then our user is another program. Machines communicate with machines. 3r31078.  3r31088. 3r31078.  3r31088.

Business logic layer

Here, usually, classes call Service, for example, UserService, although there may be anything at all. Just a set of classes with methods. The main thing is to make calculations and calculations of our application. This is the thickest and most bulky layer. Here most of the code and the various classes. This, in fact, is our application. 3r31078.  3r31088. 3r31078.  3r31088.

The data access layer

Usually we have here EF implements the patterns Unit Of Work and Repository. Yes, DbContext is, one might say, Unit Of Work, and DB sets it is Repository. This is, in fact, the place where we put the data and where we get it from. Regardless of whether the data source is a database, an API of another application, a cache in Memory, or just some random number generator. Any data source. 3r31078.  3r31088. 3r31078.  3r31088.
Entities 3r3393971. Yes, just any User, Animal and so on. One important note - they may have some behavior characteristic only for them. For example: 3r3727. class User
{
public string FirstName {get; set;}
public string LastName {get; set;}
public string FullName
{
get
{
return FirstName + "" + LastName; 3r31088.}
}
3r31088. public bool Equal (User user)
{
return this.FullName == user.FullName; 3r31088.}
}
3r31073. 3r31078.  3r31088.
Well, quite a simple example. Shoby was. 3r33971. 3r33939. using System; 3r31088. using System.Collections.Generic; 3r31088. using System.Text; 3r31088. 3r31088. //Entities
class User
{
public int Id {get; set;}
public string Name {get; set;}
}
3r31088. //Data Access Layer
3r31088. class UserRepository
{
private readonly Dictionary
_db; 3r31088. 3r31088. public UserRepository ()
{
_db = new Dictionary
(); 3r31088.}
3r31088. public User Get (int id)
{
return _db[id]; 3r31088.}
3r31088. public void Save (User user)
{
_db[user.Id]= user; 3r31088.}
}
3r31088. //Business Logic Layer
3r31088. class UserService
{
private readonly UserRepository _repo; 3r31088. private int _currentId = 0; 3r31088. public UserService ()
{
_repo = new UserRepository (); 3r31088.}
3r31088. public void AddNew ()
{
_currentId ++; 3r31088. var user = new User
{
Id = _currentId,
Name = _currentId.ToString ()
}; 3r31088. _repo.Save (user); 3r31088.}
3r31088. public string GetAll ()
{
StringBuilder sb = new StringBuilder (); 3r31088. 3r31088. for (int i = 1; i <= _currentId; i++)
{
sb.AppendLine ($ "Id: {i} Name: {_repo.Get (i) .Name}"; 3r31088.} 3r3r1088. return sb.ToString () ;
}
} 3r31088. 3r31088. 3r31088. 3r31088. Public string RunExample () 3r31088. {3r310888 _service.AddNew ();
._service.AddNew (); 3r31088.D. 3r31088. Namespace ConsoleApp1 3r?10388. {3-3?3888. Class Program 3r?31088. {3r?31088. Static void Main (string[]Args) 3r?10388. {
Var controller = 4), you have to have a default account and you have to have a default account value for the user; onsole.WriteLine (controller.RunExample ()); 3r31088. Console.ReadLine (); 3r31088.}
}
}
3r31073.
3r31078.  3r31088. 3r31078.  3r31088. 3r31080. P.S. 3r31081. Well, I want to say thanks to my Nastya for correcting grammatical errors in the article. Yes, Nastya, you are not in vain with a red diploma and generally cool. I love you <3. 3r31088. 3r31088. 3r31088.
3r31088.
+ 0 -

Add comment