 Welcome back everyone. This is Brian. And in this video, we're going to dive even deeper into Python 3 and we're going to look at what it takes to make a TCP echo server. So what is an echo server? Well, it's a server that handles multiple clients at the same time. So we're obviously doing non blocking sockets. We're going to push this off into a separate process and it's going to echo back the data the client sends it. This is very, very helpful for network programming if you're doing any sort of troubleshooting. Let's dive in and take a look. Step one, of course, is imports. And I'm not going to waste a bunch of time because this video is going to use things that we've already covered in this series. So if what I'm about to copy and paste on the screen makes no sense. Well, you might want to rewind and watch some of the videos. So we're going to use logging, multiprocessing sockets and of course select because we're using non blocking sockets, or more appropriately, we're going to be using asynchronous code. Now this all happens under the hood. So we don't have to worry about async calls select us all the work for us. And of course, we're going to set up our logging basic config, we want to basically grab everything. So we're going to use logging dot debug. And now for the heart of the tutorial, we're going to actually make the function that defines our server and this is going to run in a separate process but of course the way Python handles multiprocessing, it's simply a function. So we're going to say def chat server. And we want an IP and a port. From here, it's pretty standard what we've done before, we are going to deviate a little bit and I'll point those out. So I'm going to say server equals, and we want socket dot socket. And we want the socket dot address family IPv4. Feel free to switch that to IPv6 if you really need it and we are going to be using TCP so we want a socket stream. So we need to say socket dot Sock stream. In case you're wondering, yes, you can do this in UDP but of course you don't need an actual full blown server with multiple connections because of the way UDP works there is no such thing as a connection. So I'm going to just for the sake of time here. We're gonna say logging binding to IP and port and then from here we're going to actually bind some say server.bind and we want to go ahead and make a tuple we want the IP and the port. Of course, if that is already in use we're going to crash our program at this point simply because well that's the nature of what's going to happen you could definitely wrap that in a try finally if you wanted to. So now we want to take this server and set it to non blocking something say server. And we want to set blocking to false. That means from this point forward, we are not going to block the execution of this application. Go ahead and say server dot listen. And I want a maximum of 100 connections here. Info. Actually, what am I doing here? Let's just go ahead and paste it. Why not? We're gonna say listening on. Whatever the IP and the port is. Now from here we're gonna start working with select. So I want a list of sockets we can read from. So I'm gonna say readers. And we want a list dictionary. We're gonna add our server to that list of sockets. Because remember select doesn't care what we add in there. It just wants to know what are we reading from what are we writing to what are we getting errors at. So let's go ahead and say while true we're just going to loop forever. Now we want readable writeable. Am I spelled that I did somebody out there needs to really correct me on my spelling. Erred. That's going to be the select dot select. And if you watch the previous video basically we need to give it a list of things we can read from. So we're gonna say readers a list of things we can write to which I don't really want to pull for writing. So I'm just gonna give it a blank list and a list of things that could possibly raise errors which I'm not going to involve select in that little process. So I'm just gonna give it another blank list. There's probably a more elegant way of doing that but this just works. From here we're gonna say for S in readable. In case you're wondering where readable is coming from it's right here. So what's gonna happen is every single time this loops select is gonna go in and say hey do you got something for me. Be sure of course to put a time out here otherwise you're gonna have a very bad time. So I'm gonna say 0.5 and let's go ahead and try this. So I'm gonna say try. We want a try exempt finally. So for every single socket in readable we're gonna try something and then finally it's going to pass and then let's go ahead and flesh this out first. So I want exception as EX and then we just want to and I'm going to just grab this. I'm gonna put out a warning and I just want to see those args in our log. Finally I don't really care so I'm just gonna pass. Now try this is going to be the heart of our server. I want to say if S equals the actual server meaning the server socket then we want to do something with that. For the moment I'm just gonna say pass and then we're going to say else and then I'm gonna pass on that as well. Just so you can see the structure here. So every single time select fires off it's gonna give us a list of readables. If we have a socket in there that equals our server then we want to handle that. So really all the server is going to do is accept incoming connections. So I'm gonna say client comma address equal and I want to say s.except. We could have said server dot accept but it really doesn't matter. We've already got the object as s and then I'm going to set that client to non-blocking as well. We're gonna say set blocking false. We're going to append that to our list of readers. So we're just gonna take this client and put it right up here with this list. So we're gonna say like client, client, client, client as we get extra clients and then we're gonna have to remove those as they drop out. So let's go ahead and take our client and that to our list. And now I want to say logging dot info. I want to know that this guy actually connected to us here. And let's go ahead and get the address. There we go. So it's really that simple. Really all our server does is it just listens for incoming connections. Once it gets a connection request we go ahead and accept it, add it into our list and then we will handle that later. So when we get to else, that's when we have to actually handle that. That's one of the clients saying, hey, I want to talk to you. Let me fix this little guy. We're gonna have a bad time. All right. So once we get here, I'm going to say data equal s dot recv for receive. We want a maximum of 1024. Now we need to determine if the data is blank. So I'm gonna say if we have data, then do something else. That means we have no data and that socket is now basically closed. So I'm going to say just from the moment pass. Let's jump up here and assume we have data. And I want to know what we're actually echoing back to the client. So I'm gonna say logging dot info. And I'm just going to print out echo and then whatever data we're echoing back. That way I can see it in the log. Grab this and let's go ahead and say s dot. And we want to send them the same information they just sent us. This is the whole point of an echo server. It just literally echoes the data back. Pretty useful. That way you can see if the data you're sending gets changed in transit. I've had actually had that happen before when I was writing a network program. Really, really infuriating. So if there's no data, then we want to remove this. So I'm going to say remove. Now let's go ahead and just say what we're removing here. Go ahead and close that socket down or at least try to. And then I want to remove it from our list. So I'm going to say readers dot remove. And we want to remove that object. Pretty simple, pretty easy to understand. I'm going to give this a good run. Make sure we don't have any gremlins popping up in our code and we are good to go. Now that we've fleshed out the server, I want to do our main function. So I'm just going to collapse that code. Let's go ahead and fill this in. I want our main function to do something a little bit more than just run a server here. So I'm going to say SBR equals multiprocessing. So if you skip that video, I highly encourage you to go out and watch it. But basically we're going to make a whole new process and shove this server out into that process. I'm going to say, whoops, target equals and we want our chat server function. I'm going to go ahead and give it some args. So I'm going to say args equals, give it a list of arguments. We need the IP and the port. So the IP is just going to be our local host. And the port, again, this is going to be very dependent on your system or what you got running, but I'm going to put this on 2067. I want this to be a daemon. That way when our application shuts down, it kills that process along with it. And let's go ahead and give this a name of server. Name is not really mandatory, but it just helps in logging land. All right, so now that we've got the server, I want to be able to do something with it. I don't want to just fire it off immediately because we are building an example application. I want to have the end user have the ability or the control to start and stop that server. So I want to say while true, we're just going to lock up this main thread here with user commands. So command equals, and I want to get the input from the user. I'm going to say enter command, start or stop. Pretty self-explanatory. What's that going to do to our program here? I'm going to say if the command, and you could do some special things like, you know, make sure it's lowercase or uppercase or, you know, there's no padding or anything like that, but I'm just going to keep it super simple. I'm going to say starting the server, so we get some feedback on the screen and I'm going to say SVR. I'm going to go ahead and start that. That's going to kick that process off. However, if the command is stopped, then we want to actually kill that running process. Now, there's a lot of little gremlins that we could introduce here, but I'm going to keep it super simple. I'm going to say stopping the server and we're going to say SVR.terminate. We're not going to do it very friendly. We're just going to say, hey, stop running. We're going to wait for that to join back to our current context of execution. And then we're going to free up those resources by closing that process down altogether. And then I'm going to say server stopped. Once we've gotten to this point, you could actually break this out and then say, hey, we're now done. All right. Let's give this a run. Make sure it's going to give us a command prompt. Okay. Let's see this in action here. So I'm going to start this and we probably have a few bugs we'll have to work out. And we are now listening on localhost 2067. Let's go ahead and fire up command line. I want to open up telnet session. And if you're on Windows, I'm sorry, you're going to have to install probably putty or telnet or something like that. Because I don't think it comes actually built in the OS. Everything else you should just be able to do this. So we're going to say telnet. And this is on port 2067. And my spelling has probably screwed something up. And uh-oh, of course we have a problem. So connection closed by foreign host. That usually is not a good sign when you're connecting to a server. And we got a warning name client is not defined. Name clients not defined. Okay. So what's going on here is we have what I like to refer to as a boo boo. I have client dot address. Well remember socket accept returns two things, not one. And we're basically saying we have a class named client as a property named address. Nope, that's not the case. It's client comma address. We've also introduced another problem. So let's kill this thing and rerun it. And let's try to start this. See now I'm frustrated and I can't type. Uh-oh. Address already in use. When you see this, that means something else is bound to that address. Now wait a minute. We just did it and it just ran. So what's bound to that address of course is our program. And you can see out my system monitor. Python three eight of course is consuming 5.2 megs. And normally I don't advise doing this. You can't see what it is. We can see there is the full path to our script. Python three dash 60.py. So that's what's got that address in use, meaning that is now still running in memory. We never stopped that. Uh, so let's go ahead and kill that. And you can see it is now killed. That should have freed everything up. Let's go ahead and clear that out. Fingers crossed we don't have any other gremlins here. Go ahead and rerun. And let's go ahead and start this. Now we're able to rebind listening on localhost 2067. And let's go ahead and reconnect here. All right. Now we've got a solid connection. Our remote client is one two seven zero zero one on port 52 444. And we can just simply say test. And it's going to echo it back. For example, I can say cat and it will send cat back dog, et cetera, and so on and so on. So let me open up another command line. And let's go ahead and say element. And I want to say one two seven zero zero dot one on port 2067. And you can see we have a different connection. And let me move these out of the way here. And this one is on port five two four six eight. And this thing works as expected. Now we can go ahead and close one client. And you see it has removed that socket appropriately and this one works. So the other connections are not impacted. Now we can take this and have the user all stop. And it does what we expect it to do stopping the server stopped application finish. We've now exited that whole application loop. I go back out to my system monitor. There is no hung process out there. And if we flip back to our command line, we can see connection closed by foreign host because the server slammed that connection close and deleted the socket. I hope you enjoyed this video. You can find the source code out on github.com. If you need additional help myself and thousands of other developers are hanging out in the void realms Facebook group. This is a large group with lots of developers and we talk about everything technology related not just the technology that you just watched. And if you want official training, I do develop courses out on you to me dot com. This is official classroom style training. If you go out there and the course you're looking for is just simply not there. Drop me a note. I'm either working on it or I will actually develop it. I will put a link down below for all three of those. And as always, help me help you smash that like and subscribe button. The more popular these videos become, the more I'll create and publish out on YouTube. Thank you for watching.