I read one of your posts about how difficult it was to start and at one point you didn't know if UA-cam was for you. I'm glad that you carried on. You have a cool channel. You are a smart man, and you are a creative programmer. Keep it up and stay happy.
Yeah, I'm in college. Fell in love with programming, and cannot stop researching it. I even got used to sleeping every other day to get more hours in the week to study. This one was a bit daunting, but after about 5 days of solid network programming for windows, and making a simple client and server, this one is finally making sense, as all of your videos do, if not the first time, then the second or fifth time lol.. Ur awesome man, I appreciate everything you do, my university ain't teaching me half of what you do. I am becoming a better programmer, particularly in part by your videos specifically. Thanks! @@javidx9
Hello! Due to some IRL scheduling, I've brought forward next weeks video to now! This does mean there will be a gap before Part#3. Anyway, this video and the accompanying code is enough to start tinkering with in the meantime should you choose to. Though be aware it isnt ready for production - there is no security, and as its incomplete, it consumes 100% processor, and there is a memory leak too.
@@Ryan-xq3kl the fact that your game is 3D or 2D doesn't decides your networking connection. Your networking code is mainly defined by time and stability requirements
ua-cam.com/video/UbjxGvrDrbw/v-deo.html You have a bug: net_server.h:112: m_deqConnections.erase(.... - it will remove nothing, as client isn't a reference, so the shared_ptr in deque wasn't changed by previous lane, and it still contains a valid ptr.
Two things: 1. I believe there's an error at 29:00 regarding checking whether we should read the body. It checks if header.size>0, but recall that header.size contains the size of the whole message (the header + the body, see: Part 1, 33:57). So in ServerPing scenario, the ping message should consist of 16 bytes (8 B header and 8 B body). SimpleClient writes a 8-byte body, but sets header.size to be 16. So the SimpleServer expects 16 bytes of body, and since only 8 are sent, it gets stuck. Surprisingly the initial ServerAccept message was received correctly. It's because when we set header.id to ServerAccept, we did not update the header.size and left it at 0. I think the simplest way to correct it would be to correct message& operator >, and replace `msg.header.size = msg.size()` with `msg.header.size = msg.body.size()`. 2. This 'Windows-way' to read keys pressed (around 40:00) is kind of discouraging Linux users, since it is not that easy to achieve sth, similiar in Linux, as there are no direct equivalents of GetAsyncKeyState(). It is however possible to have a solution working on both platforms, and thanks to asio itself! I adapted the solution: stackoverflow.com/questions/52308998/read-from-keyboard-using-boost-async-read-and-posixstream-descriptor to react to characters '1' and '3' (of course, reading from STDIN requires confirming the input with Enter, while the Windows solution reacts directly to pressed keys). One more thing would be to create additional thread to asynchronously start io_service.run().
Nice catch! For the first issue, I think it would be better to change ReadHeader to correctly account for the header size instead of changing how we define header size entirely. To do this, just change 'if(m_msgTemporaryIn.header.size > 0' to 'if(m_msgTemporaryIn.header.size > 8', and change the following line from 'm_msgTemporaryIn.body.resize(m_msgTemporaryIn.header.size)' to 'm_msgTemporaryIn.body.resize(m_msgTemporaryIn.header.size - 8)'. This way, we keep the interpretation of header size consistent with how it was previously defined (header + body). By changing the > operators, it changes size's definition to be just the size of the payload.
Hey David! I recently came across your channel by accident, and I hardly understand anything, but you are so calm and clever, that your videos are kind of magnetic. Remember that it's not just your content that is attracting audience.
Even as a very experienced modern C++ softy just wanting to speed date the ASIO API I've really found this to be an excellent series. First class tutorial and explanation.
21:10 - probably use of 'std::numeric_limits::max()' instead of -1 will be warning less at some compilers. 22:53 - folks, try to change port if some one of visitor of this channel got an exception at the binding (WSAEACCES at Windows) while execution of Server constructor (actually basic_socket_acceptor). In my case 6000 was fine instead 60000. 23:00 - this actually offtop for this video, however if you press cancel (for example you not an administrator of computer where you develop this program and do not know password of first one), and re-run program from Visual Studio you can still connect at putty. 25:40 - in section you call critical, for some compilers (CLang) order must be same like in member list, and m_nOwnerType should be too, at least with default value. Otherwise some compiler show warning here. 38:35 - major interesting here to make constructor and destructor of client_interface class public. They was left with default access (private) at 53:17 in part 1. Red underline at 'c' variable in video also indicate that moment. 41:44 | 44:34 - send only in connection class. So should be 'm_connection->Send(msg);' instead 'Send(msg);'. That moment already fixed in source from GitHub. Unfortunately video version of code do not grant full access to possibility (answer from server if showed at client - do that only once) that was show in this part, probably according to off frame editing, so source for GitHub should help with that.
I tried asio in the past for a simple networked application. There's a lot of complexity here, specifically having each task reprime the state machine seems odd. But I got it all working. I appreciate your explanation. It makes some of the things I didn't fully understand clearer. It also strikes me that there are similarities between this design and the actor pattern.
*Summary* This video focuses on building a functioning client-server system with ASIO and the framework outlined in Part 1. Here's a breakdown: *1. Server Functionality & Design* (1:09) * The server must handle: * Accepting client connections (1:14) * Handling client disconnections (2:10) * Implementing game logic (2:16) * An asynchronous `asio::acceptor` (10:38) object continuously listens for connections. * The server needs a task to keep the ASIO context alive: continuously wait for and handle client connections (10:38) *2. `Server` Interface* (1:09) * A template class designed for inheritance by user's application logic. (3:00) * Contains: * An ASIO context shared by all connected clients (10:20) * A single thread for the context. (10:25) * An `asio::acceptor` object to handle connections. (10:38) * A deck to store connected client `Connection` objects. (15:54) * An ID counter for assigning unique IDs to clients. (10:43) * A `queue_incoming_messages` (Threadsafe Queue of `OwnedMessage` objects) to hold received messages (10:08) * Key functions: * `Start()` (11:59): Creates a task to wait for connections and starts the ASIO context thread. * `Stop()` (13:08): Stops the ASIO context and joins the thread. * `WaitforClientConnection()` (13:32): An *asynchronous* task run by the ASIO context that waits for incoming connections using `asio::acceptor`. * `OnClientConnect()` (15:32): Called when a client attempts to connect, allowing the server to approve or deny it (customizable by the user). * `OnClientDisconnect()` (18:11): Called when a client disconnects. * `OnMessage()` (19:52): Called from within `Update()` (20:12) to handle messages in the incoming message queue (customizable by the user). * `Update()` (20:12): Processes messages from the incoming queue, calling `OnMessage()` for each. Users can control the number of messages processed per call to `Update()`. * `SendToClient()` (8:55): Sends a message to a specific client (using their ID). * `MessageAllClients()` (9:00): Sends a message to all connected clients (optionally excluding a specific client). *3. `Connection` Object* (24:14) * A template class representing a connection to a client (whether created by the server or by a client). * Includes: * An `owner` field (using `Owner` enum class) to distinguish between server-owned and client-owned connections. (24:26) * A socket (`sock`) (24:57) * References to the ASIO context and the relevant message queue (server's or client's) (24:45, 25:02). * A unique ID (`id`) if owned by a server. (25:54) * Key *asynchronous* tasks executed by ASIO: * `ReadHeader()` (27:54): Reads a message header from the socket. * `ReadBody()` (29:24): Reads a message body based on size indicated in the header. * `WriteHeader()` (31:30): Writes a message header to the socket. * `WriteBody()` (32:22): Writes a message body to the socket. * `AddToIncomingMessageQueue()` (30:16): Adds a completed message to the appropriate message queue, and re-primes the ASIO context to read the next header. * `Send()` (33:13): Called by either the server or client to send a message. Uses ASIO's `post()` to add a task to write the message to the socket (avoiding concurrent header/body writes). * `Disconnect()` (35:03): Uses ASIO's `post()` to add a task to close the socket cleanly. *4. `Client` Interface* (35:35) * Template class with most implementation already present from Part 1. * Uses an `asio::resolver` (36:25) to translate a domain name into an IP address/endpoint. * Key function: `Connect()` (35:59) now fully implemented. It resolves the host address, creates a `Connection` object (client-owned) (37:02), starts the ASIO context thread (37:29), and then calls `Connection::ConnectToServer()`. *5. Example: Ping Server and Broadcasting a Message* (38:37) * This part includes modifications to the client and server examples from Part 1 to showcase sending and receiving custom messages: * The client can now: * Send "Server Ping" messages with timestamps for calculating round-trip time. * Send a message to the server asking it to broadcast a message to all other clients. * The server responds accordingly, including: * Reflecting the "Server Ping" messages. * Receiving the broadcast request and distributing the message to all other clients. *Key Improvements:* * *Robust error handling:* Network failures and disconnections are detected and managed to prevent application crashes. * *Asynchronous design:* Network operations are handled by the ASIO context in a background thread, allowing the application logic to continue without blocking. * *User-friendly API:* Complexities of ASIO are hidden from the user, allowing for streamlined development of client and server applications. *Note:* While the framework is functional at this stage, it is still not ready for production as it lacks security and other necessary features. This is planned to be addressed in future videos. i used gemini 1.5 pro to summarize the youtube transcript
2:20 As a beginner javascript programmer everything you say sounds massive. I can barely keep up, but I've learned so much from this series and your channel in general.
May I suggest that you take some time to learn server/client patterns in node.js ? I promise you'll enjoy it and you'll avoid some of the confusing data types (namely the templates)
For anyone getting an error on the std::scoped_lock usage along the lines of scoped_lock use of dependent type name must be prefixed with 'typename', you need to be using Visual Studio 2019, retarget the entire solution to the current version of the Windows SDK, and make sure every project is set to use C++17, not default, in their project settings.
Yeah, I've noticed that myself but then I got stuck again at 26:45 because VS2019 fails to compile the program. The error is: Error C2440 'initializing': cannot convert from 'net::tsqueue' to 'net::tsqueue &'
I am super happy this got brought forward, this niche little series your doing is so helpful. Thanks for taking the time to make content like this. Your methods of explaining the material is spot on.
“Using a numeric id is much easier than using ip addresses” I mean, technically, IPv4 addresses *are* 32 bit integers, we just write them as 4 bytes converted to decimal
34:30 Isn't there still a tiny race condition window, between checking if the queue is empty and re-scheduling the WriteHeader() call? What if the queue empties just after assigning bWritingMessage? Then the WriteHeader() call will not be scheduled and the message will just sit there, waiting... Since you don't need to split the sending part in Header/Body (since you know the complete message beforehand), wouldn't it be better to have a single "WriteMessage()" function that sends the whole message, avoiding the "header/body" interleave problem?
This wont happen because it's being run inside the asio context. We're posting a lambda to be run on that thread (asio context), and it won't process the work (Lambda we just passed) until the previous work (Any reads/writes) have been completed. Think of all the lambdas he's creating as blocks of code. At no point are 2 lambdas ever going to run at the same time.
@@danbopes6699 Thanx a lot for the explanation. Now I am wondering if there is a reason to use thread-safe queues inside Asio context lambdas... 🤔 Maybe it is still necessary for those .front() calls that are made outside them.
Great couple of videos. Thank you very much for making game network programming accessible. I like the way in video 1 the message size() returns the size of whole message (header+body) but in video 2 (implied by accompanying source) it mysteriously returns body size only. Forces the student following along to find and fix the problem!
As someone who uses and has always used qt but would like to switch over to visual studio, I'd love to see a quick rundown video for the basics! Loving the network series also!
Oh fun, client supplied buffer sizes. This MMO better be good otherwise someone might decide to send a few malicious headers with a MAX_INT size field. :)
@@DanCojocaru2000 or predefined lengths, if (msg_size > max_length_by_id(msg.id)) { client.lifetime_ban(); }, youll likely check if valid id and do the same thing aswell.
when these things happen i decide to stop trying to "debug" it. Instead, I take a break and look at other alternative. Things that are not debuggable. Since I can't find any atm.
Hey javidx9! The first video of this series was recommended to me by one of my colleagues, because of the clear and easy-to-understand way you explain things. I got hooked up! I love programming and read/watch a lot of content, but I _rarely_ found anybody who can explain stuff as well as you. I also love the fact that you talk about design too while showing asio. It is so much more than a "tech tutorial", which is unfortunately all too common nowadays. A small question about the video. I noticed you use inheritance both for the client and server to implement the custom code (e.g. fire a bullet or ping). What do you think about the "composition over inheritance" principle? I read about it a few years ago, but to be honest, I never really understood the benefit of it. Your code seems very natural and simple with inheritance, so I don't see a reason to use composition instead. Would composition add anything to this example, in your opinion? Would you prefer composition in some other cases?
Hey thanks TeaShuty :D My understanding of composition is that you can sort of inject functionality without worrying about hierarchy, but I guess the problem with this is it becomes syntactically messy (and I would guess, difficult to maintain?) In this series, there are have been several moments where I have felt inheritance is probably not required, and would prefer to have some bolt in functionality. I guess its a way of using OOP code and languages in a more procedural way? lol dunno, must confess, not a pattern I use much.
very good presentation , as for asio itself (as demonstrated) - it is a perfect example on how to overcomplicate something relatively simple and make it hardly manageable/debuggable, I am not even talking about horrific buffer management
From 22:40 onwards, you have to edit the entire source code and remove all the mistakes and typos. You have to go to the Github repository to check what you are missing. E.g. if (m_threadContext.joinable) //WRONG if (m_threadContext.joinable()) //CORRECT E.g. TsQueue m_qMessageIn; TsQueue m_qMessagesIn; //Beware the additional 's'. It will be added in the new project source file.
Trying to implement this framework myself, following along the great explanation from Javid, whenever I'm stuck I have Doc's voice in my head repeating: "you're not thinking asynchronously!!"
Outstanding tutorial! Looking forward to part 3. One thing I'd like to learn more about is on finding the server's IP on the local network using a broadcast message. Is that something you can incorporate as well?
Instead of having dedicated server and client classes, you could just have one class for the "net_node" by removing the restriction of clients only being able to have one connection. It would allow the framework to be more flexible and allow meshes and other structures of nets while reducing the size of the framework at the same time.
10:10 why would we need to pass the connection/client shared pointer to the OnMessage function if the only messages the server will ever receive are of type 'owned_message' which already include the connection/client pointer?
well i already have PuTTY :) + don't we need some sort of deltatime or fps in order to not kill the processor with 100000 while loops per second? also each client will move at the speed of each machine 22:00 for anyone who forgot the setup of project right click > Properties > VC++ Directories >> Include Directories >> add "../NetCommon" and asio \include path right click > Build Depencencies... > Project Dependencies... >> check NetCommon box and don't forget the "#include "olc_net.h>" in server file also olc_net.h should contain this now #pragma once #include "net_common.h" #include "net_message.h" #include "net_client.h" #include "net_server.h"
I know, it's unfinished, but: 1. connection::Send(): Between lines 'bool bWritingMessage = !m_qMessagesOut.empty(); ' and 'm_qMessagesOut.push_back(msg);' queue can get empty. It doesn't matter now, when all access to m_qMessagesOut is done via 1 thread (asio context run). But still, it may become thread-(un)safe problem in the future. 2. tsqueue::wait(): 'cvBlocking.notify_one' can finish before 'cvBlocking.wait' starts => infinite waiting. You should use same mutex for queue and for condition variable. OR move all 'std::unique_lock ul(muxBlocking);' at the top of the functions where it occurs.
I ran into this interesting problem with your networking code: 'pinging' the server takes about 0.5 ms on my system when triggered the first time. About 40 ms each time thereafter. Until 'messageAll' is invoked, then the first time thereafter we are back in the 0.5 ms zone. This behavior is consistent here. Anyone else ran into this? Any suggestions?
on 26:50, how do you get "Connection Approved", how does "OnClientConnect(newconn)" returns "true" since: virtual bool OnClientConnect(std::shared_ptr client) { return false; }
@@javidx9 Hi, thank you for all the help until now and sorry to bother you again, but, in "ReadHeader()' (as it is in 39:08), "asio::async_read()" doesn't get called, I even went to "asio::async_read()"'s definition and changed it a bit, so the first thing to do is print a message to the screen (I just added a "std::cout", I deleted it later), but that message was never printed, actually, later by accident, it got printed, but by NetClient.exe, it does so every time I close NetServer.exe before NetClient.exe Thank you again
I'm stuck at this part 26:45 because VS2019 fails to compile the program. The error is: Error C2440 'initializing': cannot convert from 'net::tsqueue' to 'net::tsqueue &' I've already switched from C++14 to C++17 because that also caused issues with compilation previously.
Ended up copying and pasting the code from Github and it compiled succesfully. Not sure what that compilation error was about because I'm sure up to that point I was following the tutorials and doing things step by step :/ I will still continue watching them though!
For some reason my client can send messages and the server receives them, but the Server.cpp's 'OnMessage' function is not being called when a new message comes in. I have confirmed the server is indeed receiving the message, but just that function won't call. I've basically copy pasted the entire project files and it still doesn't work
34:50 this code is so confusing .. why not simply just write: { bool queueIsEmpty = m_qMessagesOut.empty(); m_qMessagesOut.push_back(msg); if(queueIsEmpty) { WriteHeader(); } } is that double negation necessary?!? i think not so
I have to disagree. I limit the usage of auto for temporary things (start and end in the same scope) that also have a near meaningless type. Stuff like trying to definite an iterator. C++ being strongly typed, I would prefer to see the datatype if it has any meaning at all. It does in this case.
Been waiting for this one. Judging from the comments, there are a few of us curious: is this the same ASIO that drives audio and MIDI interfaces? That particular ASIO has a lot of network capabilities, extensible though other protocols. Thanks and cheers, mate.
Visual Studio 2019 only makes .exe from NetClient and not from NetServer as well, so when I run it, like in 22:56, it runs NetClient.exe, what can I do about it?
I have noticed that connection::IsConnected returns true as soon as connection::ConnectToServer is called. It seems to be because m_socket is set to open inside the call to asio::async_connect but before the handler is called. This means that the client thinks it is connected, even if the endpoint is invalid.
javidx9 still though, all that in depth explanation and time you've put into it. I can see you like to really let people understand things! I can't wait for the rest, as this is actually really good knowledge.
"...using a tool that most network developers love and depend on" ...netcat? "putty" I didn't expect that somehow, to me it was always just windows ssh for uni connections.
Since STL containers aren't thread safe, wouldn't using a std::deque for the connections be dangerous? The async_accept handler gets called from a different thread and writes to the deque.
@javidx9 Thank you for good quality video, I'm new to asio and am learning a lot from this. just one curious thing: Could you explain the reason behind choosing deque for container of connections? The erasing/removing unvalidated clients over whole deque seems to be worst O(n^2) time complexity. I'm wondering if unordered_map or linked_list would do better.
17:50 what if client is nullptr (or anything else signaling that client == false) you just proceed do stuff related to client object which could be disposed. That might become a problem i suppose. i would have written like this: if(client && client->isConnected()) { ... } else if (client) { OnClientDisconnect(client) client.reset(); } this will ensure that client object is not null and you can call methods in that instance. and by the way, why are calling reset using dot and not arrow? i thought 'client' is a pointer, shared, but nonetheless a pointer
@@vilkillian shared_ptr object (client) still exists. And has reset() method. But it could hold pointer to object of connection class. Or it could hold nullptr. And I agree, 'if (client)' should be top-level 'if' there.
hey, i coded this project and everything is working fine, but when i test server-client communication with multiple client like at the end of the video and press 3 to quit client, all the opened client consoles close simultaneously, no matter which one was in focus. Anyone have any idea why this is happening?
I don't know how your head isn't pulsating with all that knowledge trapped in there. Maybe you use UA-cam as a dumping ground to prevent outright combustion? Joking aside thanks for the video!
In ReadBody(), would it be better to use async_read_some() intead of async_read()? Because if the the body is huge, isn't it better to read it in smaller junks? I think you did this in the first video when reading the html data... you used async_read_some there. If async_read() meant to be used if the body-data is small in size?
It's not really about body size, it's about knowing in advance how much data you wish to read. Streamed data like webpages you just nibble at until no more data arrives or it signals termination. In a packet system, there are no unknowns, so I request of asio to not bother me again until all the data I need is ready.
@@javidx9 Yes async_read() makes "life easier" if just needs all the data/body at once. Ok, async_read_some() gives more control. Like if I want a system receiving huge files and able to for example pause the file-send and then resume.... in that kind of system I guess async_read_some() would be good, am I right? I did that kind of programming before with MFC CAsyncSocket ... so splitting a huge file data and building the big body message by its parts at the receiving end. So each body part has its index so the receiver can re-assemble the message.
Hello, wenn using this code i get quite high ping times when sending inside my local network. For example when i run the server on my windows laptop and use my linux pc as a client i get ping times between 50ms and 100ms. This seems quite a lot for sending a message such a short distance. Any ideas why this is? If both the client and server run on the same machine i get under 1ms ping times.
Been binging your videos lately because i want to get into C++, and loving them so far! is there a place for me to get some basics? Like making the game screens and such and how they work, i have been looking into making some atari games to start out and theres jist so much info everywhere its a bit overwhelming haha. Thanks for these vids and im looking forward to more!
Sounds like you are looking for OpenGL/SDL tutorial, there are UA-camrs talking about using OpenGL making game engining he also has a list video talking about c++ basics.
the connection owner feels like a slightly strange way of doing this... similar objects with some slight changes depending on what it is feel like you want ClientConnection and ServerConnection subclasses
Thank you for this. I can't wait for Part 3 now! I'm going to have to watch this video and the first video again. I'll see if I can figure out the memory leak myself as a technical exercise. The 100% Proc usage is interesting. Have to understand the context of all of the function calls to really figure out what is going on there. That should be fun also.
While this is a good video to learn some basic networking concepts and their implementations, it has basic design flaws like using a tcp socket. Online games almost always use udp for gameplay, and most of those are custom "reliable" udp. Just a heads up, good video regardless.
Sir is there any way that can automated broutforceing all the port's, protocol's all the netwark machine at a time .auto magically download word list from net . Spacially GPU based 🔥 working process
If anybody has problems with ping. fix net_message.h line "return sizeof(message_header) + body.size();" to "return body.size();" int size() method. 30:00 in Part #1 I had the same problem and could fix this only with comparing with guthub.
Great video, a useless comment, though: funny, that black text cursor always makes me think there is a bug (literally, not software bug ...) on my monitor ;)
"In this case, its quite safe, as I programmed it" -- famous last words ;)
I was going to comment basically this exact same thing.. but instead I'll upvote yours. :D
I think accidentally coding a virus would be challenging
I read one of your posts about how difficult it was to start and at one point you didn't know if UA-cam was for you. I'm glad that you carried on. You have a cool channel. You are a smart man, and you are a creative programmer. Keep it up and stay happy.
Thanks Daniel, comments like that make it all worthwhile!
Yeah, I'm in college. Fell in love with programming, and cannot stop researching it. I even got used to sleeping every other day to get more hours in the week to study. This one was a bit daunting, but after about 5 days of solid network programming for windows, and making a simple client and server, this one is finally making sense, as all of your videos do, if not the first time, then the second or fifth time lol.. Ur awesome man, I appreciate everything you do, my university ain't teaching me half of what you do. I am becoming a better programmer, particularly in part by your videos specifically. Thanks! @@javidx9
Hello! Due to some IRL scheduling, I've brought forward next weeks video to now! This does mean there will be a gap before Part#3. Anyway, this video and the accompanying code is enough to start tinkering with in the meantime should you choose to. Though be aware it isnt ready for production - there is no security, and as its incomplete, it consumes 100% processor, and there is a memory leak too.
Sounds like any modern game in early access, no security, resource hungry, and eats memory for breakfast :-)
I havent started this series but I was wondering if it can be applied to 3D games in a similar way?
@@Ryan-xq3kl the fact that your game is 3D or 2D doesn't decides your networking connection. Your networking code is mainly defined by time and stability requirements
Looking forward to part 3!!
ua-cam.com/video/UbjxGvrDrbw/v-deo.html
You have a bug: net_server.h:112: m_deqConnections.erase(.... - it will remove nothing, as client isn't a reference, so the shared_ptr in deque wasn't changed by previous lane, and it still contains a valid ptr.
Two things:
1. I believe there's an error at 29:00 regarding checking whether we should read the body. It checks if header.size>0, but recall that header.size contains the size of the whole message (the header + the body, see: Part 1, 33:57). So in ServerPing scenario, the ping message should consist of 16 bytes (8 B header and 8 B body). SimpleClient writes a 8-byte body, but sets header.size to be 16. So the SimpleServer expects 16 bytes of body, and since only 8 are sent, it gets stuck.
Surprisingly the initial ServerAccept message was received correctly. It's because when we set header.id to ServerAccept, we did not update the header.size and left it at 0.
I think the simplest way to correct it would be to correct message& operator >, and replace `msg.header.size = msg.size()` with `msg.header.size = msg.body.size()`.
2. This 'Windows-way' to read keys pressed (around 40:00) is kind of discouraging Linux users, since it is not that easy to achieve sth, similiar in Linux, as there are no direct equivalents of GetAsyncKeyState(). It is however possible to have a solution working on both platforms, and thanks to asio itself! I adapted the solution: stackoverflow.com/questions/52308998/read-from-keyboard-using-boost-async-read-and-posixstream-descriptor to react to characters '1' and '3' (of course, reading from STDIN requires confirming the input with Enter, while the Windows solution reacts directly to pressed keys). One more thing would be to create additional thread to asynchronously start io_service.run().
thank you so much bro
bro u are an absolute legend thank you so very much
Nice catch! For the first issue, I think it would be better to change ReadHeader to correctly account for the header size instead of changing how we define header size entirely.
To do this, just change 'if(m_msgTemporaryIn.header.size > 0' to 'if(m_msgTemporaryIn.header.size > 8', and change the following line from 'm_msgTemporaryIn.body.resize(m_msgTemporaryIn.header.size)' to 'm_msgTemporaryIn.body.resize(m_msgTemporaryIn.header.size - 8)'.
This way, we keep the interpretation of header size consistent with how it was previously defined (header + body). By changing the > operators, it changes size's definition to be just the size of the payload.
Hey David! I recently came across your channel by accident, and I hardly understand anything, but you are so calm and clever, that your videos are kind of magnetic. Remember that it's not just your content that is attracting audience.
He's cool... maybe too cool...
Hours and hours studying to learn this stuff from google, fail. Two short videos from you, succeed. You are most epic my dude.
Even as a very experienced modern C++ softy just wanting to speed date the ASIO API I've really found this to be an excellent series. First class tutorial and explanation.
Thanks Simon!
21:10 - probably use of 'std::numeric_limits::max()' instead of -1 will be warning less at some compilers.
22:53 - folks, try to change port if some one of visitor of this channel got an exception at the binding (WSAEACCES at Windows) while execution of Server constructor (actually basic_socket_acceptor). In my case 6000 was fine instead 60000.
23:00 - this actually offtop for this video, however if you press cancel (for example you not an administrator of computer where you develop this program and do not know password of first one), and re-run program from Visual Studio you can still connect at putty.
25:40 - in section you call critical, for some compilers (CLang) order must be same like in member list, and m_nOwnerType should be too, at least with default value. Otherwise some compiler show warning here.
38:35 - major interesting here to make constructor and destructor of client_interface class public. They was left with default access (private) at 53:17 in part 1. Red underline at 'c' variable in video also indicate that moment.
41:44 | 44:34 - send only in connection class. So should be 'm_connection->Send(msg);' instead 'Send(msg);'. That moment already fixed in source from GitHub.
Unfortunately video version of code do not grant full access to possibility (answer from server if showed at client - do that only once) that was show in this part, probably according to off frame editing, so source for GitHub should help with that.
Love u mane
Thanks you man, two days to understand one exception ASIO_…PARAM. But is just change 60000 to 6000.
As if the musical version of ASIO wasn't enough of a headache for me, it also share a name with C++ stuff too? Wonderful.
The austalian version of the CIA is called ASIO.
@@beatrute2677 I hope they function better than the ASIO driver lol.
@@isaac10231 never had any problems with the asio drivers, what gives you headaches with them?
"Because you all write awesome code" 😂😂😂😂😂
I tried asio in the past for a simple networked application. There's a lot of complexity here, specifically having each task reprime the state machine seems odd. But I got it all working.
I appreciate your explanation. It makes some of the things I didn't fully understand clearer.
It also strikes me that there are similarities between this design and the actor pattern.
*Summary*
This video focuses on building a functioning client-server system with ASIO and the framework outlined in Part 1. Here's a breakdown:
*1. Server Functionality & Design* (1:09)
* The server must handle:
* Accepting client connections (1:14)
* Handling client disconnections (2:10)
* Implementing game logic (2:16)
* An asynchronous `asio::acceptor` (10:38) object continuously listens for connections.
* The server needs a task to keep the ASIO context alive: continuously wait for and handle client connections (10:38)
*2. `Server` Interface* (1:09)
* A template class designed for inheritance by user's application logic. (3:00)
* Contains:
* An ASIO context shared by all connected clients (10:20)
* A single thread for the context. (10:25)
* An `asio::acceptor` object to handle connections. (10:38)
* A deck to store connected client `Connection` objects. (15:54)
* An ID counter for assigning unique IDs to clients. (10:43)
* A `queue_incoming_messages` (Threadsafe Queue of `OwnedMessage` objects) to hold received messages (10:08)
* Key functions:
* `Start()` (11:59): Creates a task to wait for connections and starts the ASIO context thread.
* `Stop()` (13:08): Stops the ASIO context and joins the thread.
* `WaitforClientConnection()` (13:32): An *asynchronous* task run by the ASIO context that waits for incoming connections using `asio::acceptor`.
* `OnClientConnect()` (15:32): Called when a client attempts to connect, allowing the server to approve or deny it (customizable by the user).
* `OnClientDisconnect()` (18:11): Called when a client disconnects.
* `OnMessage()` (19:52): Called from within `Update()` (20:12) to handle messages in the incoming message queue (customizable by the user).
* `Update()` (20:12): Processes messages from the incoming queue, calling `OnMessage()` for each. Users can control the number of messages processed per call to `Update()`.
* `SendToClient()` (8:55): Sends a message to a specific client (using their ID).
* `MessageAllClients()` (9:00): Sends a message to all connected clients (optionally excluding a specific client).
*3. `Connection` Object* (24:14)
* A template class representing a connection to a client (whether created by the server or by a client).
* Includes:
* An `owner` field (using `Owner` enum class) to distinguish between server-owned and client-owned connections. (24:26)
* A socket (`sock`) (24:57)
* References to the ASIO context and the relevant message queue (server's or client's) (24:45, 25:02).
* A unique ID (`id`) if owned by a server. (25:54)
* Key *asynchronous* tasks executed by ASIO:
* `ReadHeader()` (27:54): Reads a message header from the socket.
* `ReadBody()` (29:24): Reads a message body based on size indicated in the header.
* `WriteHeader()` (31:30): Writes a message header to the socket.
* `WriteBody()` (32:22): Writes a message body to the socket.
* `AddToIncomingMessageQueue()` (30:16): Adds a completed message to the appropriate message queue, and re-primes the ASIO context to read the next header.
* `Send()` (33:13): Called by either the server or client to send a message. Uses ASIO's `post()` to add a task to write the message to the socket (avoiding concurrent header/body writes).
* `Disconnect()` (35:03): Uses ASIO's `post()` to add a task to close the socket cleanly.
*4. `Client` Interface* (35:35)
* Template class with most implementation already present from Part 1.
* Uses an `asio::resolver` (36:25) to translate a domain name into an IP address/endpoint.
* Key function: `Connect()` (35:59) now fully implemented. It resolves the host address, creates a `Connection` object (client-owned) (37:02), starts the ASIO context thread (37:29), and then calls `Connection::ConnectToServer()`.
*5. Example: Ping Server and Broadcasting a Message* (38:37)
* This part includes modifications to the client and server examples from Part 1 to showcase sending and receiving custom messages:
* The client can now:
* Send "Server Ping" messages with timestamps for calculating round-trip time.
* Send a message to the server asking it to broadcast a message to all other clients.
* The server responds accordingly, including:
* Reflecting the "Server Ping" messages.
* Receiving the broadcast request and distributing the message to all other clients.
*Key Improvements:*
* *Robust error handling:* Network failures and disconnections are detected and managed to prevent application crashes.
* *Asynchronous design:* Network operations are handled by the ASIO context in a background thread, allowing the application logic to continue without blocking.
* *User-friendly API:* Complexities of ASIO are hidden from the user, allowing for streamlined development of client and server applications.
*Note:*
While the framework is functional at this stage, it is still not ready for production as it lacks security and other necessary features. This is planned to be addressed in future videos.
i used gemini 1.5 pro to summarize the youtube transcript
2:20 As a beginner javascript programmer everything you say sounds massive. I can barely keep up, but I've learned so much from this series and your channel in general.
May I suggest that you take some time to learn server/client patterns in node.js ?
I promise you'll enjoy it and you'll avoid some of the confusing data types (namely the templates)
For anyone getting an error on the std::scoped_lock usage along the lines of scoped_lock use of dependent type name must be prefixed with 'typename', you need to be using Visual Studio 2019, retarget the entire solution to the current version of the Windows SDK, and make sure every project is set to use C++17, not default, in their project settings.
THANK YOU
THANK THEE ME LORD
Yeah, I've noticed that myself but then I got stuck again at 26:45 because VS2019 fails to compile the program. The error is: Error C2440 'initializing': cannot convert from 'net::tsqueue' to 'net::tsqueue &'
I am super happy this got brought forward, this niche little series your doing is so helpful.
Thanks for taking the time to make content like this.
Your methods of explaining the material is spot on.
"It's never gonna crash because you all write awesome code" Obviously OLC has never seen my github account lolll
Nor mine.
“Using a numeric id is much easier than using ip addresses” I mean, technically, IPv4 addresses *are* 32 bit integers, we just write them as 4 bytes converted to decimal
34:30 Isn't there still a tiny race condition window, between checking if the queue is empty and re-scheduling the WriteHeader() call? What if the queue empties just after assigning bWritingMessage? Then the WriteHeader() call will not be scheduled and the message will just sit there, waiting...
Since you don't need to split the sending part in Header/Body (since you know the complete message beforehand), wouldn't it be better to have a single "WriteMessage()" function that sends the whole message, avoiding the "header/body" interleave problem?
Came here to say exactly that. Answering to you to get updates on this comment
This wont happen because it's being run inside the asio context. We're posting a lambda to be run on that thread (asio context), and it won't process the work (Lambda we just passed) until the previous work (Any reads/writes) have been completed. Think of all the lambdas he's creating as blocks of code. At no point are 2 lambdas ever going to run at the same time.
@@danbopes6699 I see. Thank you for the explanation. Threads and asynchronous calls are hard to wrap your head around.
Just exactly what I was thinking. I am glad there is people paying attention to this wonderful videos.
@@danbopes6699 Thanx a lot for the explanation. Now I am wondering if there is a reason to use thread-safe queues inside Asio context lambdas... 🤔 Maybe it is still necessary for those .front() calls that are made outside them.
Great couple of videos. Thank you very much for making game network programming accessible. I like the way in video 1 the message size() returns the size of whole message (header+body) but in video 2 (implied by accompanying source) it mysteriously returns body size only. Forces the student following along to find and fix the problem!
most of the time you should pass const& to shared pointers to avoid their copy when not necessary. Removes a lot of overhead, especially for an MMO ;)
41:44 When I try to call Send() it tells me it isnt declared in this scope
Man, your material is awesome, I'm lucky for starting to study networking in C++ just when you started this series. haha
As someone who uses and has always used qt but would like to switch over to visual studio, I'd love to see a quick rundown video for the basics! Loving the network series also!
Oh fun, client supplied buffer sizes. This MMO better be good otherwise someone might decide to send a few malicious headers with a MAX_INT size field. :)
if (msg_size > 4096) { client.gtfo(); }
@@DanCojocaru2000 or predefined lengths, if (msg_size > max_length_by_id(msg.id)) { client.lifetime_ban(); }, youll likely check if valid id and do the same thing aswell.
Your explanations are always so clear, especially on this seldom discussed, yet very important topic.
Thanks for this. Actually waited for this one.
I spent 4 hours debugging why std::scoped_lock wasn't working, until I realized my project's C++ version was
C++ 14, not 17.. *sigh*
Lol, been there....
Me too
when these things happen i decide to stop trying to "debug" it. Instead, I take a break and look at other alternative. Things that are not debuggable. Since I can't find any atm.
Yeeeees, I've been eagerly waiting for the continuation of this series!
im grateful for your videos
21:36
He's gonna say Wireshark...
He's gonna say Wireshark...
It's comming...
"A program called putty"
Oh.
so good seeing all of these concepts i learned about being put into practice. thank you
This is just gold. So easy to understand this ASIO with javix.
Hey javidx9! The first video of this series was recommended to me by one of my colleagues, because of the clear and easy-to-understand way you explain things. I got hooked up! I love programming and read/watch a lot of content, but I _rarely_ found anybody who can explain stuff as well as you. I also love the fact that you talk about design too while showing asio. It is so much more than a "tech tutorial", which is unfortunately all too common nowadays.
A small question about the video. I noticed you use inheritance both for the client and server to implement the custom code (e.g. fire a bullet or ping). What do you think about the "composition over inheritance" principle? I read about it a few years ago, but to be honest, I never really understood the benefit of it. Your code seems very natural and simple with inheritance, so I don't see a reason to use composition instead. Would composition add anything to this example, in your opinion? Would you prefer composition in some other cases?
Hey thanks TeaShuty :D My understanding of composition is that you can sort of inject functionality without worrying about hierarchy, but I guess the problem with this is it becomes syntactically messy (and I would guess, difficult to maintain?) In this series, there are have been several moments where I have felt inheritance is probably not required, and would prefer to have some bolt in functionality. I guess its a way of using OOP code and languages in a more procedural way? lol dunno, must confess, not a pattern I use much.
very good presentation , as for asio itself (as demonstrated) - it is a perfect example on how to overcomplicate something relatively simple and make it hardly manageable/debuggable, I am not even talking about horrific buffer management
From 22:40 onwards, you have to edit the entire source code and remove all the mistakes and typos. You have to go to the Github repository to check what you are missing.
E.g. if (m_threadContext.joinable) //WRONG
if (m_threadContext.joinable()) //CORRECT
E.g. TsQueue m_qMessageIn;
TsQueue m_qMessagesIn; //Beware the additional 's'. It will be added in the new project source file.
Great video as always!!!!
I don't code in C at the moment, but all these videos show a lot of concepts that easily translate to all programming efforts. Really enjoy it.
"and all of the other chrono rubbish you have to do to display this number". This made me laugh :D
Thank you so much! :) Was dreaming about such content !!!
Trying to implement this framework myself, following along the great explanation from Javid, whenever I'm stuck I have Doc's voice in my head repeating: "you're not thinking asynchronously!!"
For Linux dont forget to link the thread library otherwise it won't build.
Outstanding tutorial! Looking forward to part 3. One thing I'd like to learn more about is on finding the server's IP on the local network using a broadcast message. Is that something you can incorporate as well?
He wasn't kidding when he said networking is complex GODDAMN!!
Also, if anyone is getting an error that Send is not defined in the client, use m_connection->Send(msg); instead.
THX MAN! :D
Instead of having dedicated server and client classes, you could just have one class for the "net_node" by removing the restriction of clients only being able to have one connection. It would allow the framework to be more flexible and allow meshes and other structures of nets while reducing the size of the framework at the same time.
10:10 why would we need to pass the connection/client shared pointer to the OnMessage function if the only messages the server will ever receive are of type 'owned_message' which already include the connection/client pointer?
Why are lines 63 and 64 at 34:57 not a race condition? Is it because it's wrapped in an asio::post and that is somehow atomic for our use-case?
This is incredible. I'm gonna need a long weekend to try this stuff....
well i already have PuTTY :) + don't we need some sort of deltatime or fps in order to not kill the processor with 100000 while loops per second? also each client will move at the speed of each machine
22:00 for anyone who forgot the setup of project
right click > Properties > VC++ Directories >> Include Directories >> add "../NetCommon" and asio \include path
right click > Build Depencencies... > Project Dependencies... >> check NetCommon box
and don't forget the "#include "olc_net.h>" in server file
also olc_net.h should contain this now
#pragma once
#include "net_common.h"
#include "net_message.h"
#include "net_client.h"
#include "net_server.h"
I know, it's unfinished, but:
1. connection::Send(): Between lines 'bool bWritingMessage = !m_qMessagesOut.empty();
' and 'm_qMessagesOut.push_back(msg);' queue can get empty. It doesn't matter now, when all access to m_qMessagesOut is done via 1 thread (asio context run). But still, it may become thread-(un)safe problem in the future.
2. tsqueue::wait(): 'cvBlocking.notify_one' can finish before 'cvBlocking.wait' starts => infinite waiting. You should use same mutex for queue and for condition variable. OR move all 'std::unique_lock ul(muxBlocking);' at the top of the functions where it occurs.
For Mac users who don't have PuTTY, use ssh instead to test the server, give it an address and port
$ ssh 127.0.0.1 -p 60000
I am learning more here than my university network programming class
I ran into this interesting problem with your networking code: 'pinging' the server takes about 0.5 ms on my system when triggered the first time. About 40 ms each time thereafter. Until 'messageAll' is invoked, then the first time thereafter we are back in the 0.5 ms zone. This behavior is consistent here. Anyone else ran into this? Any suggestions?
on 26:50, how do you get "Connection Approved", how does "OnClientConnect(newconn)" returns "true" since:
virtual bool OnClientConnect(std::shared_ptr client)
{
return false;
}
Polymorphism overrides that base method.
@@javidx9 Hi, thank you for all the help until now and sorry to bother you again, but, in "ReadHeader()' (as it is in 39:08), "asio::async_read()" doesn't get called, I even went to "asio::async_read()"'s definition and changed it a bit, so the first thing to do is print a message to the screen (I just added a "std::cout", I deleted it later), but that message was never printed, actually, later by accident, it got printed, but by NetClient.exe, it does so every time I close NetServer.exe before NetClient.exe
Thank you again
I'm stuck at this part 26:45 because VS2019 fails to compile the program. The error is: Error C2440 'initializing': cannot convert from 'net::tsqueue' to 'net::tsqueue &'
I've already switched from C++14 to C++17 because that also caused issues with compilation previously.
Ended up copying and pasting the code from Github and it compiled succesfully. Not sure what that compilation error was about because I'm sure up to that point I was following the tutorials and doing things step by step :/
I will still continue watching them though!
For some reason my client can send messages and the server receives them, but the Server.cpp's 'OnMessage' function is not being called when a new message comes in. I have confirmed the server is indeed receiving the message, but just that function won't call. I've basically copy pasted the entire project files and it still doesn't work
Thank you Mr. Bearded Man.
You should have a full c++ series, you're great :)
Series is singular as well. 1 series, 2 series.
@@clonkex Thanks,
I am really enjoying this series
34:50 this code is so confusing .. why not simply just write:
{
bool queueIsEmpty = m_qMessagesOut.empty();
m_qMessagesOut.push_back(msg);
if(queueIsEmpty)
{
WriteHeader();
}
}
is that double negation necessary?!? i think not so
Thank you so much for this detailed comprehensive explanation! Are you going to create beast server/client lessons as well?
41:00 'auto' is your friend ;)
I have to disagree. I limit the usage of auto for temporary things (start and end in the same scope) that also have a near meaningless type. Stuff like trying to definite an iterator.
C++ being strongly typed, I would prefer to see the datatype if it has any meaning at all. It does in this case.
auto is pretty when you do not need to care what is the variable type. Or you tired of using template ~
Been waiting for this one. Judging from the comments, there are a few of us curious: is this the same ASIO that drives audio and MIDI interfaces? That particular ASIO has a lot of network capabilities, extensible though other protocols. Thanks and cheers, mate.
More More More More !!!!!!!!!!!!!!!!!!!!!!
I don't understand why server_interface has no Send function, and instead call Send function of that client to send message to that client?
Visual Studio 2019 only makes .exe from NetClient and not from NetServer as well, so when I run it, like in 22:56, it runs NetClient.exe, what can I do about it?
You can only run one at a time from within VS, that's why I launch them manually from the project folder.
Could you tell me how to pass the open socket as a parameter to a C++ function ?
I have noticed that connection::IsConnected returns true as soon as connection::ConnectToServer is called. It seems to be because m_socket is set to open inside the call to asio::async_connect but before the handler is called. This means that the client thinks it is connected, even if the endpoint is invalid.
Thank you so much for your videos!Really interesting!
i want to learn there , so what book i should learn ?
thank for helping me
You make this look so easy lol. I've made some c style server clients, but never this abstract. Pretty neat ngl, very good info to learn here!
Thanks, though dont be fooled by the magic of video editing! It is complicated stuff, that takes practice and patience to develop 😁
javidx9 still though, all that in depth explanation and time you've put into it. I can see you like to really let people understand things! I can't wait for the rest, as this is actually really good knowledge.
Ohh suprise video 👍👍👍
"...using a tool that most network developers love and depend on"
...netcat?
"putty"
I didn't expect that somehow, to me it was always just windows ssh for uni connections.
I was also surprised. It's like "Telnet? Curl? Wget? Netcat?" and then he says Putty.
I use putty to send data to develop board serial port. Don't know putty can do network things :p
@@wizardy6267 It's great for managing Linux computers remotely.
I assumed we had to setup the Netserver Project as a .exe instead of a static library .lib. As a static library, it will run into problems.
Since STL containers aren't thread safe, wouldn't using a std::deque for the connections be dangerous? The async_accept handler gets called from a different thread and writes to the deque.
adding one more question here: Is tsqueue really thread safe? I think data race can happen between tsqueue.empty() check and tsqueue.pop() operation
Thanks a lot for this stuff
I saw a lot of shared_ptr passed to function by value, could it be better to just pass in by const ref?
@javidx9
Thank you for good quality video, I'm new to asio and am learning a lot from this. just one curious thing:
Could you explain the reason behind choosing deque for container of connections? The erasing/removing unvalidated clients over whole deque seems to be worst O(n^2) time complexity. I'm wondering if unordered_map or linked_list would do better.
Why is the latency so big from sendign 8 bytes it takes 0.7 ms on the same computer
17:50
what if client is nullptr (or anything else signaling that client == false)
you just proceed do stuff related to client object which could be disposed. That might become a problem i suppose.
i would have written like this:
if(client && client->isConnected()) { ... }
else if (client) { OnClientDisconnect(client) client.reset(); }
this will ensure that client object is not null and you can call methods in that instance.
and by the way, why are calling reset using dot and not arrow? i thought 'client' is a pointer, shared, but nonetheless a pointer
@@MuhammadHosny0 whats wrong?
reset() is a method of the class shared_ptr. You only use the arrow operator if you call methods of the stored class.
@@michaelmahn4373 still, if this object is empty i.e. if there is no instance, there is nothing to call
@@vilkillian I was only answering the second question, why he uses dot instead of ->
@@vilkillian shared_ptr object (client) still exists. And has reset() method. But it could hold pointer to object of connection class. Or it could hold nullptr. And I agree, 'if (client)' should be top-level 'if' there.
So now the Console Game Engine will run on the Server? Yayyy.
hey, i coded this project and everything is working fine, but when i test server-client communication with multiple client like at the end of the video and press 3 to quit client, all the opened client consoles close simultaneously, no matter which one was in focus. Anyone have any idea why this is happening?
I don't know how your head isn't pulsating with all that knowledge trapped in there. Maybe you use UA-cam as a dumping ground to prevent outright combustion?
Joking aside thanks for the video!
In ReadBody(), would it be better to use async_read_some() intead of async_read()? Because if the the body is huge, isn't it better to read it in smaller junks? I think you did this in the first video when reading the html data... you used async_read_some there. If async_read() meant to be used if the body-data is small in size?
It's not really about body size, it's about knowing in advance how much data you wish to read. Streamed data like webpages you just nibble at until no more data arrives or it signals termination. In a packet system, there are no unknowns, so I request of asio to not bother me again until all the data I need is ready.
@@javidx9 Yes async_read() makes "life easier" if just needs all the data/body at once. Ok, async_read_some() gives more control. Like if I want a system receiving huge files and able to for example pause the file-send and then resume.... in that kind of system I guess async_read_some() would be good, am I right?
I did that kind of programming before with MFC CAsyncSocket ... so splitting a huge file data and building the big body message by its parts at the receiving end. So each body part has its index so the receiver can re-assemble the message.
Yeah, if you need to interrupt the transfer reliably then nibbling away at it is your only option.
Big thumbs up👍. Great Tutorial like always, can't wait for the security patching.
Hello, wenn using this code i get quite high ping times when sending inside my local network. For example when i run the server on my windows laptop and use my linux pc as a client i get ping times between 50ms and 100ms. This seems quite a lot for sending a message such a short distance. Any ideas why this is? If both the client and server run on the same machine i get under 1ms ping times.
Been binging your videos lately because i want to get into C++, and loving them so far! is there a place for me to get some basics? Like making the game screens and such and how they work, i have been looking into making some atari games to start out and theres jist so much info everywhere its a bit overwhelming haha. Thanks for these vids and im looking forward to more!
Sounds like you are looking for OpenGL/SDL tutorial, there are UA-camrs talking about using OpenGL making game engining he also has a list video talking about c++ basics.
the connection owner feels like a slightly strange way of doing this... similar objects with some slight changes depending on what it is feel like you want ClientConnection and ServerConnection subclasses
Thank you for this. I can't wait for Part 3 now! I'm going to have to watch this video and the first video again. I'll see if I can figure out the memory leak myself as a technical exercise. The 100% Proc usage is interesting. Have to understand the context of all of the function calls to really figure out what is going on there. That should be fun also.
Hi 👋, awesome vids, any tips for struggling software engineer
thanks so much!
Can you make a UDEMY course about c++?
While this is a good video to learn some basic networking concepts and their implementations, it has basic design flaws like using a tcp socket. Online games almost always use udp for gameplay, and most of those are custom "reliable" udp. Just a heads up, good video regardless.
Sir is there any way that can automated broutforceing all the port's, protocol's all the netwark machine at a time .auto magically download word list from net . Spacially GPU based 🔥 working process
Thank you for the video. This helped me very much.
If anybody has problems with ping. fix net_message.h line "return sizeof(message_header) + body.size();" to "return body.size();" int size() method. 30:00 in Part #1
I had the same problem and could fix this only with comparing with guthub.
Esse cara Sabe Muito!!
Great video, a useless comment, though: funny, that black text cursor always makes me think there is a bug (literally, not software bug ...) on my monitor ;)
Yees
Thank you OLC!