How To Create a Chat App and Server Tutorial WPF C#

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
do you remember that time you get on your favorite chat application to send a message to your crush or when you were fighting monsters in the popular role playing game in order to get some gold so you could trade it for an epic sword have you ever thought about how the networking might work under the hood well today you'll learn how to create your own chat client and chat server that communicates with one another and also lets you communicate with others before we get started make sure to subscribe to the channel so you do not miss out any cool updates and if you have any questions make sure to join the discord community link will be in the description so the project that we're going to work on today is going to look like this before we get discouraged because of the ui look don't worry i have a video on how to make a better looking one which you can see on the screen right now that being said let's get into it so we're going to start by connecting three clients we're going to connect with armada foe as well as fubar there we go if i start typing something here hello we can see that everyone receives that message but we can type messages left and right everything gets sent to the server if i disconnect with let's say armada we can see that it disconnected everywhere this project is so cool you're gonna love it so let's pull up visual studio and let's get started all right so starting up visual studio we want to create a new project we'll create a wpf application we can call it chat app now for the target framework we want to select.net 5.0 then hit create a couple of things before we get started i like to hit this vertical split in order to have my samo on the right hand side and my designer on the left hand side we want to rename this to chat client we also want to add another project by right clicking the solution add new project this is going to be a console application we'll call this chatserver.net 5.0 and create perfect we won't be touching that for now we're going to be working on the client first we will be setting this up using an nvvm approach so we're going to right click the project we're going to hit add new folder we'll call this mvvm we'll copy paste it a couple of times this one's going to be called view next one is going to be called the view model and the last one is going to be called model we can group these under the nvvm folder just like so moving our main window into the view folder that's going to break the application momentarily heading into app.saml we just want to change this to mvvm dash view dash main window rebuild the project by clicking ctrl shift b heading over in here of course it didn't rebuild we're going to start the application and it works just fine closing the main window and opening it back up reloading the designer there we go now in terms of the design we want a text box on the left hand side as well as a connect button as well as the list where we can see the actual user somewhere where we can see the the messages as well as an input field so we can actually now send messages and a button to actually send the message so let's split this grid up into two columns with the column definitions we'll add two column definitions there we go perfect we can explicitly set the width to i don't know 200 is that too much that's fine and let's start by adding now for the right hand side we want to create a stack panel we're actually going to set the column for that one to one so the grid column is going to be one we're going to add a list view the height of the list view is going to be about 380. let's see 380. yeah it seems about right followed by a text box where the height is going to be 55 yeah and the vertical content alignment is going to be center you know what let's actually do this so instead of having this text box just like this we'll create a another stack panel in here setting the orientation to horizontal followed by the text box or there was the text in box setting the height to 55 as usual the width about 545 the vertical content alignment center obviously let's add a button in here setting the width to 55. there we go and actually set the content as well content i can't spell there we go uh send all right and that's the client done at least the design right so let's try to connect to a server we need to go ahead and set up the server object first so let's go into the chat client add a new folder call it net in here we're going to create a new class call it server there we go now in the server we're going to create a tc or actually we're going to start by creating a constructor there we go inside the class we want to create a tcp client import the namespace which is using system.net.socket call it underscore client inside the constructor we want to instantiate it to a new instance of the tcp client so the client equals new tcp client perfect we also want a function that's actually going to connect to the server so let's do a public void because this will be exposed to the view model hence why we're making it public connect to server perfect now we don't want to try to connect to the server if we're already connected so let's do some quick error handling if let's do client dot connected checking oh connect that there we go checking if it's not already connected then one do client dot connect oop connect there we go and we want to connect to one two seven zero zero one which is our local address and here you wanna specify a port make sure to pick a port that's not already in use like port 80. i'm gonna go with 78.91 that seems like a good port and that's pretty much it for actually connecting to a server now we don't have a server to connect to so we should probably set up a server but before we do that let's just hook up the button on the client so that we can actually you know connect to the server so let's create a view model so go into the view model folder call it main view model create a constructor in here there we go now since we want to use a command here we probably want to use a relay command which i'm going to create a new folder for so in nvidia i'm going to create a folder named core there we go inside here i want to create a new class call it relay command now i decided to go ahead and write this out so that you don't have to sit here and look at me write this out you can pause this right here and just copy this entire class because you will need it by the way the source code will be available on my patreon which you can find in the description as well moving back into our main view model we're going to create a property of type relay command import the namespace we're going to call this connect to server command command there we go we're also going to create a new instance of a server object which we created earlier we'll do a private server import the namespace underscore server in the constructor we're actually going to underscore server equals new server here we go clean this up a little bit and now i want to create a new instance of the command as well so connect to server command equals new relay command object goes into server dot connect to server there we go and let's go ahead and bind that command real quick so let's set up the the data context for the window so we'll do window data context main view model oh there we go import xml namespace and there we go let's rebuild this so we can actually see it again if rebuilding doesn't work then just close the main view and open it back up there we go for some reason my visual studio didn't want to cooperate so i had to restart visual studio in order for this to actually show again if rebuilding the project doesn't work for you then just restart visual studio and it should work right so the button let's add a command to it we do so by adding it as a property command binding and worsty there we go connect to server command perfect now if we run the application or try to connect it's going to throw an exception no connection could be made because the target machine actively refused it meaning that there's nothing listening for an incoming connection on that port which is good so let's go ahead and create the server which is actually going to you know accept the connection so we can close down all of these windows minimize all these make it look a little bit better than heading into the chat server heading into program and we can start by creating a tcp listener call it underscore listener let's then create a new instance of the listener oh yeah we gotta make it static because it's in the static context of static there we go we'll do a listener there we go equals new tcp listener we need to check in the ip address we'll do ip address and we'll call parse two seven zero zero one for the port it's going to be the exact same as we specified on the client which is seven eight nine one in my case at least now whoops uh there we go then we'll do listener dot start now we could go very in depth with this we can use like a backlog for instance we could do way better error handling but you got to keep in mind that i'm doing this for people who barely have any idea what networking is that being said let's go ahead and accept a client so we'll do var client equals listener that accept tcp client there we go now this is a blocking call so we don't need to specify console read line down here in order for the application not to shut down or while the server in this case we can however send a message to the console saying client has connected there we go now right clicking the solution properties we want to start both of the projects not at the same time we actually want to start the server first so i'm going to click the server move it up in the hierarchy making sure that it starts first start as well as the client right after it click apply okay now i'm gonna run the application now the server is obviously the console in this case the client being well declined and this is look at this this is really cool i'm gonna click connect and we can see that the client has connected that right there to me is so fascinating oh yeah we should probably fix this design here as well we'll resize that in just a sec so as of right now we're only accepting one client then we're shutting down the server we want to be able to accept multiple clients and keep track of those clients in a some sort of collection let's use a list let's actually create a custom object for the client as well so we'll go into the server add class we'll call this client we'll add a constructor we'll give it some properties such as well actually we'll give it a string property of type name it could be username as well that's the username let's give it another property of guid which is a globally unique identifier this is going to be id of the application in case we want to specify which client we want to do things with later on if you want to expand on the status we'll call this uid we also want to keep track of the actual tcp client socket object in here so we'll do uh prop tcp client there we go and import the namespace whoops that was oops i created a new object tcp client there we go import and namespace call this client socket now in the constructor we actually want to pass in the a tsp client call it client we'll set client socket to be client there we go we also want to generate a new user id whenever this client gets instantiated so we'll do uid equals guid new jehuid to string there we go my keyboard does not want to cooperate today all right we set it that's the geo id so we're going to have to call tostring there we go we can then broadcast this into the console saying that a user has connected so we'll do console.writeline we can do we can actually format this so it looks a bit better there we go we'll do it like that and we'll do date time dot now uh cli oop claw the client has connected with the username and then you know it will format it like this um and we'll do username now the username is going to be empty because we haven't read the actual username that the client sends yet we'll get to that but for now this will be more than enough right so we have our very basic client object let's head back into the program where we define the listener let's create a static list of type oh it's important namespace as well type client called this underscore users and underneath we can actually remove that line we can do oh and we gotta instantiate the list as well so we'll do underscore users equals new collection which is a list in this case and we'll do underscore users add and what we're going to check in is actually we're going to create a new client there we go again with the keyboard and chuck in the tcp client that this returns now that probably went really fast i'll try breaking it down so let's just remove that so we're creating a new instance of the client object that we just created right which takes a parameter in the constructor a tcp client this accept tcp client function that we get from the listener actually returns a tcp client and that's the object we're using as the parameter now we can run the application we can i can show you the server down here connect and we can see that that time and etc etc we're not printing out a username because again we're not sending one just yet we will but moving on we actually want to wrap this in a while true loop there we go so an infinite loop where we'll be accepting multiple clients because once we've accepted one client we want to start processing the packets and whatnot which is super fun and then once we're done with that we want to start accepting the next client so we'll be able to accept more clients let's go ahead and check this client that we accepted into the users collection as well so users to add and we can check in the client there we go and down here we want to later on broadcast the connection to every one on the server there we go so that they can update their local list of users all right so i think it's time to actually start sending data to the server so let's go ahead and head into our client net and server and let's think about this for a second so connect the server is going to connect to the server we're going to send the username to the server as well so we're going to pass that in as a parameter to where we're calling this from so we'll do string username there we go and remember we're calling this from the main view model which we can see right here we're getting an exception because we're not checking in the username the username that we want to check in if we look at the main view model is going to be defined within this text box right here so we're actually going to create a property in the main view model call it prop string user user name there we go we're going to chuck this in as a parameter right now it's just going to be empty because we need to bind it so let's do text box and it's because it can't know it's text binding username there we go so whatever we pass in here is now going to get bound to this property which in return is going to be sent over here now the reason to why we want to use a relay command we want to be able to disable the button if the username property is empty so if i run the application right now you can see that i can connect even though the username is empty which is that's bad we don't want that so we're actually going to add a o goes into goes into string is no or empty and we'll pass in username so if the string right here is not null or empty this command will be allowed to run aka it's going to make this enabled so you can see that right now it's disabled but if i type something in oh right when you set up the two-way data binding update source trigger property changed there we go now we can run it here we go and if we type something in we can see that we can now connect if we remove that we can't connect anymore all right so heading back into the connect to server command we now have some data that we want to send to the server but how on earth are we going to do that this is where the packet builder comes into place so in our net folder we're going to create a new folder call it io we're going to add a new class call it packet builder all this class is going to do is it's going to allow us to append data to a memory stream which we'll be able to use in order to get the bytes to send to the server because all we're doing is we're just sending the data in the form of bytes from the client to the server and vice versa so we're going to create a constructor as always we're going to create a memory stream import the namespace call it underscore ms in the constructor we're going to instantiate it to a new memory stream let's see new memory stream there we go and we're going to have three functions we're going to have one that allows us to write an op code to the packet which we're going to be able to use as a social as a flag saying okay this is the server is going to be able to interpret the packet different ways depending on the op code so if we send a packet with the upcode of one we know that the server wants to read a let's say a string message for instance if that didn't make any sense don't worry it will in just a sec the public void we'll call it write opcode there we go let's make sure that we spell it a good way as well there we go we'll do underscore ms dot right byte we'll actually pass in the op code as the parameters also byte of code oh not bob code but op code op code there we go now the reason to why we're writing a byte here for the opcode and not like an int is because we don't really we're not going to have 2.1 billion different op codes we're going to have less than 255. so in order to make the packet smaller we don't have to reserve four bytes in the buffer so writing one byte to the array we also want to be able to actually write a string for instance the username so we'll do public void write string there we go we'll pass in a string message there we go this is going to be a core function because we want to use it to send messages as well and not just the username we'll do uh var msg lane so the message length is going to be msg.length there we go because this package is going to be read as opcode length followed by how many bytes we actually need to read in order to get the full string which is the payload in this case we want to do ms.write there we go we'll do bit converter there we go get bytes i want to get the bytes from the message length so the bytes from this end which is 4 bytes we want to get those bytes and append it to the memory stream now we want to do the same thing pretty much the same thing for the actual message so we'll do ms the right we'll do encoding as key get bytes from the actual message so now the packet will look like this we'll have a packet just like that opcode is going to be let's say one that's one byte we reserve four bytes for the length of the message which well the payload which is going to be here let's say the the string that we're sending is uh low there there we go that's 11 characters if we include the white space however if we ever had a message that's longer than 255 bytes that wouldn't really fit that's why we allocate four bytes in order to fit bigger messages so this right here would actually hold the value 11 even though this section right here is four bytes big and we can fit up to 2.1 billion something in four bytes followed by the actual payload right here all right and then we want to be able to get a hold of the memory stream the actual bytes so we'll do public byte array because that's what we're going to return get packet bytes oh i should be able to spell packet there we go here we go close that off and we want to return return ms dot 2 array all right and that's our entire package builder done with you can expand on this later on if you want to there's also going to be a packet reader which is essentially a mirror of this it's going to reflect whatever we're doing here heading back into our server we can create a new instance of that well we can create a we can create a member of type packet builder now let's import the namespace call it package builder now heading back into the server we want to create a new instance of the packet builder because this is where we're actually going to start sending the data so the var will call this connect packet equals new packet builder there we go now remember how we we're going to structure the actual packet we'll do connect packet write off code now for the actual connection packet we'll give it an upcode of zero to keep it simple followed by connect pack connect packet write string which is gonna be username and then we just wanna send the packet so we'll do client dot client send all we got to do is connect packet get packet bytes and there we go that's how easy it is to actually send a packet to a server let's go ahead and interpret this packet on the server shall we so heading into the server program and remember where we wanted to actually set the the username that's right here as soon as the client connect so we're going to need is we're going to need a packet reader we can create a folder call it net followed by another folder call it io we'll create a class called packet reader now this class right here is just going to reflect whatever we're writing so if we write a string we want to be able to read it the same way we wrote it luckily for most of the operations we have access to a binary reader so we can inherit from a binary reader which already has a lot of predefined functions for reading a bunch of binary data so we'll create a constructor in here as well as a parameter we want to do a network stream rather than a memory stream we'll call it ns and i want to pass it into the base class there we go we also want to create a private network stream underscore ns and one instantiated in the constructors underscore ls equals ls now in here we're just going to have one single function and it's going to be to read the message so we'll do public string read message there we go we need a temporary buffer it's going to be byte array message buffer var length is going to be read in 32 because that's the size of the the actual length that we're sending because before calling read message we've already read the op code we haven't done that yet explicitly but we will get to it now the message buffer is going to equal a new byte array with the length of whatever length we just read from the from the server the client now we'll do dot read we want to read into the message buffer we want to start at the opposite of zero and we want to read the length of the actual packet well the payload now we can get the message by var message equals encoding we gotta import that as well as key get string message buffer there we go oh message buffer there we go now we can actually return message as well and that's how easy it is to read the packet that we just sent well at least reading the payload part of the packet so heading into the client this is where we want to read the op code we'll do var op code equals and we don't have a packet reader in here we should probably define one we'll do packet reader actually we can do it in the class um so we'll do packet reader we're going to import the namespace call it underscore packet reader there we go we'll instantiate it in the constructor equals new packet reader and here we need to pass in a network stream so we'll do client socket dot get stream that's how easy it is now we can do packet reader dot read byte because that's the op code we can assign this to a variable opcode there we go now since this is going to be the first packet that we receive and we were following our own protocol at this point you would want to validate the opcode to check if the opcode is zero which is what we're sending if not then drop the connection but again that's out of the scope of this tutorial we're trying to make this as basic as possible so let's keep going now we'll assign the username equals packet reader read was it read string read message no it's not read string it's read message yeah read string is something else and now if we go ahead and run this real quick we chuck the server over there we'll type in a username for instance armada connect we can see that client has connected with the username armada so we actually managed to send a packet to the server the server then interpreted that packet correctly and utilized the payload how cool is that right so we're gonna need a packet reader on the client and we're gonna need a packet builder on the server so let's go ahead and go into our packet reader we just copy this over and create a new packet reader in the client there we go so remove that paste that in import the namespaces now i know that this is probably somewhat confusing understanding like the reading and the writing and why it's got to be on like why why it's going to be on both ends but playing around with this is actually going to make you understand it way better so i'd say after this create a couple of chat applications make one with your friend make one that you host with a friend for instance etc etc you'll get it now the packet builder chuck that over on the server as well so we'll do add class package builder so remove this there we go let's do that ah right now we have the project set up fully to where we can actually send and receive packets just fine right let's start actually working on the fact of where i should be able to connect with multiple clients and because i'll show you the issue right now armada connect right we connect with our mother great we'll connect with foe connect we can see that we actually do connect we're both connected to the server however we're not populating the list how are we going to do that the server is actually going to broadcast out a message to everyone connected saying hey this person connected or like here's everyone that's already connected on the server so you can update your local list so let's start by doing that let's start with the sending of the packet so we'll head into the server into program and right here is where we want to actually broadcast the connection so we'll create a function static void broadcast connection so make sure i spell it right there we go all right we will broadcast a message out saying that a specific client has connected and will pass that client in as a parameter later on but for now let's just focus on one thing at a time we'll do a for each loop that's a for loop for each there we go for each we'll do user in underscore users now for each user that's already connected we want to send out a packet for each of those users to all the already connected users that probably made no sense but it probably will once i actually write the code out so do another for each loop in here for each of our usr in users let's spell that right as well there we go and again there are better ways of doing this this is just the most readable way of doing it in my opinion take into consideration that there are people who have no idea what i'm doing we'll create a new packet because we have a packet builder so we'll do var broadcast packet equals capital sap equals new packet builder there we go import the namespace now let's uh build the actual packet so we'll do broadcast packet write opcode here we go this op code is going to be one so we're going to interpret this on the client as well differently than if we were to send a packet with the opcode of zero because the packets obviously do different things this is how you differentiate each packet we also want to write a string which we're going to do here so right string no it's a write a message no it's actually right string yeah we should probably change that to write message but yeah right message there we go now we'll rename this to write message and obviously we can't pass in a int we're going to pass in the string but what is the string we want to pass in we're going to pass in the usr the current object dot username and let's actually pass in the uid as well which we need to actually cast to a string because it's of type guid to string there we go and then we just send the packet so we'll do user and not usr that's very important dot client clientsocket.client.send i will do broadcast packet get packet bytes there we go and where do we want to broadcast this right after our connection so we'll just do that perfect and now on the client we want to read that packet now heading into the actual server on the client don't get that confused so in the chat client server we want to create a couple of events we also want to create a packet reader that we'll be utilizing so let's go ahead and do that real quick we'll do a public packet reader let's call it packet reader it actually capitalize the peaks it's a public property and we we don't want to instantiate this in the constructor we actually want to instantiate it if we manage to make a connection equals new packet reader and you'll see why and new packet reader there we go because we want to pass in the client of get stream there we go because that's a requirement for this packet reader in order for it to work there we go now that the packet reader is done we can actually go ahead and create a couple of events we'll do public event of type action which is a delegate which returns nothing we'll do a connected event event and we'll also do a actually let's start with the connected event now heading into the main view model underneath the server we can do server dot connected event plus equal in order to attach an event handler click tab to generate a new function we'll call this user connected and this is what's gonna get invoked whenever well we haven't actually told it invoke anything yet but that's the function that's gonna get invoked whenever we receive a packet that has the well the correct op code so heading back into the server we'll do if string is null or empty username so if the string isn't null or empty we can do that and then want to start reading the package so we'll do read packets we can call it interpret packets as well but we'll we'll we'll call it read packets here we go in here we're going to offload this to a different thread because we don't want to we don't want to deadlock the application we just want to offload the data onto a different thread they weren't going to do it we're not actually going to keep keep track of the thread because again out of the scope of this tutorial but let's go ahead and create a new task so we'll do dot run oop we gotta import the namespace so there we go threading the task uh let's run and we'll create a lambda in here oh here we go and in here we're going to have an infinite loop so while true we want to read start by reading the objects with var opcode equals packet reader we don't have a packet reader in here we should probably make one we do have a backup reader packet reader dot read opcode which i thought i had i can just do read byte otherwise read by it works just fine you could create a a function called read opcode as well and just make it return a byte or read the byte from the stream and return that but you know this works just fine and then we'll do a switch based on the op code in the default we can just to console rightline ah yes of course we'll do case one which is going to be op code one and we're not chucking in case zero here because well we're already handling it somewhere else so if we get a packet with the op code of one we want to do connected event if it's not null invoke so we're just not checking it with the question mark this is bare bones of what we're doing we're going to add more opcodes in just a sec let's just finish this one packet first then it's going to be the same thing across the entire thing right so in the user connected in the main view model we want to create a new user so we should probably create the user model so let's go down into the model user use user model there we go let's give it two properties we'll give it a prop string username a prop id which is going to be a type string as well we'll call it uid uid perfect once uh user is actually connected we wanna read because remember how we're sending the username and i guess the uid i don't know did we actually send that or are we we're going to right so right here whenever we a user connects we and there's a broadcast we're sending the username as well as the uid so in the main view model we want to create a new user of our user equals new user model let's import the namespace the username is actually the one that we wrote first yeah equals server packet reader read message yeah and then want to do the same thing for the uid uid perfect now we have the user now we just want to append it to our collection of users so we'll do if users do we now have users we don't have a collection of users oh okay so let's create a an observable collection of type user model so we'll do prop observable collection of type user model called users and spell users instantiate it in the constructor do it at the top we'll do users equals new user model let's go ahead and bind that straight away i'm going to close the chat server right there and head into the actual view this list view right here is going to have the item source binding to users we need a list view item template have a data template of type text block i'll do text binding and we'll do user name all right so we'll do going back into the actual view model we'll do users dot any you're gonna have to import a link if you haven't already which is where is it this one using system.link any we're going to pass it as an x the object has an x x dot uid is equal to user.uid now if the user's collection doesn't contain any user that already has that id then we can go ahead and add that to the collection now you would check this on the server as well make sure that the when the user connects that it's not like a duplicate user now and in order since we're doing this from a different thread we want to use the dispatcher so we'll do application important namespace which is system.windows.current.dispatcher.invoke and we want to chuck in the user to the user so we can actually do users.add just checking the user just like that so if we now run the application i'll chuck the server over here one instance over here and then i just chuck another instance down here we'll connect with armada see that the server gets it and we'll do flow on the other one there we go see how we can now see every user this is so cool now what about disconnecting users or sending messages we're gonna need two more packets that we're sending two different top codes let's start by finding out where actually let's start by sending messages i feel like that's going to be more fun right in order to fix the the actual sizing if you haven't already i'd set the height to 474 and the width to 816. now sending messages is actually really easy so we're actually going to set up the backend first and then we'll do the the front-end stuff so heading over into the server on the client side we want to create a function for we can actually minimize that one for now we'll create a function a public void send a message to server string message is obviously going to be a parameter and we can just build a packet and send it straight away to the var connection no what am i saying not connection packets message packet equals new and we'll do packet builder the connection pack or i mean the the the message packet write no it's message packet there we go dot the to write string we write message we should change that name right message here we go right message is going to be message but we also need to add an op code prior to this so we'll do write opcode and we're going to add the op code of five five is going to be the the option that defines sending a message and this can be any type of message and then we just send it so we'll do client dot client dot send and we'll do message packet dot get packet bytes there we go now we just need to call upon this whenever we click the send button in well on the view so heading back into the view model we also want a property for the message so we'll do instead of a username we'll create a new property call it message which we're going to bind in the view here we go it's going to be bound in here so we'll do text binding message and we don't need to specify the update source property trigger because whenever we click the send button it's going to lose focus and whenever it loses focus that's when the property updates so let's create a command we'll do send message command and we'll create a new instance of it down here send message command it's going to be equal to well actually it's going to be the same condition here to when you can cannot send it but instead of username it's going to be message here we go button command binding send message command which is going to be disabled to begin with and yeah we're going to have to update the do the update source property trigger update source trigger it's going to be properly changed and now if we type something in it's going to work heck yeah what we can do is we can actually do send message to server and then do message rather than creating a uh something over here that actually sends it because that would be kind of redundant in in my opinion so let's go ahead and call that just like so now since we're sending this to the server we need to interpret it on the server as well so let's head back into the server go into program and from here we want to head into client and we want to set up a processor in here which is going to process all the packets that we get so we'll do a void process we'll do a while true because it's going to be running forever until we break out of it being that if something disconnects or if something goes wrong i will do a try catch the exception here you can specify a network exception if you want to again out of the scope of this tutorial we'll do so we want to keep reading bytes essentially we want to keep reading packets we're essentially going to do the same thing we did earlier where we had the event but we're not going to use events here even though you could but we won't because it's we're only going to be interpreting one packet so we'll do var opcode equals packet reader dot read byte there we go that's going to be the op code with our switch statement based on the op code we'll do case five because that's the op code that we're sending remember how we structured it we just got to read it the same way so the var message equals packet reader read message we can write out the message and message we'll actually structure it a bit nicely here we go we'll do time dot oh do it isn't oh it's day time yeah of course date time dot time time maybe now now that's the one followed by message received and it's always just to print out the message as well and then we want to broadcast the message broadcasting the message is super simple we'll head into the program we have a broadcast connection which we should probably spell correctly broadcast connection there we go and now we want to have a function that broadcasts the message public static void broadcast connect no broadcast message there we go and we might as well pass in the parameters with a string message and then we want to send it out to every user so every user in users here we go and then we just for each user we want to construct a packet and send it out so we'll do var message packet equals new packet builder and we'll do message packet write opcode and this is going to be five and the one to write a string so write message it's obviously going to be a message and then just user dot client socket dot client dot send and then message packet dot get packet bytes now going back into the client.cs we want to call that function so do program dot broadcast message and we'll pass a message as to parameter now while we're here we might as well deal with disconnect so if we try to process something and we get an exception it's usually because of the fact that we can't you know read the data because the connection was closed or something that way we want to broadcast a disconnect packet as well so we'll we'll start by printing out uh which client is connected again you should probably error check this uh a bit better if you're planning using this in production we'll do uid to string which i don't think yeah we're gonna need two strings it's gonna print it out anyways let's do disconnect that there we go and then we wanna we'll do client socket dot we'll do close because that's close because that's gonna dispose of the the actual object as well and then close it now we probably want to broadcast a disconnect packet as well so we can actually create one we can copy this one and just change the name of it we'll do disconnect message or actually call it broadcast disconnect and we want to find the user that did disconnect based on the uid so we'll do uid and we can actually remove that we'll call this a broadcast packet i want to find the user as i said so the var disconnected user equals i'll do users where i need to import link where x x the uid is the same as uid let's get the first uh oh right we need to cast it as a string there we go and we want to get the first or default value defaults going to return to null however we want to remove that users remove i will want to remove the user that's disconnected so this connected users now we won't have an issue sending a packet to every user in the user's collection because the one that was disconnected and can't be sent to anymore is now gone so we'll do broad broadcast packet write opcode now the opcode for a user that was disconnected is going to be 10 the data that we want to send is the user id of the the person that was disconnected so we'll do right message it's going to be uid and then we just got to send it so the user.clientsocket.client.send and we'll do broadcast packet die get packet bytes there we go and what's cool now is that since we can broadcast a message to every person on the everyone connected we can just call broadcast message afterwards saying that the user disconnected which will check in the name like so so we'll get the disconnected user that username this connect that perfect so now every client is going to be able to see that right so now we need to head into the server on the client and let's see read packets now we got to interpret two more packets so we got to do case 5 and case 10. so we'll do case 5 followed by case 10 and the events that we want to invoke is not the connected event obviously we want two new events we'll do message receive event as well as disconnect we'll do user disconnect event amazing and obviously it's going to be message received on 5 and user disconnected on 10. looking good so far now in the main view model we want to hook these up as well so we'll do message received we also want to do user disconnected for this one we're going to create a new function which is going to be called receive we're gonna create a method there we go and in here we wanna just read the data that we got sent so the var message equals server dot packet reader which is a public property read message and then we just want to add that to our messages collection which we don't even have yet but we can create one by doing it like that we'll do messages it's going to be an observable collection of type string this one is going to be essentially added in the constructor as well message just there we go a new observable collection of type string which we're going to hook up in the main window as well the messages are going to be displayed in the list view so the only right thing to do would be setting the item source binding it to messages there we go and now we just need to append that to the messages collection so we can do application dot current oop current dispatcher that invoke an anonymous function also known as the lambda and messages that add let's say just dot add and then the message oops there there we go all right and for the actual disconnecting of a user we just want to remove them from the collection so we'll create a user disconnect we'll call this uh remove user we'll create a new method just like that and we need to get the uid first of our uid equals server packet reader read message which is the first thing that we send whenever we get or whenever we do send the disconnect packet the first thing we do send is the user id followed by the username actually no that's the only thing we sent isn't it yes so we're gonna try to find the user based on that id so the users where xo x x dot uid is equal to the uid that we got uh first or default oops first or default there we go and then we can just remove this user from the collection so we'll do app application dot current dispatcher dot invoke and we'll do users remove and we'll get the user in there all right now let's go ahead and do the did we bind the send message command i think we did didn't we right send message command which sends a message to the server now as of right now we we need to head back into the actual server go into the client and start the processing because we we haven't started the actual process function so we're going to do that right underneath here but we're going to offload that to a different thread so we don't you know get caught up on the the while loop so do task oh task dot run and we'll chuck in the process right there and another thing we want to do is we actually want to get rid of this throw statement down here as well as we want to broadcast the you know the disconnect so we'll do program dot broadcast disconnect and we want to pass in the uid to string there we go and then we want to break out of this loop all right and i believe that's it we can we can actually make things look better for instance when we broadcast a message we can let's see so in here we can actually give the the date and the username so we could do something like we'll do something like that i will say date time dot now followed by user name followed by the actual message as well so chuck that in there all right let's try running this real quick i'ma chuck the server over here and decline here i'm gonna pull up another client there we go we'll we'll pull up a third one as well because why not there we go we'll do flow we'll do our model and we'll do uh full bar why not if i send the message right there we can see that foe sent that message armada hello send and well this one as well obviously now if i were to disconnect with armada we can see it disconnected and removed it from the collection that's this is so cool to me i don't know why and that pretty much sums up the actual the actual project now as for all my projects this is not something that you probably should use in any sort of production environment at all this is more so to show you how to create something and the actual concept of it there are things that you probably want to error handle and various other things but that pretty much sums it up the source code for this project will be available on my patreon which you can find in the description down below if you enjoyed the video make sure to leave a like and subscribe and as always i'll see you in the next one
Info
Channel: BinaryBunny
Views: 4,823
Rating: undefined out of 5
Keywords: WPF, C#, networking, chat app, professional chat app, modern chat app, chat server, server, networking server, game server, networking tutorial, wpf tutorial, chat app tutorial, how to code, how to program, how to make a chat app, chat app server, C# chat app, c# networking, networkstream, wpf chat app, how to code wpf, how to code c#, c# tutorial, modern chat app turorial, modern app design, best app design, app ideas, what to code, what to program, how to code a chat app
Id: I-Xmp-mulz4
Channel Id: undefined
Length: 55min 28sec (3328 seconds)
Published: Wed Oct 06 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.