 Hey everybody, it's Brian. Welcome to the 134th Qtutorial with C++ Inquiry Programming. We're going to be continuing the high performance TCP server design. This will be part 3. I did get a message on Facebook last night saying, Hey bro, yeah, you got your numbers wrong. I guess there's two 132s. So, yeah, this is actually going to be 135, but I'm just going to keep the numbers because, well, I'm lazy. And, hey, while I'm looking at this, we got some feedback. Slumdog says, nine hours ago, In TCP connections, except when connecting disconnect and error, I get no matching function call. Hmm. I copied them from TCP connections, set socket, where they worked. Interesting. We're going to look at that real quick. So, you know, I think my headset just cut out. I've got this wireless headset and it just drives me nuts. Because I won't know when it cuts out, but I'll hear it beep when it reconnects. So, I'm sorry, I'll repeat what I just said in case it did cut out if I didn't just fast forward through this. Slumdog is saying that in the TCP connections, except when he connects the disconnect and error signal slots up, he gets a no matching function call. So, he copied them from TCP connections, set socket. I've already gone ahead and done that. I'm not sure where he was getting it. I'm not seeing really a difference here. So, anyways, the originals commented out and here's the one that I copied and I modified the class names. So, I'll just give this a good build. What did I screw up here? Oh, yeah. We are going to fast forward a little bit, ladies and gentlemen. I actually deleted some stuff here. So, let me look at my notes. We're going to just do some includes here. QtBug, QTCP server, Qthread. We're also going to include our TCP connections. I've started running again, so I'm kind of tired. I'm not a big fan of running. I don't know why. I just don't like it. Alright, so virtual, bull. We're going to do listen. We're going to override listen. We're going to override close. We're going to add port, just because I really want to. We're going to add a protected section in here. We're going to say Qthread and connections. Yeah, I don't know what it is. I've got these Logitech. What are they? G930. It's once in a while. They just randomly cut out and it's at like the worst time. I'll be playing a video game with some of my mates and I'll say, hey, you know, go over here and kill this guy. And they don't. And I'm like, I hear my headset beep, meaning it just, you know, it just reconnected. And I'm like, oh, you didn't hear what I said I did you and they're like, nope. And then the whole team dies and they get mad at me, but whatever. Now the incoming connection, this is something you'll have to be a little careful about depending on your Qt version. I've seen Q int 64. I've seen Q handle. I've seen Q int pointer. The Qt documentation says they're all pretty much the same and they should work, but I've actually seen it where it'll compile in a run. It won't issue any errors, but you'll never see an incoming connection and then you'll have to go in and modify this variable type right here to whatever your platform takes. And unfortunately, the documentation is horrible. So I'm just going to comment this and say, could be a Q int 64, could be a Q handle, could be a Q int PTR. And in some really bizarre instances, I've just seen it as int or actually it was what was it you int unsigned integer. So I'm just going to leave that in there commented that way. If you have a problem, you don't have to go look it up. You can just grab one of those types. All right. So virtual void except Q int. And what am I using Q int pointer? Call us the descriptor because it's descriptive. And whoops. Did I just hit caps lock? No, I didn't. We're going to give this a pointer to the a connection object. So what we're going to do here, and I'll kind of flesh this out as I'm talking is we're going to make some signals. We're going to say void except, except ding. I cannot type. Man, this keyboard is possessed. You ever have one of those days where like everything just does not go great? That's kind of my day so far. And you can see it my typing anyways. So we're going to emit a signal. And the signal is going to have the handle or the socket descriptor. And it's going to have a pointer to while you guessed it a TCP connection object. So we're going to actually create the connection and then move it to another thread. Let me see if I can actually do this. This is somewhat embarrassing. I almost feel like just stopping the video and starting over. I actually don't edit any of my videos. I've been told that I should. I just don't because I don't really have the patience for it. Number one, I don't have the time for it. I mean, some of these videos, depending on how many takes because I don't always get it in the first take, it can take me two to three hours to do a video that's only 15 minutes long if it's a pretty complex topic. And by the time I'm done, I just, I don't want to add logos and glittering lights and bouncing bunnies and all that garbage. I just want to get the stuff out there so people can play with it. Oops, let me close that. So we got accept already. Damn you cursor. Oh yeah, it's a signal. I probably shouldn't do that. See what I mean by having one of those days? All right. So we've got those many anything I'm missing. Oh yeah, I'm missing my slot here complete. All right. So we've got our basic server. Let's give this a build and just make sure this is actually going to work without exploding on us here. All right, good. So we've got some warnings and they're just unused parameters, but we'll get rid of those. So if you guys have wireless headsets like wireless gaming headsets, I'd be really interested in knowing what you use and how you how you like it. My G930 Logitech is just kind of really pissing me off. I'm just going to say it. I almost threw it across the room the other day and I'm usually not like that. I got it because A, I like to game and B, I like making tutorials. And sometimes when I have this cord, I like turn my head and it'll snag the headset, which just, oh yeah, that's the worst. I just want to like flip the desk over when that happens, which ironically I have a cord mouse and you know, I have a hardwired mouse and a hardwired keyboard, but a wireless headset. Don't ask me why. You probably never actually see that Q-Debug message right there, but you know, whatever, we'll just do it. All right, so let's do this. Address and port. So when we're listening, we're going to, you know, return false if the base class, the QTCP server cannot listen. If the QTPC server base class does listen, then there's some extra magic we want to do here. So we're going to say mthread. Did I not make mthread? Or is my computer just being stupid here? Hmm. I did not make that. I actually screwed up here. There we go. That should be better. Man, that was kind of scary. I would just kind of like froze and went, oh no, what have I done? Like the universe as we know it's just going to, you know, cease to exist because I screwed something up here. All right, so we're going to make a new, maybe, new Qthread. And I might get an email saying, why are you making a new, you know, why are you making a pointer? Why don't you just make it as a member? I just wanted to just have it, you know, it's kind of my answer when people start questioning me. I just go, I just wanted to do it my way. I'm sorry, I'm the one writing the code, but don't ever tell your boss that, you know, I always follow corporate standards, but yeah. All right, so we're going to make a new thread, and we're going to make a new connections object. Remember the connections object is what's going to hold all of our connections here. And we need to connect up some signals and slots here. So we're going to connect, and of course it's right over my notes so I can't see what I'm connecting. We're going to connect them thread. What do you guys think about the new Q5 way of doing signals and slots? Once I got into it, I actually kind of like it. It's a lot easier than having all the parameters and stuff in there. And we're going to connect the TCP connections start. So when the thread is started, we're going to call TCP connections start. That's important because we're going to move the connections object that we're creating in the line 18 here. We're going to move that to a separate thread. And last but surely not least, this is probably something you might not have seen before unless you've watched some of my threading tutorials. We're going to give it a parameter of cued connection. Signals and slots don't always connect the right way. You can have what's called a direct connection, an auto connection, or a cued connection. A direct is like a one to one. Typically you do that if they're on the same thread. Auto typically defaults to a direct connection, which we just talked about. And then a cued connection, which we're making, is for cross-threaded signals and slots. You throw it into a queue and then cued does some magic under the hood and says, hey, when it's ready, you know, pull this bucket and look for signals that you're connected to. So if you try to do an auto or a direct connector, you just don't specify it. It's going to have problems. So, all right, what are we doing now? We're going to use QTCP server. Oh, no, we just want TCP server, sorry. We're going to accepting. We're going to take the accepting signal from our server object here. Oops, I got an extra comma. And wire that up to the connections accept slot. And if we, I'm going to kind of jump into here. If we go into the connections accept slot, that's where we're actually making the TCP connection. You know, the socket, we're setting the socket descriptor, which actually accepts the connection. So we're not actually, you know, going to accept the connection in incoming connection. We're going to actually just forward it. All right, so, all right, so we're going to do finished. My eyes got a little blurry for a second there. Bear with me. I had, if you've never watched any of my videos, you know, but I had PRKI surgery. It's similar to LASIK. And I'm almost, I'm actually at 2020. One eye is 2025, but I'm very happy with the surgery. But sometimes my vision just kind of fluctuates in and out. And I got to stop for a second and just kind of, and I think the doctor explained it to me. It's kind of weird if you're interested. Otherwise just put me on mute because I'm going to go in a rant here. It's basically, you know, your eyes are adjusting to not wearing glasses. So sometimes your eyes think they still need glasses, even though they don't, if that makes any sense. So while I have 2020 vision, my brain still thinks that I need glasses. So it says, whoa, where are my glasses? And your vision gets like blurry for a minute. All right, so what we're doing now is we're saying when the server is finished, we're going to tell the TCP connections class, remember it's the container that's going to hold all our connections to quit. We're going to say, hey, stop what you're doing, kill all the connections, you know, die essentially. All right, so, and I'm just for the sake of time going to copy and paste. I don't know why I didn't do that earlier. Maybe I just like talking. All right, so we're going to connect the M connections, TCP connections finished to this TCP server. And we want the finished socket here. All right, whoo. So let's kind of go through these super quick. I know I talked about them, but the first connection we're making is the thread started to the TCP connections start. Because we're going to be moving this to another thread, the connections object, we're going to move it to a thread. The server that we're in, the accepting signal, is going to wire up to the TCP connections accept, and that's where the socket's actually going to be created. We cannot create the socket here, because this is going to be on the parent thread, the main thread or the GUI thread as it's called. So if we create the socket here and then we move it over, we cannot connect signals and slots to it. So we have to create it on the parent thread. I should say the thread that it's going to live on. And then we're going to take this object finished and tell the connections object to quit, which is going to kill, maybe. Let's go look at it real quick. Yeah, it's going to remove all the sockets and remember and remove sockets. If it's running, it's going to actually disconnect all the signals and slots and then close the socket down. And then we're going to, in the connections object, we're going to say when it's finished, TCP server is going to be finished. Is that right, finished, or maybe is that complete? Yeah, that should be complete, not finished. There we go. All right, so basically what we're saying is once the connections class, let's pull that up. Let's look at quit here. Yeah, we'll call it quit. It'll do everything. It'll close all the sockets down. Say I'm finishing and it's dying breath. It'll say I'm done. It'll admit finished. And when it does that, the server's going to know down here that, hey, it's done. All the connections are closed. We can safely shut the server down. All right, here's where the magic happens. The problem is you cannot have, say, a thousand connections on your main thread because it will drag your GUI thread down. So we're going to make a thread, which we've already done, and we're going to say M connections, move to thread. And then we're just going to give it the M thread. Now let me explain this for a quick second. Some of you may be going, why are you doing that? And some of you are going, well, duh. The reason why we do move to thread is there's a very lengthy article about threading done correctly in Qt. And what a lot of people do, well, they will inherit the Q thread class and then they will override the run function. And that's actually not the way it was meant to be done. The actual author of the Q thread class posted a very lengthy, you can find it on Google, a very lengthy article about how that's incorrect. So the correct way of working with a thread, because a Q thread is not a thread, it's a wrapper around a thread. So the Q thread, you create that, and then you move objects onto that thread. So it'll take a reference and shove it onto that thread that it holds internally. All right, now we take our thread and we're going to start it. Last but surely not least, we're going to return true because we're listening now. All right, so I know this is a little bit of a beefy function. We'll go through it real quick. We'll create our thread, create our connections, wire our signals and slots, take the connections and move it to the thread. Notice how the thread's not running yet. So we're just taking that pointer and moving it to the thread. And then we're going to say thread start. And when we start that thread, this connection's instantly going to fire off. It's going to say the thread started, it's going to be admitted, connection start is going to be called. So if we go into connections and start, we'll see connection started on blah, blah, blah. And that's why we have Q thread, current thread, because we'll see that's a different thread and we should actually think about it. That way we can see they're different threads, right? So you'll see the server and the connections are on two different threads here. Whew, that's a little bit of a mouthful there. All right, so now we're going to go with the close. I started watching, I don't know if anybody out there watches Walking Dead, there's a new spin-off called Fear the Walking Dead. While I watched the pilot and I thought it was entertaining, I'm not sure how I really feel about it. It's not the same, you know? It's just there's something... It doesn't have that gritty, raw factor that I really like in Walking Dead. But I like kind of dark shows. Like I love Breaking Bad, I love Walking Dead. So anyways, in close, we're going to just, you know, a debug of we're closing the server, we're going to admit finished, and then we're going to actually close the server. Now, when we admit finished, this is going to fire off. It's going to say a server is finished, so the connection should quit. Now, remember we're going to wait down here, we'll actually have a completed port. This is just something I wanted to add. So we'll say if is listening return and I wanted to do this so that I could return a default port because as we inherit this class, different protocols have a different default port like web drive traffic is typically 80, FTP is typically 21, you know, things like that. Alright, so incoming connection. This is going to be the single most frustrating thing about this program, not because of its complexity, it's actually very simple, but because of the way Qt versioning has been handled. And I kind of touched on this with the Qt int pointer and remember it's in the header here how it might be different depending on your operating system and your Qt version and your Qt build and all this other stuff. So just beware if you try this and you get no connections, switch that variable type, play around with it and you'll get it eventually, but if you're going to deploy this on multiple operating systems you may actually have to reimplement that for each OS which is kind of a pain and really pisses me off. Attempting to accepting. That made no sense. No, my new job is actually I like it, it's quite fulfilling. I've worked there before for about 10 years, but there's a gym and it's like a couple floors down from me and it's free of charge of course and now I'm going to the gym every day. So you work an 8 hour day and then you're just tired. Let's go. What did I do wrong here? Excuse me, what did I do wrong here? Oh, I see what I did. I was looking at my notes, I'm sorry. So we're going to take a TCP connection. Oh, I do not want to print that. Now notice how we're making a new object and we're not giving it a parent. We're not saying this. We're doing that specifically and I'm pointing that out because you may be inclined to do this so that you have resource handling, memory management basically so that when this class is closed it'll close the connection object. Do not do that. We're creating this object in memory without a parent so it's just out on the heap out by itself with no parental supervision. We're doing that because it's going to get moved to a thread and you cannot have a parent object when you do that. You'll get all sorts of errors and then we're just going to call the accept function which is well right below and we could have very easily done both of these in the same one. The first one to admit that but I wanted to break it up so it was very very easy to understand the logic the flow of the application of what was going on here. Here we're going to take that individual connection object that we just created in incoming connection. We're going to move it to the thread and then we're going to emit accepting. So the reason why we're doing this via signal slots instead of just creating a function in moving is because you cannot cross call functions through different threads meaning if you have object A on thread 1 and object B on thread 2 you can't call those directly. You need to use signals and slots and that goes back to our cute connection signals and slots that we're using because we're doing a cross thread operation there or I should say a cross thread message if you will. Accepting and when we look at this we're going to say this accepting connects to connections accept and remember connections accept is where the socket is going to be created etc etc etc that's mouthful here now my goal for this is to actually get this class done which we're almost done and then wire it up into our GUI and then maybe do a bit of debugging in case I screwed something up really bad and hopefully get an actual connection running tonight but I got to really watch that clock because YouTube gets kind of squirrely on me maybe it's not YouTube maybe it's my encoder that I'm using alright so yeah but anyways what I was saying let's change this to Q warning the fear of the walking dead well I thought it was alright it was kind of slow I mean it was an hour and a half long and it was a lot of just following this junkie around the mean streets of I think Hollywood or LA I couldn't tell which and it was like it was alright wasn't the greatest thing but then again you know walking dead season 2 they spent the entire season walking around the woods looking for some little girl so they could have collapsed that thing into like 2 episodes alright so and here I am actually going to delete the M connections object normally I do a delete later but I want to actually hard delete that and just get rid of it because we're done processing everything and I don't want to wait around I do not want to wait around for it you know what I mean so Q debug and it may seem a little hypocritical but I'm going to explain why in just a second why I'm deviating from my standard here alright you know quitting thread we're going to wait oops I'm sorry first we're going to quit then we're going to wait and then we are going to delete the thread it was like really cloudy and thundering and lightning earlier so I'm kind of hoping we don't get any storms because I will shut my computer off because I love my computer alright so this is why I'm deviating in the complete remember we're not calling complete until the TCP connections has closed all the sockets and done all this nice little cleanup here we'll call complete and we'll jump down here and if there's no thread we're just going to exit out I feel like I'm going to sneeze I could promise you that if I do sneeze I will not pause the video so that you could witness my beautiful sneeze excuse me alright so we're going to delete the connections object because we're done with it the reason why we're not doing delete later is because we have no idea when Qt is going to do it's cleanup we have no idea when it's going to delete that object for us and we want to get rid of this thread well if we do delete delete later and then we do delete thread we don't know in which order those are going to be deleted so if we do delete later on connections and thread and Qt decides to delete the thread first even though it still has the connections object it's going to have a segment fault now I'm sure there's ways to code around that and fix that problem but I just want to take the easy route and I just want to make sure it's deleted in the order that I want it deleted in let's give this a good build hopefully we don't have any problems wow we locked out of course I probably just totally jinxed myself right alright so alright we got a little bit of work here on the GUI and then we're good include TCP server oops I don't want those there we go so there's our beautiful little server sometimes I feel like Bob Ross if any of you guys know him he's that artist that had like the afro thing going on even though he's a white guy and he would paint these beautiful little trees and it was just hilarious to listen to him we're going to paint some beautiful little code in case you're wondering what Q host address any is you can actually have multiple IP addresses and typically what a server application will do is you'll take a specific IP address and bind to that we're just going to say any just because well I'm lazy we may actually do later where we do specific IP addresses and enumerate through them and all that but that's more of an advanced tutorial so we're going to say if we were able to listen run some code otherwise don't run some code we're going to so server started I almost want to like throw some theme music in there like yeah it started I'll throw a critical oh man I really feel like I'm a sneeze see I pet my cat and then I started writing code and I know at some point I like itched my nose or whatever and now I'm going to sneeze damn cat strikes again alright so we're going to have server close and then we're going to set that so well I'm in a truth here save and run so our server was created let's try to start it alright so dialogue server created TCP connections started so if we actually let's just open a telnet I probably should move this out of the way so you can see yep we have attempted to accept connection created the connection class the server accepted the connection and we have zero clients that's not right let's do a bit of debugging here guys and figure out what's going on socket notifiers cannot be enabled or disabled from another thread hmm I'm going to do a bit of debugging and if I can't figure it out I will debug it offline and then the next tutorial I'll show what the problem was but this is why we want one of those queue debug statements so we can actually figure out what in the heck is going on here so let's actually let's step through this dialogue server started connection started attempting to accept connection connection was created alright the server accepted connection connections client zero closing server that never actually went through here so if we go where is it where is it where is it accept let's just do a little debugging here actually this was actually requested by a few people they're like you need to start you know doing your debugging on the screen so we can see your process and we're like it's nothing magical I usually just throw a queue debug statement in there and go hey watch this you know it's usually nothing very fancy at all and let's see here just something to get my attention let's clear that out I'll bet you that's the problem is that this connection is actually never getting triggered here so we're just going to reconnect nope hey watch this is in there so TCP clients this client's connections count I'll bet you we forgot to actually add that in here I think that's the problem we'll see here connection and we probably need to do this connect oops maybe I don't want to do that let me think about this for a minute here because we created the connection on the server right or are you admitting that we're going here to accept hey watch this popped up let me look at my connections here let's do this let's go queue thread current thread let's move that object in here and insert this and then emit the connected object because it was barking about the sockets not being connected here alright so let's I'm going to try it one more time and if it doesn't work I'm probably just going to stop this video do a little debugging and I'll throw it in my next video here so we've got that in here we're going to actually see if I can get this on the screen alright so we've got one client but we're not getting any signals and slots from that client what did we do wrong here I bet I know what the problem is alright so another thing is whenever you stop you should always watch to see make sure we're deleting like the socket we're calling destroyed I think I know what the issue here is we're going to actually go connection let's look at our connection object here yeah we need to set that socket that's the problem I don't have my notes for that up with me so I'm just kind of winging this here but the fact that I've been working on this for months and months and months is kind of like you know it's just burned in a memory at this point so once we've moved the thread then we're going to say connection let's set socket socket and that'll wire up the signals and slots and that should work and if it does I'm going to do the happy dance alright so let's get this bad boy over here hey alright so now we've got ready read signals so we have got a working TCP server here let's actually close this oops I forgot you got a Damu Linux I'm just going to close the window and then remote we got a socket air remote host closed well we figured that so we're moving the socket so we can see the socket got removed socket is open attempting to close it deleting socket client count zero so you can see that it's actually done the cleanup and all that so let's just leave this thing running and let's let's get a little funky my daughter hates it when I say that let's get funky anyways so we're going to load up Siege and if you watch the previous tutorials you know what this is if not it's a website testing tool where you can put a website under siege by hammering it with connections so we're going to make 800 connections and we're just going to hit our address here and let's actually clear this out so we can see this thing going in real time there we go and you can see how we've got all our connections here server is now under siege so if I hit that boom you can see how it all well if you really wanted to go through here you can see how it's you know going through all these connections it'll go through 800 of them like there's 719 client count see if we got I can't seem to find that magic spot where there's actually 800 anyways you get the picture and it goes through and it cleans up each and every connection now someone's going to say well you're getting errors there's a remote host closed that's actually because we connected the error signal and slot if we didn't connect that we just get the disconnect signal and if we look at siege you see we got 0 hits because we're not actually returning an HTTP protocol and that was over 6 seconds so if we start actually just closing those like let's try it why not I've got a few minutes left in this video connected so as soon as we connect actually as soon as we ready read did we get ready reads I don't remember we should have yeah we're getting ready reads because it's going to send the HTTP protocol we're just going to go mmm equal get socket socket.close we should do a little defensive programming here if not socket return I just want to actually see this working in siege here let's actually close that out load this bad boy back up start this get my command line back up we're going to hammer this with siege again yeah and you can see how now it's actually doing it and it actually gave up because after so many connections failed transactions 1800 failed transactions they're failed because we're not returning the HTTP protocol but you can see that in under 2 seconds we handled 1800 connections and that's just on my little Linux box here kind of running out of steam getting a little tired so I think that's all for this tutorial I hope you found this educational entertaining this source code and all other source code is out on my website voidrealms.com also be sure to join the Voidrealms Facebook group I added 8 people today I think we're like up to like 270 programmers in there and it's just a free for all you go in and ask whatever questions you got alright thanks for watching