{"id":19252751,"url":"https://github.com/tomaszrewak/socketdispatcher","last_synced_at":"2026-05-17T03:03:47.386Z","repository":{"id":125409520,"uuid":"243857843","full_name":"TomaszRewak/SocketDispatcher","owner":"TomaszRewak","description":"Synchronous socket API for the System.Windows.Threading.Dispatcher","archived":false,"fork":false,"pushed_at":"2020-11-12T20:42:08.000Z","size":51,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-01-05T07:13:24.362Z","etag":null,"topics":["dispatcher","library","network","socket","wpf"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/TomaszRewak.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-02-28T21:30:15.000Z","updated_at":"2020-11-12T20:42:10.000Z","dependencies_parsed_at":null,"dependency_job_id":"cc5b65f8-0f3e-46e6-b7e9-38c7c9fac89c","html_url":"https://github.com/TomaszRewak/SocketDispatcher","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TomaszRewak%2FSocketDispatcher","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TomaszRewak%2FSocketDispatcher/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TomaszRewak%2FSocketDispatcher/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TomaszRewak%2FSocketDispatcher/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TomaszRewak","download_url":"https://codeload.github.com/TomaszRewak/SocketDispatcher/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240347947,"owners_count":19787236,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dispatcher","library","network","socket","wpf"],"created_at":"2024-11-09T18:28:17.879Z","updated_at":"2026-05-17T03:03:47.301Z","avatar_url":"https://github.com/TomaszRewak.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SocketDispatcher\n\nSocket Dispatcher marries network sockets with the `System.Windows.Threading.Dispatcher`.\n\nIt enables you to consume network traffic synchronously on a thread that hosts a standard windows dispatcher. It’s worth noting that it doesn’t necessarily has to be the main GUI thread, as the `System.Windows.Threading.Dispatcher` can be spawned manually on any background thread if needed. But if you decide to use this library on the main thread of your desktop application, please make sure you know perfectly well what the maximal network load it has to handle might be - as it will have a direct impact on the responsiveness of your user interface.\n\n### Why?\n\nWhy would you want to go with this solution instead of just handling the networking completely asynchronously? Well, sometimes it's just simpler to think about problems in a single-threaded domain. Funny enough, it can also bring some big performance improvements. Depending on the type of the data you are receiving, you might want to deserialize a newly received stream directly into preexisting objects by overriding their current state. In a multi-threaded application you might need to ensure thread safety by either locking, creating new immutable objects to hold the new state or by pooling pre-allocated structures. The first approach raises the thread contention rate, the second one puts a pressure on the GC and the third one significantly increases the code complexity. Of course putting network handling and processing on a dispatcher is not a Holy Grail, but it might bring quite few benefits in some very specialized applications.\n\n### How to use it?\n\nAll you have to do is to derive a your own class from the base `SocketConnection` class. \n\nWhat’s important, you have to create objects of this derived class directly on the thread your network dispatcher is running on.\n\nIn the derived class you will have an option to override following methods:\n\n```csharp\nprotected internal virtual void OnConnected();\nprotected internal virtual void OnDisconnected();\nprotected internal virtual void OnConnectionFailed();\nprotected virtual void OnAccepted(Socket socket);\nprotected virtual int Read(ReadOnlySpan\u003cbyte\u003e data);\n```\n\nThe first three simply inform you about socket state changes.\n\nThe `OnAccepted` method allows you to accept new connections in case your application is acting as a server.\n\nThe most interesting one is of course the `Read` method. It's invoked whenever new data has been received. As you might have noticed, it has to return an integer. Integer that indicated how many bytes have been actually consumed by the client. It might be that an incomplete message has been received (and there is no way to know about it on the pure TCP level) and in that case the method should return only the number of bytes it was actually able to process. The remaining ones will be part of the buffer next time this method is called.\n\nApart from that, other methods that are available through the `SocketConnection` class are:\n\n```csharp\nprotected void Connect(string host, int port);\nprotected void Disconnect();\nprotected void Listen(int port, int maxPendingConnections = 100);\nprotected void Close();\nprotected Span\u003cbyte\u003e Write(int bytes);\nprotected void Flush();\n```\n\n`Connect` and `Disconnect` should be quite straightforward. They allow you to connect to the remote server and end the connection afterward.\n\n`Listen` and `Close` are equivalent of the `Connect` and `Disconnect` methods, but should be used in case you are creating a server that accepts incoming connections. When using them, don't forget to override the `OnAccepted` method (which by default simply rejects all clients).\n\nThe `Write` method is probably the one you will be using most frequently. It allows you to write to the send buffer. It has a single parameter that specifies how many bytes the client wants to send. When called, it allocates (or most likely reuses) buffer space of requested size and returns it as a mutable `Span`. Thanks to that, if your serialization algorithm is well optimized, unnecessary allocations and copying can be easily avoided. Once writing is complete simply call the `Flush` method to notify the socket about pending data being available (tip: you can also stack multiple messages together before calling the `Flush` method).\n\n### How does it work?\n\nThe Socket Dispatcher does not \"select sockets\". It means that it doesn't spawn any timer on the dispatcher to continuously check if new data has arrived or is ready to be sent. Instead, it hooks directly into the native wsock32 API which provides an option to publish network events on a STA thread, which the dispatcher (by using the `ComponentDispatcher.ThreadFilterMessage` handler) can then intercept and consume.\n\n### One more time: why?\n\nI've created this library mostly for my private use and to experiment a bit with the lower level networking. Nevertheless, if there is a functionality that you see missing here or if you've discovered a bug worth fixing, feel free to drop a PR or create a github ticket.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftomaszrewak%2Fsocketdispatcher","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftomaszrewak%2Fsocketdispatcher","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftomaszrewak%2Fsocketdispatcher/lists"}