TCP socket sharding in .NET - c#

I'm trying to write a high-performance HTTP server in C# without using third-party libraries, and during my readings, I found this post on nginx blog. What mentioned there is using SO_REUESEPORT but that option is not available in .NET sockets and also Windows, so I searched for an alternative to this option and I've read that SO_REUSEADDR which is available in both Windows and .NET is the option that I have looking for.
I have tried to implement that by creating 4 sockets and enabling reuse-address before binding the sockets and start listening, but what happens after is only one of the sockets accepts connections even though its thread goes busy.
static readonly byte[] Response = Encoding.ASCII.GetBytes("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r");
static int s_ListenerIndex = 0;
static void Main(string[] args)
{
var listenAddress = new IPEndPoint(IPAddress.Any, 26000);
var sockets = new Socket[4];
Console.WriteLine("Creating sockets");
for (int i = 0; i < sockets.Length; i++)
{
sockets[i] = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sockets[i].SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
sockets[i].Bind(listenAddress);
}
Console.WriteLine("Starting listener threads");
for (int i = 0; i < sockets.Length; i++)
{
var socket = sockets[i];
CreateThread(() => ListenSocket(socket));
}
Thread.Sleep(Timeout.Infinite);
}
static void ListenSocket(Socket socket)
{
var listenerId = Interlocked.Increment(ref s_ListenerIndex);
socket.Listen(100);
Console.WriteLine($"Socket #{listenerId} is listening");
while (true)
{
Socket client = socket.Accept();
Console.WriteLine($"Socket #{listenerId} accepted connection");
client.Send(Response);
client.Close();
}
}
static void CreateThread(ThreadStart threadStart)
{
var thread = new Thread(threadStart);
thread.IsBackground = true;
thread.Start();
}
Am I doing something wrong or the whole trick is not possible in Windows and .NET?

On Windows, the SO_REUSEADDR option has no use cases for an HTTP server. It's only real use case is for multicast sockets where data is delivered to all of the sockets bound on the same port.
I suggest this SO post for a indepth discussion. How do SO_REUSEADDR and SO_REUSEPORT differ?
Under Windows with IOCP you don't need the Linux/Unix equivalent which can provide load balancing across multiple threads. IOCP takes care of this for you. The implementation is very different but achieves the same highly scalable result.

Related

Too many open files while data transfer over Wifi

I have 2 applications: Xamarin.Android client app that send value from SeekBar over Wifi and WinForms server that receive this value in real time. Everything works good but every time after ~40sec of data transferring android app throws System.Net.Sockets.SocketException with message "Too many open files".
My server code thats receive data:
public void StartReceiving()
{
IPAddress localAdd = IPAddress.Parse(SERVER_IP);
TcpListener listener = new TcpListener(localAdd, PORT_NO);
listener.Start();
while (true)
{
Socket client = listener.AcceptSocket();
client.NoDelay = true;
var childSocketThread = new Thread( () =>
{
byte[] datareceived = new byte[1];
int size = client.Receive(datareceived);
for (int i = 0; i < size; i++)
{
Console.WriteLine(datareceived[0].ToString());
}
Console.WriteLine();
//client.Close();
});
childSocketThread.Start();
}
}
Client code which sends value from SeekBar:
private void Seek1_ProgressChanged(object sender, SeekBar.ProgressChangedEventArgs e)
{
TcpClient client = new TcpClient(SERVER_IP, PORT_NO);
NetworkStream nwStream = client.GetStream();
byte[] bytesToSend = new byte[1];
bytesToSend[0] = Convert.ToByte(e.Progress);
nwStream.Write(bytesToSend, 0, bytesToSend.Length);
}
So my question is, what causes this problem and how can I solve it?
Your problem is the following: you open a socket for each call of the ProgressChanged event handler. There is a limited number of sockets that you can open on a machine and if you open them fast enough, you will end up in a System.Net.Sockets.SocketException.
A solution to this problem would be to make sure that you close the TCP connection gracefully. In that way you will release the sockets for further usage.
My opinion is that TCP is a bit overkill for this kind of communication. You can use HTTP to transfer the data. Your desktop app will be the server and the Xamarin app will be the client. In that way you will be freed by things like synchronization, connections states, etc.

Measuring mb sent per second with C# sockets? (Multithread)

I am trying to create a multi-threading application that'll try and send a lot of data to a specific IP and port using sockets in C#. I have completed this, but I need help in getting more information from it.
I would like to know how I could get how much data is being sent a second? In MB if possible, from all threads and all requests?
I am mearly doing this for educational purposes to see how much data can actually be sent and how it all works when doing it with multi -threading
Here is my code:
static void Main(string[] args)
{
int amountOfThreads = 10;
while (amountOfThreads > 0)
{
Thread thread = new Thread(SendData);
thread.Start();
}
}
private static void SendData()
{
byte[] dataToSend = Encoding.Default.GetBytes("some string that'll be sent many times.");
string ipAddress = "127.0.0.1";
int port = 3924;
IPEndPoint ep = new IPEndPoint(IPAddress.Parse(ipAddress), port);
Socket socketToSendTo = new Socket(System.Net.Sockets.AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
socketToSendTo.SendTo(dataToSend, ep);
}

C# Server - Socket not connecting and out of memory exception

I am trying to implement a simple TCP server and I basically copied the example on MSDN sans a couple of lines and tried to make it work. I have an external client trying to connect already.
This is my code:
IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
IPEndPoint localEP = new IPEndPoint(ipHostInfo.AddressList[0], 4001);
Socket listener = new Socket(localEP.Address.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
try
{
listener.Bind(localEP);
listener.Listen(1000);
while (true)
{
listener.BeginAccept(new AsyncCallback(AcceptCnxCallback), listener);
}
}
catch (Exception e)
{
//Log here
}
This is my callback:
private void AcceptCnxCallback(IAsyncResult iar)
{
MensajeRecibido msj = new MensajeRecibido();
Socket server = (Socket)iar.AsyncState;
msj.workSocket = server.EndAccept(iar);
}
And this is the information of one of the incoming packages:
TCP:[SynReTransmit #1727889]Flags=......S., SrcPort=57411, DstPort=4001, PayloadLen=0, Seq=673438964, Ack=0, Win=5840 ( Negotiating scale factor 0x4 ) = 5840
Source: 10.0.19.65 Destination: 10.0.19.59
I basically have two issues:
If I use the while loop I get an OutOfMemoryException
I never do manage to connect to the client
Any tips on either of the two problems? Thank you in advance!
Your problem is, that you use asynchronous calls all the time. There is no wait mechanism or similar, so generally you are just creating new asynchronous callbacks in an infinite loop.
For a basic TCP I would recommend to use the simple approach and use the synchronous methods.
Accept() is blocking, so the program flow will stop until there is an ingoing connection.
while (true)
{
Socket s = listener.Accept();
buffer = new byte[BUFFER_SIZE];
s.Receive(buffer);
//Do something
s.Send(...);
}
Noe that this is just a basic example. If you want to keep your connection you might consider a new Thread for each accepted Socket, that continoues with receiving and sending data.
First problem
You are using an infinite loop to call an async method.
try it like this:
listener.BeginAccept(new AsyncCallback(AcceptCnxCallback), listener);
//add your code here (this part will be executed wile the listner is waiting for a connection.
while (true)
{
Thread.Sleep(100);
}
and change the Callbackmethod to:
private void AcceptCnxCallback(IAsyncResult iar)
{
MensajeRecibido msj = new MensajeRecibido();
Socket server = (Socket)iar.AsyncState;
msj.workSocket = server.EndAccept(iar);
//call again the listener after you get a message
listener.BeginAccept(new AsyncCallback(AcceptCnxCallback), listener);
}

Check if IP Address and Port are responding

I'm currently developing a autodiscover feature for SNMP printer monitor software. I need a helper method, which is executed from several threads each checking an ip in a range, to determine if a device at a certain ip address, is responding to port 9100, to establish that it in fact is a printer, before sending an SNMP request to it.
I've ended up with the following method, however im unaware if this is the correct approach, and if it by convention is correct use of the Close() method in this context (I can see that Dispose(), Disconnect() and Shutdown() methods are also available, so which to use?). Furthermore i need to set a timeout value of max. 5 seconds, so the threads won't linger for too long, before presenting a result. My code so far:
private bool GetTCPPrinterResponse(IPAddress _ip)
{
int port = 9100;
bool isResponsive = false;
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
s.Connect(_ip, port);
isResponsive = true;
}
catch (SocketException)
{
isResponsive = false;
}
finally
{
s.Close();
}
return isResponsive;
}
After method edit:
private bool GetTCPPrinterResponse(IPAddress _ip)
{
int port = 9100;
bool isResponsive = false;
using (Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
s.ReceiveTimeout = 3000;
s.SendTimeout = 3000;
try
{
s.Connect(_ip, port);
isResponsive = true;
}
catch (SocketException)
{
isResponsive = false;
}
}
return isResponsive;
}
Setting of Timeout properties, has no effect.
That is the correct way to check if a computer/printer is online at a certain IP on a certain Port.
You should call the dispose method to release the memory being used by the object.
Socket class implements IDisposable, so it would be best if you use using and not worry about calling dispose because using does it for you.
using(Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
//...
}
Socket class has properties ReceiveTimeout and SendTimeout.
There is no need to use multi-threading for this. You're tying up threads that will end up waiting for the I/O operation to complete anyway. Instead, why not use asynchronous I/O?
public async Task<Tuple<IPAddress, bool>> GetResponse(IPAddress address)
{
using (var client = new TcpClient(AddressFamily.InterNetwork))
{
var connectTask = client.ConnectAsync(address, 80);
await Task.WhenAny(connectTask, Task.Delay(5000));
if (connectTask.IsCompleted)
return Tuple.Create(address, true);
else
return Tuple.Create(address, false);
}
}
This can further be improved - the timeout mechanism is somewhat wasteful (Task.Delay uses a timer, not really necessary), but it's easy to write, understand and use, and it doesn't unnecessarily waste threads.
The call would then be something like this:
Task<Tuple<IPAddress, bool>>[] tasks =
new []
{
GetResponse(Dns.GetHostAddresses("www.google.com").First()),
GetResponse(Dns.GetHostAddresses("www.microsoft.com").First()),
GetResponse(Dns.GetHostAddresses("www.yahoo.com").First()),
GetResponse(Dns.GetHostAddresses("www.altavista.com").First()),
};
Task.WhenAll(tasks).Wait();
foreach (var t in tasks)
t.Result.Dump(); // t.Result has the IP address and status
This will wait for all of the devices to respond (or timeout). Of course, there's nothing preventing you from doing this in a more interactive fashion - you could just as easily update the UI with the data as it comes back.

getting 10060 (Connection Timed Out) when stress testing simple tcp server

I have created simple tcp server - it works pretty well.
the problems starts when we switch to the stress tests -since our server should handle many concurrent open sockets - we have created a stress test to check this.
unfortunately, looks like the server is choking and can not respond to new connection request in timely fashion when the number of the concurrent open sockets are around 100.
we already tried few types of server - and all produce the same behavior.
the server: can be something like the samples in this post(all produce the same behavior)
How to write a scalable Tcp/Ip based server
here is the code that we are using - when a client connects - the server will just hang in order to keep the socket alive.
enter code here
public class Server
{
private static readonly TcpListener listener = new TcpListener(IPAddress.Any, 2060);
public Server()
{
listener.Start();
Console.WriteLine("Started.");
while (true)
{
Console.WriteLine("Waiting for connection...");
var client = listener.AcceptTcpClient();
Console.WriteLine("Connected!");
// each connection has its own thread
new Thread(ServeData).Start(client);
}
}
private static void ServeData(object clientSocket)
{
Console.WriteLine("Started thread " + Thread.CurrentThread.ManagedThreadId);
var rnd = new Random();
try
{
var client = (TcpClient)clientSocket;
var stream = client.GetStream();
byte[] arr = new byte[1024];
stream.Read(arr, 0, 1024);
Thread.Sleep(int.MaxValue);
}
catch (SocketException e)
{
Console.WriteLine("Socket exception in thread {0}: {1}", Thread.CurrentThread.ManagedThreadId, e);
}
}
}
the stress test client: is a simple tcp client, that loop and open sokets, one after the other
class Program
{
static List<Socket> sockets;
static private void go(){
Socket newsock = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
IPEndPoint iep = new IPEndPoint(IPAddress.Parse("11.11.11.11"), 2060);
try
{
newsock.Connect(iep);
}
catch (SocketException ex)
{
Console.WriteLine(ex.Message );
}
lock (sockets)
{
sockets.Add(newsock);
}
}
static void Main(string[] args)
{
sockets = new List<Socket>();
//int start = 1;// Int32.Parse(Console.ReadLine());
for (int i = 1; i < 1000; i++)
{
go();
Thread.Sleep(200);
}
Console.WriteLine("press a key");
Console.ReadKey();
}
}
}
is there an easy way to explain this behavior? maybe c++ implementation if the TCP server will produce better results? maybe it is actually a client side problem?
Any comment will be welcomed !
ofer
Specify a huge listener backlog: http://msdn.microsoft.com/en-us/library/5kh8wf6s.aspx
Firstly a thread per connection design is unlikely to be especially scalable, you would do better to base your design on an asynchronous server model which uses IO Completion Ports under the hood. This, however, is unlikely to be the problem in this case as you're not really stressing the server that much.
Secondly the listen backlog is a red herring here. The listen backlog is used to provide a queue for connections that are waiting to be accepted. In this example your client uses a synchronous connect call which means that the client will never have more than 1 connect attempt outstanding at any one time. If you were using asynchronous connection attempts in the client then you would be right to look at tuning the listen backlog, perhaps.
Thirdly, given that the client code doesn't show that it sends any data, you can simply issue the read calls and remove the sleep that follows it, the read calls will block. The sleep just confuses matters.
Are you running the client and the server on the same machine?
Is this ALL the code in both client and server?
You might try and eliminate the client from the problem space by using my free TCP test client which is available here: http://www.lenholgate.com/blog/2005/11/windows-tcpip-server-performance.html
Likewise, you could test your test client against one of my simple free servers, like this one: http://www.lenholgate.com/blog/2005/11/simple-echo-servers.html
I can't see anything obviously wrong with the code (apart from the overall design).

Categories

Resources