Part 1: Introduction

Published one month ago Updated one month ago


Here it is. The long awaited C# networking tutorial. It's finally here after much delay, and we have a lot to cover.

I decided to write this series because there seems to be a distinct lack of actual “tutorials” for working with sockets. Most information is hidden away behind cryptic man pages, obscure Win32 docs, or sample code in languages you may not even be comfortable reading.

I think it's high time this comes to an end. I aim to create the definitive guide for working with sockets with the intent that you walk away better equipped, better prepared, and with a better understanding of what is actually going on when your computer communicates with another.

So let's start with the obvious question.

Just what is a socket?

Have you ever wondered how online multiplayer games manage to seamlessly connect players from around the world in real-time? How does your message in Discord get sent to everyone else in the server? Just what is end-to-end encryption anyway? In this tutorial series, we'll demystify the technology behind these experiences and I hope to empower you to create your own networked applications.

In a nutshell, a socket is a mechanism in our developer toolbox which allows our code to send data to - and receive data from - a remote location almost instantly. More technically, it's an endpoint which systems can use to establish a connection and exchange data. This data can encompass anything from text, images, audio and video, to applications, games, and more!

Behind every multiplayer game, every web browser, every email client, and every messaging platform, sockets are hard at work transmitting data back and forth. Even if you've only used Unity libraries such as Mirror or Photon PUN, behind the scenes there exist two or more sockets communicating with each other.

Despite some common misconceptions, sockets are not actually implemented at the language level. C# has no implementation of sockets, nor does C, C++, Python, Java, or any other language. No, sockets are implemented at the operating system level. How the data actually gets sent is far beyond our reach and instead handled by Windows, Linux, macOS, Android, iOS, or whatever platform in question that you're running. These platforms all implement socket functionality right into the kernel. All we are given is a list of functions we can call to tell the operating system what it is we want it to do.

If you've ever worked with OpenGL or any graphics API, you may find the concept of sockets familiar. OpenGL, for instance, isn't implemented in any one language. Instead, its actual implementation is provided by the manufacturer's device drivers. As a developer, you're given access to a list of functions, known as an API (Application Programming Interface), that you can call to interact with OpenGL. Essentially, you have to ‘trust’ that these functions work as expected and perform the intended operations.

Sockets work in a very similar fashion. You, the developer, know about some functions you can call to connect to a server, and send and receive data. But how these functions behave is ultimately up to the operating system you're running. How Windows handles sockets is drastically different to how Linux handles them. But thankfully, the API is more or less the same on both platforms. (There are some minor differences, but nothing we will have to worry about for now.)

Because sockets are implemented at the operating system level, it means the functions that the operating system provides are, for lack of a better word, “global”. No matter what language you're using, you'll have access to functions like connect, send, bind, accept, and all the other functions needed to work with sockets. The only real difference is how they get abstracted in the language.

In C and C++, creating a socket is as simple as calling the socket function. This function gives you back what is essentially a “file descriptor” (we'll cover this later), which you then pass around to the other functions. In C# and other .NET languages, we're given the Socket class, and the functions we need to call are members of this class. Java has its own Socket class too.

Ultimately however, the functions you have access to are the same, and they will behave the same no matter what language you're using. While this series will be using C# exclusively - since the majority of my audience are here for my C# content - keep in mind that the concepts I'll be teaching are transferable, and applicable anywhere you go. If you know how to work with sockets in one language, you know how to work with them in any language. All it takes is learning the language-specific syntax and flavour of abstractions.

What this series will cover

I understand that delving into networking concepts can feel daunting at first. When I was starting out, I myself didn't have a very good understanding of what was happening, and there were not a lot of resources at my disposal to learn more. Most of my knowledge and experience with sockets comes from endless experimentation, long dives into technical documentation, and trying to replicate C examples in Visual Basic while simultaneously understanding neither language very well at all.

Rest assured, this tutorial series is designed to guide you through the intricacies of socket programming in a clear manner. I aim to give you the guide I never had myself and so each concept will be explained thoroughly, with ample examples and practical exercises to reinforce your understanding.

If you find yourself struggling with any aspect of the material, don't hesitate to ask questions or seek clarification. I'll also provide as many resources and references as I can throughout the series for further exploration. Remember, mastering socket programming is a valuable skill that opens up a world of possibilities in both software dev and game dev. With dedication and persistence, you'll soon see it's not as daunting as it may appear.

But let's get this clear: This series is focused on teaching socket programming, not C# basics or introductory programming concepts. While sockets are a fundamental aspect of network programming, this tutorial assumes that you have a solid understanding of programming fundamentals and are comfortable with C# syntax or similar programming languages. Constructs such as pattern matching, collection expressions, or the use of Span<T>, will be used throughout this guide, and I must put the responsibility on you to learn what these things are.

That said, if you're new to C# or feel unsure about certain language-specific features, don't let that deter you. While I won't be covering basic programming concepts extensively, or the weird quirks of C# in particular, I'll do my best to explain socket-related topics in a way that's accessible and easy to understand. If you encounter unfamiliar concepts or syntax along the way, take it as an opportunity to learn and expand your programming skills. A bit of Googling goes a long way, so don't be afraid to do your own research into aspects that may confuse you.

We'll cover as much as we can, and each part will end with a tangible project that you can play with. This should solidify the progress we make and show you that with a little bit of time, you can get results.

So, if you're ready to dive in and explore the world of socket programming, let's get started!

Important

I'd also like to preface this series by saying all of this is a work in progress, and sections of it may change over time as it's being released to accommodate any information I inadvertently miss.

While the guide is being released I do encourage you check back over sections you may have already read, as some advice may have been rewritten or clarified.