{"id":251,"date":"2017-06-11T13:35:59","date_gmt":"2017-06-11T13:35:59","guid":{"rendered":"http:\/\/blog.qubekwest.com\/?p=251"},"modified":"2017-06-11T13:35:59","modified_gmt":"2017-06-11T13:35:59","slug":"ignoring-network-events","status":"publish","type":"post","link":"https:\/\/blog.qubekwest.com\/?p=251","title":{"rendered":"Ignoring Network Events"},"content":{"rendered":"<p>So as usual around here lately, I&#8217;ve been working a lot on the network code. \u00a0I suspect if you read this blog with any amount of consistency, or if you are reading all of the posts all at once as a form of weird entertainment, you are probably getting a bit tired of hearing about it. \u00a0I am too, so I get it. \u00a0The problem is that networking is hard and complex and easy to screw up. \u00a0The other problem is that it&#8217;s such an important core piece of QubeKwest, that I have to get it right to have any hope of building a game on top of it.<\/p>\n<p>Today&#8217;s networking story is about network events. \u00a0These magical things fly around inside the various parts of the networking engine and change flags on selection keys and allow it to behave accordingly as it does its thing. \u00a0The start of the problem was that I noticed that every single time I connected to the server from the client, the client took almost exactly 3 seconds to do so. \u00a0To be fair, I could ignore this problem and say &#8220;well it&#8217;s slow, but it works,&#8221; at least for a little while. \u00a0That didn&#8217;t feel right to me, so I started to dig in and study the code to try to figure out both why it was happening, and why it was so consistent.<\/p>\n<p>Thanks to 3 seconds being the selector&#8217;s select() method timeout, and a time that I chose when I realized that the network engine was never shutting down properly, I had a place to start in my search. \u00a0Unlike so many other issues with the networking code, this one jumped out immediately.<\/p>\n<p>The process of connecting to the server from the client is a two step process. \u00a0The first step is to set up some stuff and schedule the second part to occur once the selector gets to it. \u00a0The second part is for the selector to realize it has a connection to complete, and to, well, complete it. \u00a0On the surface, this all seems pretty straight forward, but these things are taking place in two different threads. \u00a0The client network engine is up and spinning in its own thread, and the UI has its own thread too, and that will be where the connection process is started.<\/p>\n<p>If we look at the client network engine thread first, we see that it does something a bit like this: \u00a0process any events that came in, select() on our selector for things that are ready, and then process the stuff that&#8217;s ready. \u00a0Then it loops back to the start of that and does it all over again. \u00a0The problem is that select() is a blocking call. \u00a0That means that in a network that isn&#8217;t busy doing anything (like before it has connected) there is nothing to cause the select() to ever finish waiting for something to do. \u00a0This is the exact spot that I added the 3 second timeout, so it would have the chance to check if the loop is supposed to end because the engine is being shut down.<\/p>\n<p>Do you see the problem? \u00a0My selector is sitting there waiting for something to have its flags changed by an event. \u00a0The step where events change things happens somewhere else in the loop that isn&#8217;t happening because select() is blocking the loop from running. \u00a0This causes network events to be effectively ignored for 3 seconds. \u00a0That means the pattern is really more like this: when select() times out in 3 seconds, it immediately loops back around, processes the events, tries to select() again, and that ends immediately since there is a flag set from the event. \u00a0Just like that, the second part of the connection process immediately processes, but after the 3 second timeout.<\/p>\n<p>Now comes the hard part. \u00a0Determining what was happening was easy, coming up with a way to fix it will be quite tricky and I believe to have any shot at it working, it will need to be yet another thread. \u00a0This new one has only one job to do. \u00a0Watch for events and process them immediately in a thread that isn&#8217;t being blocked by the select() method. \u00a0I don&#8217;t think the code involved in the new part will be terribly difficult to write, but it will require a bit of messing with the client and server engine codebases to integrate the proper use of it.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>So as usual around here lately, I&#8217;ve been working a lot on the network code. \u00a0I suspect if you read this blog with any amount of consistency, or if you are reading all of the posts all at once as a form of weird entertainment, you are probably getting a bit tired of hearing about &hellip; <a href=\"https:\/\/blog.qubekwest.com\/?p=251\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Ignoring Network Events<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[],"class_list":["post-251","post","type-post","status-publish","format-standard","hentry","category-dev"],"_links":{"self":[{"href":"https:\/\/blog.qubekwest.com\/index.php?rest_route=\/wp\/v2\/posts\/251","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.qubekwest.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.qubekwest.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.qubekwest.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.qubekwest.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=251"}],"version-history":[{"count":2,"href":"https:\/\/blog.qubekwest.com\/index.php?rest_route=\/wp\/v2\/posts\/251\/revisions"}],"predecessor-version":[{"id":253,"href":"https:\/\/blog.qubekwest.com\/index.php?rest_route=\/wp\/v2\/posts\/251\/revisions\/253"}],"wp:attachment":[{"href":"https:\/\/blog.qubekwest.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=251"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.qubekwest.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=251"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.qubekwest.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=251"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}