Sockets and Multi-threading is not really difficult concepts. It's rather logical.
Sockets
There are multiple types of sockets, but the sockets used in Conquer are under the TCP protocol.
Transmission Control Protocol - Wikipedia, the free encyclopedia
There is another common protocol called UDP.
User Datagram Protocol - Wikipedia, the free encyclopedia
The biggest difference between them is that TCP always reports back and forth with error and ensures that the amount of bytes you want to send/receive will also be the amount of bytes you've sent/received; where UDP doesn't care about that and will keep sending whatever bytes it can and receive whatever bytes it can get. TCP is usually more safe, but slower. Where UDP is faster, but sure as hell not safe. UDP is common for streaming because of this, where TCP for packets that has to be ensured specific sizes and data all the type ex. HTTP packets are always TCP.
There are two different major concepts of sockets.
Server sockets and client sockets.
Server sockets are bound to an endpoint in which they listen for connections on.
Client sockets are connected to an endpoint.
I will be describing this in D, but you should be able to get the concept in any other language as well. The concept of using sockets is basically the same in every language.
Server concept
Walkthrough- socket.bind()
- socket.listen()
- socket.accept()
- socket.receive()
- socket.send()
socket.bind()
Binds the socket to a specific endpoint (InternetAddress, IPEndPoint in C#)
Code:
socket.bind(new InternetAddress("127.0.0.1", 9988));
The example above binds the socket to "127.0.0.1:9988" which is:
IP=127.0.0.1
Port=9988
socket.listen()
Starts to listen for connections. The parameter listen() takes is the backlog.
The backlog is the numer of connections that can be queued up at once, it's uncommon to have this as 0, because that will only allow one connection at a time to be accepted and until the connection has actually been accepted all other connections will be refused. IMO it would be a good idea to start with 100 and if ever needed (Which you probably won't for a conquer server.) then raise it.
Code:
socket.listen(100);
The example above listens for sockets with a maximum queue of 100 connected sockets.
socket.accept()
Accepts connected sockets. When a socket (client) has connected to the socket (server) it can be accepted and used calling socket.accept().
It returns the newly connected socket which can now call socket.receive() to receive packets.
Code:
Socket client = socket.accept();
The example above accepts a client socket.
socket.receive()
Receives bytes from the connected socket.
Code:
ubyte[] buffer = new ubyte[1024];
int recv = socket.receive(buffer);
The example above receives a buffer of 1024 bytes. The recv variable basically tells how many bytes has been received. If the return value is 0 then the socket was disconnected and if it's negative there was an error.
socket.send()
Sends bytes to the connected socket.
Code:
ubyte[] buffer = new ubyte[1024];
socket.send(buffer);
The example above sends 1024 bytes to the connected socket.
Synchronous Server Example:
Code:
import std.socket;
class SynchronousServer {
private:
Socket m_socket;
public:
this() {
m_socket = new TcpSocket;
}
void run(string ip, ushort port) {
m_socket.bind(new InternetAddress(ip, port));
m_socket.listen(100);
while (true) {
Socket client = m_socket.accept();
ubyte[] buffer = new ubyte[1024];
int recv = client.receive(buffer);
if (recv <= 0) {
// Error or disconnect ...
client.shutdown(SocketShutdown.BOTH);
client.close();
continue;
}
// Do something with buffer ...
client.send(buffer); // Sends the buffer back ...
}
}
}
If you want to learn about asynchronous sockets then take a look here:

Implementation:
If you're interested in some real world usage of dasocks take a look at this:
The concept is the same in most language except for that they use poll() or epoll() However the implementation is a bit different in C# as it seem to call poll() but actually calls select() and C# has a great abstraction of asynchronous programming using Begin*() methods, so the implementation of asynchronous sockets in C# is a little different.
BeginAccept() for C# in replacement of Accept() for synchronous sockets.
BeginReceive() for C# in replacement of Receive() for synchronous sockets.
Client concept
IMO a client should never connect through asynchronous sockets unless you really need multiple connections which is only common for IM's and browsers. Games etc. usually only have one (or a very few) connections and it might just be safer and easier to implement a single thread for every connection.
Walkthrough- socket.connect()
- socket.send()
- socket.receive()
socket.connect()
Connects to a specific end point. The end point it connects to is the same endpoint the server was bound to.
Code:
socket.connect(new InternetAddress("127.0.0.1", 9988));
The example above connects to the endpoint "127.0.0.1:9988" which is:
IP=127.0.0.1
Port=9988
socket.send()
The concept is the exact same as the previous socket.send() example. Except for that this sends bytes to the server.
socket.receive()
The concept is the exact same as the previous socket.receive() example.
Except for that this receives bytes from the server.
Synchronous Client Example
Code:
import std.socket;
import std.stdio : writeln, readln;
class SynchronousClient {
private:
Socket m_socket;
public:
this() {
m_socket = new TcpSocket;
}
void run(string ip, ushort port) {
writeln("Press ENTER to connect...");
readln();
m_socket.connect(new InternetAddress(ip, port));
writeln("Connected...");
while (true) {
writeln("Press ENTER to send a packet.");
readln();
ubyte[] buffer = new ubyte[1024];
client.send(buffer);
writeln("Sent...");
buffer = new ubyte[1024]; // Not necessary in this example ...
int recv = client.receive(buffer);
if (recv <= 0) {
// Error or disconnect ...
client.shutdown(SocketShutdown.BOTH);
client.close();
continue;
}
// Do something with buffer ...
}
}
}
Threading
The concept of threading is really simple. You use multi-threading to perform actions simultaneously. If you only use one thread then you can only do one thing at a time, but using multiple threads you can perform multiple actions at once.
Let's say we have a road going sourh <-> north. We want a car going from the north to the south and a car from the south to the north.
We want both the cars being able to drive in their direction at the same time, thus we have a road for each way.
Each road could be seen as a thread. We got a thread for cars driving north and a thread for cars going south.
If we only had one road (one thread) then each car would have to wait for the other to pass, in which the next car is blocked from driving till the previous one has passed.
Creating a thread is pretty much the same in every language too. Most languages has a simplified wrapper around a thread. Usually the constructor of the thread is a function pointer or a delegate to the action which the thread performs.
Code:
Thread myThread = new Thread(&myAction);
The example above creates a thread which points to the function myAction.
It's common for languages to have something like start() to start the thread.
The example above starts the thread (Executes myAction in a new thread.)
Threading Example:
Code:
import core.thread;
import std.stdio : writeln, readln();
void myAction() {
auto tid = Thread.getThis;
writefln("Thread %s says hello!", tid);
}
void main() {
Thread t1 = new Thread(&myAction);
Thread t2 = new Thread(&myAction);
t1.start();
t2.start();
readln();
}
There is one thing you should always take into account when working with threads and that is safety. It's important that you lock data which multiple threads might access. It can be done using mutexes (Common in most languages.)
In C# you got the lock keyword which basically encapsulates a scope with a mutex (Called Monitor in C#)
In D you got the synchronized which does the same as C# does.
Both the C# and D encapsulations can take an object to lock rather than a global lock.
If you need help or got anymore questions feel free to ask.