C
C#7mo ago
Alex

How can I accept multiple clients?

I want to write my own http server using TCP and System.Net.Sockets. Here is my code:
using System.Net;
using System.Net.Sockets;
using System.Text;

const string ipAddress = "127.0.0.1";
const int port = 27015;

try
{

// create socket
Socket listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream,ProtocolType.Tcp);

// bind ip address

IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse(ipAddress),port);

listenSocket.Bind(ipEndPoint);

// Listen
listenSocket.Listen();

Console.WriteLine($"listening on http://{ipAddress}:{port}");

Socket acceptSocket = await listenSocket.AcceptAsync();



byte[] buffer = new byte[1024];
int bytesReceived = await acceptSocket.ReceiveAsync(buffer, SocketFlags.None);

string message = Encoding.UTF8.GetString(buffer, 0, bytesReceived);

Console.WriteLine(message);


string response = "HTTP/1.1 200 OK\r\nContent - Type: text/html\r\n\r\n{ \"msg\"=\"Hello world!\"}";


await acceptSocket.SendAsync(Encoding.UTF8.GetBytes(response, 0, response.Length));

acceptSocket.Close();

listenSocket.Close();
}
catch (Exception ex)
{
Console.WriteLine($"[{ex.GetType()}]: {ex.Message}");
}
using System.Net;
using System.Net.Sockets;
using System.Text;

const string ipAddress = "127.0.0.1";
const int port = 27015;

try
{

// create socket
Socket listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream,ProtocolType.Tcp);

// bind ip address

IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse(ipAddress),port);

listenSocket.Bind(ipEndPoint);

// Listen
listenSocket.Listen();

Console.WriteLine($"listening on http://{ipAddress}:{port}");

Socket acceptSocket = await listenSocket.AcceptAsync();



byte[] buffer = new byte[1024];
int bytesReceived = await acceptSocket.ReceiveAsync(buffer, SocketFlags.None);

string message = Encoding.UTF8.GetString(buffer, 0, bytesReceived);

Console.WriteLine(message);


string response = "HTTP/1.1 200 OK\r\nContent - Type: text/html\r\n\r\n{ \"msg\"=\"Hello world!\"}";


await acceptSocket.SendAsync(Encoding.UTF8.GetBytes(response, 0, response.Length));

acceptSocket.Close();

listenSocket.Close();
}
catch (Exception ex)
{
Console.WriteLine($"[{ex.GetType()}]: {ex.Message}");
}
How can I accept multiple sockets? Should I create new Thread for each socket (I'll add while loop later)? Also, should I store threads somewhere to finish them after I handled request? Maybe you can give any other advices on this topic
15 Replies
Omnissiah
Omnissiah7mo ago
you are already using asyc/await, so there shouldn't be the need to create threads maybe a little more error control would be nice (also, in case, there is an implementation of http web server in the framework)
cap5lut
cap5lut7mo ago
to handle multiple clients at the same time u would in a loop await a new connection and spawn but not await a new task that handles that single connection
while (true)
{
Socket client = socket.AcceptAsync();
_ = Task.Run(() => HandleClientConnectionAsync());
}
while (true)
{
Socket client = socket.AcceptAsync();
_ = Task.Run(() => HandleClientConnectionAsync());
}
on another note u have issues regarding receiving and sending, its not guaranteed that u receive/send the whole message at once. eg for sending:
byte[] payload = Encoding.UTF8.GetBytes("hello world");
int bytesSent = await socket.SendAsync(payload);
byte[] payload = Encoding.UTF8.GetBytes("hello world");
int bytesSent = await socket.SendAsync(payload);
payload has a length of 11, but it could also be that it couldnt send all bytes and thus bytesSent is less than 11
Omnissiah
Omnissiah7mo ago
i mean he's not really using the data (for now?)
cap5lut
cap5lut7mo ago
now assume the client sends hello world, it could be that with that first ReceiveAsync() call u only receive hell and the rest would require more calls to ReceiveAsync() to get the rest. well, they are reading and decoding the byte array to utf8, so even there it could throw an exception because of an invalid byte sequence, if that is teared apart because the full message wasnt received by one call to ReceiveAsync() (and a little side note: Content - Type is wrong, header names are without whitespaces, this should be Content-Type)
cap5lut
cap5lut7mo ago
especially because http is a protocol where u dont have any size prefix, its not an easy to implement protocol, due to not knowing beforehand how much u have to read. System.IO.Pipelines helps a lot to manage those teared reads/writes
I/O pipelines - .NET
Learn how to efficiently use I/O pipelines in .NET and avoid problems in your code.
cap5lut
cap5lut7mo ago
it could also simply be that the http request is longer than the buffer size u r using, another problem ⤴️ is solving
Alex
AlexOP7mo ago
Thank you I'll read it I want to implement both json and html (templates) routes, I'll do more complex error control I have a question, how do I know when client sent all the data (regual data or file)? I tried to do while loop (receivedBytes > 0), but loop never finishes (that's how it is done in c++ example).
cap5lut
cap5lut7mo ago
u have to read about how the http request is structured. if u receive 0 bytes, this means that the connection was closed by the peer the rough structure for requests is - first line: request method and resource and http version (eg. GET /index.html HTTP/1.1) - optional headers (eg Host: example.org) - empty line - optional request body all line breaks have to be CRLF ("\r\n") if there is one, to determine request body length/content u need to look at the headers, there could be a simple Content-Length header telling u how many bytes the request body has, but there is also a chunk based encoding so for example
GET /index.html HTTP/1.1
Host: example.org

GET /index.html HTTP/1.1
Host: example.org

POST /something HTTP/1.1
Host: example.org
Content-Type: application/x-www-form-urlencoded
Content-Length: 7

x=hello
POST /something HTTP/1.1
Host: example.org
Content-Type: application/x-www-form-urlencoded
Content-Length: 7

x=hello
cap5lut
cap5lut7mo ago
https://www.tutorialspoint.com/http/index.htm seems to have some good resources
HTTP Tutorial
HTTP Tutorial - The Hypertext Transfer Protocol (HTTP) is an application-level protocol for distributed, collaborative, hypermedia information systems. This is the foundation for data communication for the World Wide Web (i.e. internet) since 1990. HTTP is a generic and stateless protocol which can be used for othe
Omnissiah
Omnissiah7mo ago
the loop never finishes because the connection is still open and ther could be other data you have to parse the message and understand its structure because tcp doesn't have feature of "sending a message" (which would be a self-contained amount of data), it just transmits unstructured data
Alex
AlexOP7mo ago
okay, thank you
cap5lut
cap5lut7mo ago
i would also recommend to sticking to http 1.1 for now, http 2 is vastly more complex
Omnissiah
Omnissiah7mo ago
or even http 1.0 (maybe http 0.9 would be too much)
Alex
AlexOP7mo ago
Yes, I will, I already have a lot of things to think about besides parsing, I want to make something similar to asp.net minimal api but also add template engine
cap5lut
cap5lut7mo ago
well, the actual http message stuff is mostly the same between 1.1 and 2, but 2 comes with multiplexing multiple requests via one tcp connection and thats the most complex part (and the prerequisite of ssl/tls)
Want results from more Discord servers?
Add your server