 Hey, everybody, this is Brian. Welcome to the 136 cute tutorials with C++ including programming. We're going to continue our high-speed performance TCP server. Actually, it's an HTTP server now So this will be part five. I'm mentioning that in case you're just tuning in. There are four previous parts to this and there's hundred and thirty some odd videos out of my channel specific to C++ and cute Did have some good feedback. I do try to look at the feedback But I don't get out there very often and this fine young lad Cullen reminds me of what I was talking about was the field programmable gate A ray. Oh my gosh. Why didn't I remember that? Of course as soon as I stopped recording. I actually remembered it, but you know Every time I turn this computer on I swear I smell burning cat hair. I Don't know what the deal. Maybe there's some cat hair got sucked up in there anyways Also, this gentleman says To add a definition. It's alt enter enter and then I get to go back you go alt left So we may try that no promises on how that's going to work out All right, so today what we're going to do is we're going to continue But if you remember where we left off is we have a shell of a web server I say a shell because it will send the the actual header Yeah, right here. It'll send a header of either, you know, 200 okay Or it'll send 404 not found, but we're not actually sending the file And we've got a lot of these to do make a rate controller make a rate controller I mean they're all over the place in this thing So that's actually what we're going to do today is actually make a rate controller. So What is a rate controller and why does it smell like burnt cat hair in here seriously? What is that? anyways If you if you do a speed test I'm sure some of you have some just blistering internet speed some of you have Something like this where it says five point something megs per second Some people have more some people have less depending on where you live and you know all that stuff Some people have fast and people have slow my point is Just because you have let's say a five point six megabit connection to the internet You're not going to download files at that speed There's various things that come into play first off your ISP. Let's say you're using I don't know Comcast They're gonna throw out of your connection They say they don't Every ISP says they don't but every ISP does it they have to Because if they serve everybody as fast as they can all the time, they're just gonna simply run out of bandwidth So Imagine and actually kind of got these backwards here Just think of traffic This is a lot Sim a lot similar. This is very similar to a network. You see all these little cars or all these little cars are packets Every single one of these things is packets and it's just all backed up. That's called network congestion or lag or latency So what you have to do is you have to throttle that similar to a traffic light where you stop go stop go You you know got a controlled traffic because if you don't it just becomes this big traffic jam nightmare And you know some places are better than others, but wow, that's actually a map of traffic congestion That whole area sucks. I've been there anyway, so a rate controller Actually slows us down and it does it intentionally so like this little meme here of a speed limit 70 goes 30 That's what we're gonna do. We're gonna slow things down We're doing this because as a server remember we're writing a server if you were to send the file as Fast as the server could do it. You're just gonna flood your connection And you're effectively going to block all the other clients trying to download So that kind of defeats the whole point of having a high-performance server Now I know that You may be sitting here going well. What's the point of a rate transfer if you're trying to make high performance? I want this thing to go as fast as possible That's great, and you can make it go as fast as possible But in doing so you're only going to be handling one download at a time because you're just going to completely flood that network connection All right, so We've got a simple rate transfer class and the goal of this the goal of this specific tutorial is we're gonna flush this thing out and we're gonna be able to choose a Source qio device and a destination qio device and then send those five send the data from file a to file b at a specific rate so First thing we're gonna do include qio device now Why are we doing qio device? Because a socket a q socket and a q file both inherit qio device, so it just makes sense Because we don't want to write two classes. We don't want to say Source is a socket destinations a file and then oh well. I want to flip those around So I got to write a whole new class. You just don't want to do that. We're gonna use a q timer whoops My throat's a little little raw. So if I clear my throat a few times, I'm sorry. I'm trying really hard not to It's just Very hot and humid here. I don't know why it's just kind of weird So let's just out here, and I'm gonna try not to make this an hour-long video I've been babbling for like three and a half hours about this. All right, so We have rate we're gonna int size whoops So the rate is the specific rate we're going to send the size is the packet size or the buffer size So for example, you can have a rate of say a megabyte per second But you want to do it in chunks of say 10k per chunk Makes sense if not it will the maximum is just something I threw in there It's like the maximum number of bytes So you can say I don't want to send the whole file I just want to send like part of the file probably help if I did that. I cannot type I Yeah, I had a long weekend. It was my birthday. So I pretty much did nothing but eat cake and play video games and today I went back to work and Yeah, and then I went to the gym. So it was a double shot of not awesome All right, so as you can see we've got a rate size maximum source and destination And we want to just add in is transferring just because and We're gonna do a Q string Terror string that way something goes wrong. We know let me scroll down here. Whoops. See We're gonna make our private or our protected variables here Just looking at something. I wondered if I screwed something up, but I don't think I did We're just gonna keep plowing through here. There's why it's not picking that up right there It goes for some reason it wasn't auto indenting. I'm not sure what the deal there was Maybe I misspelled it just didn't figure it out. Sometimes. I'm just a little brain dead when I'm like tired and Going to the gym and all that just kind of wears you down so M transferred is the number of bytes that we've currently transferred Just cuz the rest of these are pretty self-explanatory, but that one probably wasn't going to you know The beauty of copy and paste I hate typing they need to make a computer that can like read your thoughts Cuz I just I hate typing. I don't know why Well, I do know why because I do it all day long. That's why I hate doing it Q trimmer that was nice Q trimmer gonna make a timer. Alright, so what we've got here is we've got our protected variables for the most part We've got rate size transferring Maximum transferred source destination the timer and error for the error string and whether or not we've currently scheduled And then gosh, you know, there's that smell of burnt cat here again I'm really wondering maybe I should just crack open my computer and get it over with cuz man That was strong that time. Maybe it's my power supply starting to go Which I'll be really not happy So we're gonna set the defaults check the devices because you need to check make sure the source and destination are actually ready and then Check transfer because we're gonna check to see if we can actually transfer and It would probably be super awesome cool if I actually spelled that right Transfer, there we go. Then we're gonna schedule the transfer the premise of this is When this thing's going we're gonna be sending several dozen hundreds thousands of packets per second depending on how big we set the size and Once we hit a certain bytes per second the rate We're gonna stop and then we're going to schedule the transfer and The transfer will resume using a timer. What's it called a single shot? Did you think about that one? I was like, man, what's that called? Don't you hate it when you just you know something is right on the tip of your tongue? It's been happening to me more and more lately Everybody kind of jokes cuz it was my birthday that it's you know getting older. I think it's just stress and being tired and Switching jobs and my daughter got married and it's been kind of a crazy summer. Oh, and I went to Europe for two and a half weeks and You know they say that that jet lag you get over that in a few days, but I've I've been back a month and a half I'm still still feeling jet lagged Maybe need to go back to Europe for two and a half weeks That would be nice, right? Okay, we're almost done fleshing out the header here. So we got our public slots. We're gonna do a start Stop and I'm gonna do protected slots Now remember protected is only for this class and classes that inherit this class. So these won't be public Read read. No, we want ready read. Sorry And void Byte's written Q in 64 bites. All right. I Always like that word bite bite me. Anyways All right, so looking at this header, you can kind of see what's going on here where you've got some getters and setters Then we've got some internal where we're gonna set the default check the devices schedule a transfer Some signals we're gonna pump out Some slots like a start stop and we're gonna actually do the transfer You know whether or not we've got ready read whether or not we've got bites written All right, so let's see if that gentleman was correct. What was it? Was it alt enter? Hey, look at that Alt enter and enter again And then what was it alt left? Oh my goodness. Look at that. It's almost like it was meant to be We're gonna have some fun with this of course now. I forgot where I was and I need to go back Damn you maximum and set maximum. All right. All right, so oh my gosh That's so much nicer. It's gonna be so much faster than clicking around and I guarantee you by the next tutorial I'll completely forget how to do this and I'll be like, I don't remember what that was and he's gonna be like dude seriously All right, so if anybody was wondering you just you mouse over it you press alt and enter Well, of course now it's not gonna do it. Let's go down to one. I haven't done yet Alt and enter and it brings up that little dialogue and then you press enter again Pop and it brings it up actually creates it. You press alt and left arrow to go back Pretty slick See that's why I love you guys. I have a question. I ask you answer and you don't call me stupid most of the time Although I do get some fan mail once in a while that I just want to like find where the person lives and just destroy them Usually my definition is if hurt my definition my response is if you think you can do better Why don't you make some videos and post them and of course they never do but whatever I'm not saying that I'm better than them. I'm just saying a lot of people are very quick to judge But very slow to actually do anything about it All right, we've got this bad boy first thing we want to do is you guessed it set defaults Whoops, and we got our maximum. So we're gonna return. Yeah, let's do it after maximum set to and You know what? We're just gonna do this why not Remember we want a lot of debug statements just because we really want to see what's going on in memory And we can always filter these out later. Notice. I'm using cue to bugs instead of cue warning or cue critical All right, so magic of copy and paste again Where's my other ones? Had some beautiful ones here that I miss size. I totally miss size didn't I I did See old habits die hard. I'm already right clicking. Did I miss rate too? I did miss rate man See I was so enamored by the new fangled way of doing things I completely just blanked out there Whoops now remember the rate is the bytes per second that we're gonna send and the size is the size of the buffer that we're Gonna send each and every time The maximum would be the maximum number of bytes in total that we want to send Which I don't really remember if I implemented that fully or not, but we will find out So I'm dying to ask you guys. What's good on Netflix? I've been kind of watching some shows And I'm kind of getting burned out on a couple of them But I was wondering, you know, what what are you guys watching because? We're all kind of into like the nerd stuff that I totally just mess that up and destination I don't want device. I want source set to there we go Destination set to you should probably fix some of these little errors real quick here. Whoops That would have been like not that would have been the opposite of awesome Okay, let me look at my notes. Make sure we got everything here. Oh, yeah Yeah, we're missing some stuff here set source, okay So if the source is sequential then we want to Connect a signal slot. Now. What is six sequential? Sequential would be anything that just goes one after another like a socket There's no way to go backwards in time on the date on a socket So like a queue file would be random access meaning you can jump to the beginning or the end or anywhere in between We're like a socket is sequential. You can only go forward in time so Because of that, there's a bit of confusion with like queue file and queue socket Or I'm sorry qtcp socket because some of the signals and slots don't work depending on which queue device you're working with so Yeah, it's kind of crazy So we're gonna connect the source qio device Ready read to do this Great transfer Ready read. Wow in my notes. I actually have it wrong. Hmm Well horse pucky Okay, so basically what we're doing is we're saying if the source is sequential in other words if it's like a socket Not a file because it could be either or then we're gonna connect that signal slot And I'm pretty sure we want to do the same. Let me check my notes on the destination here Yep bytes written. That's what it was. I'm like blanking out here and I'm like So if the destination is sequential like if we're sending to a socket then we want to connect the bytes written to the bytes written Now why are we doing this well The source we want to read the ready read and when that is Emitted I don't we don't want to read the ready We want to connect to the ready read so that when that is emitted We know that there's data in the socket and then we can read from it and we can transfer The destination however if that's sequential we want to wait until the bytes have been written to the socket and Then we will pull out and say all right send more if there's available instead of just keep flooding Because that device we don't know the speed of which it's transferring In networking there's a concept called windowing where they will send as much data as they can and They'll just overflow the socket and then they'll send less and less and less and less until they find that sweet spot Where the socket's happy that's called windowing How do I know that I read a lot of books, but anyways All right, so let's see here. Where was I is transferring air? Oh, yeah set the defaults I'm going to just copy and paste because I don't want to sit here waste 10 minutes of your life Just typing out variables with the values. So we're gonna set the rate the size the maximum to zero We're not transferring we've transferred zero bytes the source is zero the destination zero remember these are pointers So we're just zeroing them out error is empty these we're not scheduled and the timer we're setting the interval to five milliseconds, so That's what we're doing there Check devices. We're gonna be calling this gosh, you know, there is that burnt cat hair smell again I better not be like a dead mouse in my computer See now. I'm kind of wondering but but for some reason these newer computers The power supply is in the bottom instead of the top like the old-school towers. It's in the top But it's in the bottom now, so I wonder if it like sucked up some cat hair in the power supply or something I don't know. So if there's no source, you know sources and available We're gonna stop transferring if we were So anybody out there play World of Warcraft all my friends are playing it I yeah, I used to play it a long time ago when it came out like a decade ago But I don't know. I just kind of whatever I got out of it Everybody says it's completely different now. I'm kind of wondering if I should get back into it All right, so then we're gonna admit the error and we're just going to return false Because remember this this function is going to take a bull Or it's gonna take a bull. It's gonna. Yeah, I'm gonna take a bull, honey. No, it's gonna return a bullying Magic of copy and paste no destination device So we're gonna make sure that thing is there and then we're gonna say is Open Where's my or or? Not m source that is readable So we want to make sure the source is open and readable All right, so we just want to throw that out there So we're gonna do pretty much the same thing for the destination make sure that it is open and writable Destination device is not open or writable It's kind of funny How your mind wanders especially when you're trying to type Because I made the saltwater battery. It's the weirdest thing ever, right? You just take like an ice cube tray and you put like a nail and a copper wire through each little slot in the tray and It actually was kicking out like I think it was like almost six volts. I was lightning LEDs off of it It was just plain old tap water. I was like whoa So yeah, if you're interested in that just go either Google or YouTube saltwater battery There's tons of them out there If you try to make a saltwater capacitor Be careful. There's will actually hold enough volts to kill you. So be very careful with that If you do it, I did not tell you about it So now we're gonna check the transfer. So if we're not transferring then we want to and let's just Little copy and paste magic here not transferring Aborting so we want to just you know a sanity check there to make sure that we're actually transferring something and then If I'm Transferred It's greater than equal to the rate Whoops Wonder how many times I say whoops in a video I think my girlfriend just got home. I just heard a door Where I'm being robbed one of the two Usually she can tell when I'm like making a tutorial or something So she'd probably leave me alone, but you never know she may come in and start chitchat and talking my head off All right, so now we've got scheduled transfer start stop transfer and read and ready read and bytes written So let's actually just We'll do a little copy and paste magic here boom and then we're going to From the byte written slot and from the ready read slot. We're going to schedule the transfer Now let's jump up to start here And we're going to go queue to bug Uh, let's see here queue to bug. So if we're already transferring we just want to Say hey, we're already transferring Whoops already transferring and then we're just going to exit out of here If you're wondering why I'm doing all this defensive programming. It's pretty much just because I don't know where this class is going to be consumed Whoops So I want to make sure that it's pretty much kind of like bulletproof even though I'm sure it's riddled with bugs most code is So if not check devices return so Remember check devices where we check to make sure they're open and they're readable and writeable and So we're going to say we are transferring. We're going to set that flag to true I'm transferred. We're going to set to zero My girlfriend just shut the door on me. So either she's mad at me or she's going to make some noise So you may hear like the microwave or something in the background So we're going to emit the started signal And then we're going to say So if the source is not sequential and the source Has bytes what is it bytes available? Is greater than zero meaning Make sure that's actually going to return an int yep in 64. Okay So if the source is not sequential in other words It's like a q file and it has bytes available for us to read then we need to manually kick this thing off the reason why Is q file is a random access qio device? So it's not going to emit a ready read signal So we need to do that manually Now if you've noticed pretty much everything like start and ready read and bytes written is calling the schedule transfer So that's really going to be the magic here is the schedule transfer function um The reason why we're doing this is we don't want to interrupt a current transfer And we don't want to just transfer it, you know the lightning speed So we want to make sure that we know what we're doing And that we can stop at any time So we need to fill in stop. So we're going to stop the timer And we're saying transferring equal faults That way we're going to kill the timer and then if we still think we're transferring we're setting that flag to fault So we're going to just stop any transfers So the only things we really have left is the schedule transfer and the actual transfer So let's take a look at schedule transfer here Which of course as I look at my notes is just this little monster that I don't want to deal with but I have vowed not to copy and paste as much as I can so here we go I think I asked once if you guys like me typing or if you like me copy and pasting and I think it was a resounding We like you typing and I think Half the people said they like seeing the mistakes I make when I try to type and talk And the other half said they like understanding the flow of my thought process and how I'm getting from point A to point B Which I understand that so All right, if I'm scheduled In other words, we're saying if this has already been scheduled then Q warning notice this is a Q warning not a Q debug All right, so if this has already been scheduled, we're going to exit out of here the reason we're doing this is because Ready read and bytes written if these get emitted and we consume these in our slots it's going to call schedule transfers and now we have essentially asynchronous Communications going on here. So this can get called two or three times even though we are already waiting on that timer So if it's already scheduled, we want to say I know I know it's like a teenager. I know mom. I know So if we're not transferring magic and copy and paste here Then we're going to break out of there and say, okay, stop that stuff Want to make sure there's bytes available on the source? And then we're going to say okay Oops, no I had that backwards My bad If there's no bytes available on the source. I was looking at something that threw me off In case you're wondering what threw me off my notes. I've got a like 20 or 30 lines of Qtabug statements and it was because I got hung up on something and I couldn't figure it out for the longest time And I don't want to throw all those Qtabug statements into our little Little video here because it'll take like an hour to type all this junk out And I could copy and paste it, but I'm just going to end up deleting it anyway. So So we're going to predict the future here int prediction equal m transferred Plus m size now what this is Is we're going to try and predict What the size is going to be after we send so we're taking what we've already transferred Plus the size of the buffer that we're going to send and we're going to say if Prediction less than or equal to The rate the rate at which we want to transfer Then we're going to actually send Maybe I see what I did wrong here All right, so if our prediction is less than or equal to the transfer rate, which is actually our limit Then we're going to go ahead and say all right, send this. All right, so we're going to transfer that bad boy otherwise Whoops Now we've got a little bit of work here to do Let's bring that up so we can see what we're doing. Let me save this file We got a little bit of work So if our prediction Is greater than the rate we have to well delay we have to say all right. We don't want to send it now We want to sit in the future. So how long do we want to wait? So we need to say int current Equal q time Current time and we want the millisecond of the current time So we want to see the current time In millisecond I should say And it's going to give us a number between zero and one thousand. So we want to say int delay 1000 minus current. So what we're doing here is we're creating a delay. So let's say It says 400 milliseconds is the current Well, then our delay is we take the limit, which is 1000 milliseconds minus the what did we say 400? So that's going to give us a delay of 600 milliseconds so that we make our one millisecond mark and then we're going to just I'm going to just copy and paste that. I'm not going to type all that out. I'm being finicky tonight. I'm crotchety boom Now, you know why I wanted to copy and paste that all out. It's just a very large q debug statement That says q debug this rate limit and then our rate exceeded in prediction m transferred how many we've transferred to the prediction delaying for our delay in milliseconds so You can thank me later. I just saved you about five minutes of watching me type all that out because it wouldn't have been pretty I can guarantee that so m transferred So we want to say that we've currently transferred zero bytes m scheduled whoops Equal true. So now we're saying hey, we've scheduled this That way if anybody else tries to schedule something we're going to say hey back off this thing's already scheduled See If scheduled then blah if not transferring etc etc Make sure that's right. Not transferring. Okay. Yeah Then last but surely not least we're going to say m timer And what usually when we work with timers we use signals and slots, but this case we're going to do a single shot And we're going to say the delay And we're going to say we want this and we're going to connect it to the transfer slot So what's going to happen here is let's just kind of back out for a second When we schedule the transfer It's going to do these checks Then it's going to and we should actually probably do another one here, but I'll do it later. Um, I'll explain it later. I should say Then we're going to try and predict. Are we going to exceed the rate if we are because that's the limit We don't want to exceed that even with our buffer size Um, I'm sorry if we're not then we're going to go ahead and transfer it But if we are going to exceed that then we want to Find out how long we want to delay You know update our Qtabug that way we know something's going on Set the current number of bytes that we've transferred to zero Say we've scheduled the transfer and then we're going to do a single shot over to the transfer slot There it is Which I believe is the last Little chunk of code I got to fill in here. Yeah So I'm going to give us a good build before we really dive into transfer here. Just uh, uh, yeah voice voice Sometimes that's where copy and pasting will bite you in the butt Actually, no, I typed that. Uh-huh great All right, let's rebuild this thing values not to clear in the scope. What? I'll do Somebody was probably going why are you doing that? Whoopsy Yeah, we gotta return true for check device or that would be very bad And gosh, I did it again. Didn't I? Great transfer set size. Hmm Don't know why I blanked out on that one, but we will figure that out Like I said running just takes it out of me. I'm just completely brain dead after I run I don't know why I don't run very far very fast. It's just you know, whatever All right, so we've got an unused parameter really not a big deal. Um, but We can actually just do uh, what is it q unused we're going to call the q unused macro Bites that way we get that out of there Build it again. Okay, so now we got no warnings in there Uh q unused is just like a no op or a no operation meaning we're not actually doing anything We're just consuming that variable into a macro that literally does nothing called q unused In case you're wondering what that does All right, so Are you ready drumroll the bread and butter of this class here? We are no longer scheduled All right, so we're transferring at a maximum of Whatever per second So we're going to check the devices So if the devices aren't ready, we're going to just return Whoops, we're going to check if we can transfer if we cannot then we're going to just return and those will emit the error Uh signal so that we can consume that And then we're just going to say Oh, let's see here Wow, I really screwed that one up somehow Q byte array we're going to make a buffer here And we want to read a maximum of whatever we specified the size Whoops And right away. I kind of noticed something that'll definitely trip us up in the future here. We've got size here. We should say 1024 is the default for the size Because if you just say zero I'm just going to read zero bytes if you don't set the size, right? So where was I? You know what? We're going to do things the fast way. Boom. There we go. All right, so here's where I was And then we're going to write to the destination And let's actually just do a q debug Really don't need these but just you know, so we have a lot of debug statements whipping around We can see what's going on how many bytes we're going to shoot out there. All right good And then we're going to say I'm transferred plus equal Buffer dot length And now we want to know if we're finished. So we're going to say if maximum It's greater than zero and I'm transferred What the heck there? geez So that way if we've got a maximum mind like we know the file size like let's say we're transferring a file by ftp And we know the transfer file size via the protocol. We can set the maximum So once we hit that maximum number, we can close the socket Trying to make this very agnostic. So it doesn't really care what the devices are It just transfers at a specific speed and tries to predict what you're doing maximum limit reached all right, so That's if we have a maximum, which isn't really necessary and we're going to say if Not m source dot sequential Whoops damn you mouse cursor or something's screwy is going on here Man i'm having just all sorts of trouble got a goofy mouse goofy keyboard and my computer smells like burnt cat here m source So what we're saying here is if the source is sequential like it's a socket And there's no bytes available. There's just nothing on that socket None We're gonna say q debug this So if it's like a q file and there's no more bytes, then we're just done and we're gonna stop And I think we're almost done with this class actually What did I do there? All right, so Wow, what do I do? What do I keep doing there? Oh, I see what I'm doing. I keep hitting my little finger on the arrow key My bad Like I said long day So if we're if we're still transferring we're just going to return Because we're just done with this And then we're going to say Copy this So if we're uh If we're not transferring We're gonna you know drop out of here. Otherwise, we're gonna say same thing Is it sequential and are there bytes available? then Then We want to schedule the transfer because remember when it is a Random access like a q file. It's not going to emit that ready read. So we got to take care of this ourselves All right, so Let's give this a good build Wow, no errors that kind of scares me a little bit I'm used to like 8 million trillion trillion errors. Let's actually give it a rebuild just because I'm always paranoid So this is the file that we're going to be whoops it done Yeah, a couple unused but no errors. Well, so this is the file. We're going to transfer here So we're going to copy this bad boy And we're going to actually Where do I want to do this? Let's actually do it in here in this dialogue We're going to include the rate transfer, right? Actually, I don't want to do that. I want to do this All right, so we're just going to make a test class here and then in here. We're just going to say do test good good we're going to Include the rate transfer And we're going to include the q file So what we're going to do is back up because I screwed that up. Haha. Anyways, sorry Let's make these private q file and source q file Destination rate transfer transfer Alrighty, so We've got our variables here. We've got a source a destination and a transfer. So let's just copy these Set file name and we're just going to We're going to transfer from a to b We're going to set the source and destination. We're going to say m transfer Set rate So how big is this file because I want to actually slow this down here This bad boy is 13k. So I was originally going to put it at 15k, but we transferred all in one shot. So Let's actually do 2k a second is a maximum Set size We're going to set the size to why not 500 bytes Actually, let's do 250 Just because I want to And our rate transfer has some signal slots here that we're going to probably want to consume here So let's do this. Let's copy those Uh, uh, I'm getting it I've only made like what? 136 of these videos and I'm just now figuring this out All right, so we've got to connect these up now All right, so start Started started and we're just going to really speed this process here up close that so we can see what's going on here Basically, um, this is a very loose form of unit testing what we're doing here. I didn't want to muck up our Our dialogue. So I think we actually forgot the admit signal for this, but we will find out Notice how we're closing the source in the destination file some operating systems If you're writing to the file, it won't actually flush the bytes down Until you close it So notice that All right, we want to capture any errors here. So We need to If we're going to do it, let's do it the correct way Could not open the source I almost wrote the word destiny. I'm still mad about that game. I got the a game called destiny for I think it was christmas and I've never been able to play it because it just won't patch it won't load It's on xbox Everybody else's is working fine mine not so much. So Start All right, so let's look at this real quick. Let's make sure start actually starts before I do this Check file okay sequential schedule transfer. Okay good So we're going to call up our test class and then we're going to call do test Which is going to do all this wonderful stuff. It's going to open the source open the destinations going to configure the transfer And with any luck, we're going to transfer from a to b And if I open this bad boy up, it's just a copy of well this program Let's say, why did I do that? I did not want to do that I said I didn't want to do it and then I did it anyways. Well blah There we go so we're just going to do the test here and just for giggles we're going to save and Let's run and see what happens and no matching function call rate advanced process What? Oh Oh, yes. Yes. Yes. Yes. Okay. Now you can see that it is sitting there reading and writing away and then once it's gone Was very out of that full because we're going kind of slow, but you can see the read writes here created setting the defaults opening the file sending sending sending sending and You can see how rate limit exceeded in prediction 2000 was our max to 2250 is what it would have been so we're going to delay for 467 milliseconds Yep, another one blah blah blah. We're going to delay for 99 999 milliseconds. So almost an entire second of delay Same there Same there We're going to delay for a whole second there Almost there so That in a nutshell is it and we yep, we have b and it opens up beautifully. So we've sent all the data Another long tutorial. I hope you're not like grumpy cat here and you actually enjoyed this The source code for this and other tutorials will be out on my website void realms.com under tutorials language is cute and Way way way back at the very end is where it'll be And the next tutorial we're actually going to take this rate transfer class that we've made and wire it into our Http server so that we can send files in a throttled manner