From what I understand, those lines:
var client = await listener.AcceptTcpClientAsync();
var client = listener.AcceptTcpClient();
should work the same way, but if I try to open, for example, 5k connections (without closing them), very soon listener (async) either stops responding or throws exception.
Anyone have idea what may be wrong?
Sample class:
class ListenerTest
{
static int connectionNumber = 0;
static int port = 23456;
public void StartListening(bool async)
{
var listener = new TcpListener(IPAddress.Any, port);
listener.Start();
if (async)
{
var task = HandleConnectionsAsync(listener);
task.Wait();
}
else
HandleConnections(listener);
}
async Task HandleConnectionsAsync(TcpListener listener)
{
while (true)
{
Console.Write("Waiting for async connection...");
var client = await listener.AcceptTcpClientAsync();
Console.WriteLine("OK #" + connectionNumber);
connectionNumber++;
}
}
void HandleConnections(TcpListener listener)
{
while (true)
{
Console.Write("Waiting for sync connection...");
var client = listener.AcceptTcpClient();
Console.WriteLine("OK #" + connectionNumber);
connectionNumber++;
}
}
public static void ConnectTest(int count)
{
var ep = new IPEndPoint(IPAddress.Loopback, port);
for (var i = 0; i < count; i++)
new TcpClient().Connect(ep);
}
}
Usage:
static void Main(string[] args)
{
var isAsync = true;
ThreadPool.QueueUserWorkItem(new WaitCallback(StartListening), isAsync);
ListenerTest.ConnectTest(5000);
}
static void StartListening(object state)
{
var my = new ListenerTest();
my.StartListening((bool)state);
}
Your test connections killed by GC, if you "pin" down your connections until end of test - you'll get your 5000 connections( i've just copy/pasted and fixed/tested your code ). Rewritten connection test:
public static void ConnectTest(int count)
{
var ep = new IPEndPoint(IPAddress.Loopback, port);
List<TcpClient> clients = new List<TcpClient>();
for (var i = 0; i < count; i++)
{
TcpClient cl = new TcpClient();
clients.Add(cl);
cl.Connect(ep);
}
}
Also please note that in "real world" conditions you need to add something like this before starting listener loop:
ThreadPool.SetMinThreads(100, 100);
This let your code work under "burst" connections count/network loading. We've just successfully "load tested" 7,5K connections under linux/mono.
You can't have 100,000 connections to a single machine. TCP/IP only has 16 bits for a port number (maximum 64k ports), and a good number of these are used (or reserved) for the OS or various services.
Normally, only 16,383 of these ports are available for incoming client connections, and you'll need to share them with all the other processes that use TCP/IP regularly.
Related
I made a little experiment where a server send continually a message to a client until a second client be connected. Testing with telnet, the first client receive the message continually, but when the second client connects, the client counter (nClients) increments in the second client thread, but not in the first one. So with a third and a fourth clients an so on. Variable nClients still being 1 in the first client but is incremented in the next ones.
The code:
class Program
{
volatile static int nClients = 0;
static void clientThread(object socket)
{
Socket client = (Socket)socket;
IPEndPoint ieCliente = (IPEndPoint)client.RemoteEndPoint;
Console.WriteLine("IP: {0} port: {1}", ieCliente.Address, ieCliente.Port);
nClients++;
Console.WriteLine(nClients);
using (NetworkStream ns = new NetworkStream(client))
using (StreamWriter sw = new StreamWriter(ns))
{
sw.WriteLine("Welcome");
sw.Flush();
while (nClients < 2)
{
sw.WriteLine($"Waiting clients... now {nClients} connected");
sw.Flush();
//Thread.Sleep(100);
}
sw.WriteLine($"{nClients} clients");
sw.Flush();
}
client.Close();
}
static void Main(string[] args)
{
int port = 31416;
IPEndPoint ie = null;
ie = new IPEndPoint(IPAddress.Any, port);
using (Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
s.Bind(ie);
s.Listen(5);
Console.WriteLine($"Server listening at port: {ie.Port}");
while (true)
{
Socket cliente = s.Accept();
Thread th= new Thread(clientThread);
th.Start(cliente);
}
}
}
}
If I add an Thread.Sleep() into the loop (or even a Console.Writeline()) it works.
Why does the first thread not detect the change of nClients.
Actualization:
Following the feeedback recommendations, I was trying de Interlocked.Increment() and Volatile.Read() but the problem persist. My code again with these changes.
class Program
{
static int nClients = 0;
static void clientThread(object socket)
{
Socket client = (Socket)socket;
IPEndPoint ieCliente = (IPEndPoint)client.RemoteEndPoint;
Console.WriteLine("IP: {0} port: {1}", ieCliente.Address, ieCliente.Port);
Interlocked.Increment(ref nClients);
Console.WriteLine(Volatile.Read(ref nClients));
using (NetworkStream ns = new NetworkStream(client))
using (StreamWriter sw = new StreamWriter(ns))
{
sw.WriteLine("Welcome");
sw.Flush();
while (Volatile.Read(ref nClients) < 2)
{
sw.WriteLine($"Waiting clients... now {Volatile.Read(ref nClients)} connected");
sw.Flush();
//Thread.Sleep(100);
}
sw.WriteLine($"{Volatile.Read(ref nClients)} clients");
sw.Flush();
}
client.Close();
}
static void Main(string[] args)
{
int port = 31416;
IPEndPoint ie = null;
ie = new IPEndPoint(IPAddress.Any, port);
using (Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
s.Bind(ie);
s.Listen(5);
Console.WriteLine($"Server listening at port: {ie.Port}");
while (true)
{
Socket cliente = s.Accept();
Thread th = new Thread(clientThread);
th.Start(cliente);
}
}
}
}
And here a video showing this behavior. And a bonus: when I close abruptly the server, sometimes the client continue in the loop.
I think that for some reason when I close the server, Windows close the process but the threads memory is not released and continue running.
The problem is here:
nClients++;
This is being executed by more than one thread simultaneously, and it is not threadsafe.
The reason why is as follows. The code is (logically) equivalent to the following:
int temp = nClients + 1; // [A]
nClients = temp; // [B]
So lets imagine that nClients is 0. Thread #1 executes line [A] and thus temp is 1. Now imagine that before thread #1 has executed [B], thread #2 comes along and executes [A]. Thread #2's value for temp is also 1, because nothing has changed the value of nClients yet.
Now both threads continue, and they both set nClients to temp, which is 1.
Oops! An increment went missing.
That's what's happening. (Well, this is actually a gross simplification, but it's a good way to understand how it can go wrong.)
To fix it you can either put a lock around the incrementing code, or (simpler and more efficient) use Interlocked.Increment():
Interlocked.Increment(ref nClients);
The data I am using arrives by UDP. I want to create several UDP connections without blocking the main thread. I have implemented UDP connections synchronously and asynchronously, however they both keep the main thread locked. My code never reaches 'Console.WriteLine("Past the Async")'
The goal is to have the UDP connections running in the background.
Can anyone provide some direction as to what to try next, or how to properly implement an async version of UDP that allows the main thread to still receive commands?
I comment out ReceiveUdpData() for the async version.
class Program
{
// The whole point of this is to not block the main thread.
static async Task Main(string[] args)
{
ReceiveUdpData();
Console.WriteLine("Past Receive UDP Data");
await foreach (var item in MessagesAsync())
{
Console.WriteLine(item);
}
Console.WriteLine("Past The Async");
}
// Synchronous connection to UDP.
public static void ReceiveUdpData()
{
IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
var count = 0;
using (UdpClient client = new UdpClient(12345))
{
while (true)
{
Byte[] receiveBytes = client.Receive(ref remoteEndPoint);
count++;
Console.WriteLine(count);
}
}
}
// Async UDP connection
private static async IAsyncEnumerable<object> MessagesAsync()
{
IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
var count = 0;
using (UdpClient client = new UdpClient(12345))
{
while (true)
{
UdpReceiveResult test = await client.ReceiveAsync();
count++;
yield return test.ToString();
}
}
}
}
await will "block" the current method by scheduling the rest of the method to run after the given task continues. It's somewhat similar (not semantically identical to Task.ContinueWith) so csharp Console.WriteLine("Past The Async") will execute only after all the messages are received.
You can not wait for the messages by enumerating the IAsyncEnumerable on a separate task in a "fire and forget" manner:
static async Task Main(string[] args)
{
PrintMessages();
Console.WriteLine("Past The Async");
}
public static async Task PrintMessages()
{
await foreach (var item in MessagesAsync())
{
Console.WriteLine(item);
}
}
But if you do that, your program will terminate as soon as Main exits, so you might actually want to wait, or maybe you have some other work you can perform.
this a basis of program i am using to use an async udp:
sample:
using System;
using System.Net.Sockets;
using System.Net;
class Program {
static void OnUpdateData(IAsyncResult result) {
UdpClient socket = result.AsyncState as UdpClient;
IPEndPoint source = new IPEndPoint(0, 0);
byte[] message = socket.EndReceive(result, ref source);
Console.WriteLine($"Received {message.Length} bytes from {source}");
// schedule the next receive operation once reading is done:
socket.BeginReceive(new AsyncCallback(OnUpdateData), socket);
}
static void Main(string[] args) {
UdpClient socket = new UdpClient(12345);
socket.BeginReceive(new AsyncCallback(OnUpdateData), socket);
//send message with same program or use another program
IPEndPoint target = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 12345);
// send a couple of sample messages:
for (int num = 1; num <= 3; num++) {
byte[] message = new byte[num];
socket.Send(message, message.Length, target);
}
Console.ReadKey();
}
}
In a project I have multiple senders of UDP data, but only a single receiver.
If traffic gets higher, the receiver "forgets" lots of packets. I know that this is a problem inherent to UDP, but I want to minimize the number of lost packets.
I have read this SO question before!
Here is my code (Please excuse the massive code blocks, but I wanted the example to be self contained)
Sender side:
public class UdpSender
{
private static int portNumber = 15000;
public void Send(string data)
{
var udpServer = new UdpClient();
var ipEndPoint = new IPEndPoint(IPAddress.Broadcast, portNumber);
byte[] bytes = Encoding.ASCII.GetBytes(data);
udpServer.Send(bytes, bytes.Length, ipEndPoint);
udpServer.Close();
}
}
class Program
{
static void Main(string[] args)
{
var sender = new UdpSender();
var count = 100000;
for (var i = 0; i < count; ++i)
{
sender.Send(i.ToString());
}
Console.ReadKey();
}
}
Receiver side:
public class UDPListener
{
private static int portNumber = 15000;
private readonly UdpClient udp = new UdpClient(portNumber);
public volatile int CountOfReceived = 0;
public void StartListening()
{
this.udp.BeginReceive(Receive, new object());
}
private void Receive(IAsyncResult ar)
{
Interlocked.Increment(ref CountOfReceived);
IPEndPoint ip = new IPEndPoint(IPAddress.Any, portNumber);
byte[] bytes = udp.EndReceive(ar, ref ip);
string message = Encoding.ASCII.GetString(bytes);
StartListening();
}
}
class Program
{
static void Main(string[] args)
{
var listener = new UDPListener();
listener.StartListening();
while (true)
{
Console.WriteLine(listener.CountOfReceived.ToString("000,000,000"));
}
}
}
Right now if I start 5 sender applications in parallel, only about a quarter of the messages is received. This is only on my local machine.
What can I do to minimize packets lost?
thinking about the speed you're sending your packets on their trip i would say that the sinks buffer might be filled in a bit of time - increasing the buffer size (as shown here) could solve this issue, i guess.
This is my Server App:
public static void Main()
{
try
{
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
Console.WriteLine("Starting TCP listener...");
TcpListener listener = new TcpListener(ipAddress, 500);
listener.Start();
while (true)
{
Console.WriteLine("Server is listening on " + listener.LocalEndpoint);
Console.WriteLine("Waiting for a connection...");
Socket client = listener.AcceptSocket();
Console.WriteLine("Connection accepted.");
Console.WriteLine("Reading data...");
byte[] data = new byte[100];
int size = client.Receive(data);
Console.WriteLine("Recieved data: ");
for (int i = 0; i < size; i++)
Console.Write(Convert.ToChar(data[i]));
Console.WriteLine();
client.Close();
}
listener.Stop();
}
catch (Exception e)
{
Console.WriteLine("Error: " + e.StackTrace);
Console.ReadLine();
}
}
As you can see , it always listens while working , but I would like to specify that I want the app be able to listen and to have multiple connections support in the same time.
How could I modify this to constantly listen while also accepting the multiple connections?
The socket on which you want to listen for incoming connections is commonly referred to as the listening socket.
When the listening socket acknowledges an incoming connection, a socket that commonly referred to as a child socket is created that effectively represents the remote endpoint.
In order to handle multiple client connections simultaneously, you will need to spawn a new thread for each child socket on which the server will receive and handle data.
Doing so will allow for the listening socket to accept and handle multiple connections as the thread on which you are listening will no longer be blocking or waiting while you wait for the incoming data.
while (true)
{
Socket client = listener.AcceptSocket();
Console.WriteLine("Connection accepted.");
var childSocketThread = new Thread(() =>
{
byte[] data = new byte[100];
int size = client.Receive(data);
Console.WriteLine("Recieved data: ");
for (int i = 0; i < size; i++)
{
Console.Write(Convert.ToChar(data[i]));
}
Console.WriteLine();
client.Close();
});
childSocketThread.Start();
}
I had a similar problem today, and solved it like this:
while (listen) // <--- boolean flag to exit loop
{
if (listener.Pending())
{
Thread tmp_thread = new Thread(new ThreadStart(() =>
{
string msg = null;
TcpClient clt = listener.AcceptTcpClient();
using (NetworkStream ns = clt.GetStream())
using (StreamReader sr = new StreamReader(ns))
{
msg = sr.ReadToEnd();
}
Console.WriteLine("Received new message (" + msg.Length + " bytes):\n" + msg);
}
tmp_thread.Start();
}
else
{
Thread.Sleep(100); //<--- timeout
}
}
My loop did not get stuck on waiting for a connection and it did accept multiple connections.
EDIT: The following code snippet is the async-equivalent using Tasks instead of Threads. Please note that the code contains C#-8 constructs.
private static TcpListener listener = .....;
private static bool listen = true; // <--- boolean flag to exit loop
private static async Task HandleClient(TcpClient clt)
{
using NetworkStream ns = clt.GetStream();
using StreamReader sr = new StreamReader(ns);
string msg = await sr.ReadToEndAsync();
Console.WriteLine($"Received new message ({msg.Length} bytes):\n{msg}");
}
public static async void Main()
{
while (listen)
if (listener.Pending())
await HandleClient(await listener.AcceptTcpClientAsync());
else
await Task.Delay(100); //<--- timeout
}
Basic idea is, there is listener socket always listening on a given IP and port number. When ever there is connection request, listener accept the connection and remote end point is taken with tcpclient object till connection is closed or lost.
hey all,
I have made a socket server in C# for a flash game that I am developing, I got the code from somewhere and I am a beginner in c# and .net development . It works fine in practice when connections are made and the server functions correctly. Get 2 concurrent connections at the same time and we have a problem.
here is the basic aspects of the socket server below: (alot taken out for obvious reasons)
how can I alter this so that it can handle concurrent connections? Should I be threading each response?
Thanks
class TcpSock
{
int tcpIndx = 0;
int tcpByte = 0;
byte[] tcpRecv = new byte[1024];
////////////////////////////////////////
public Socket tcpSock;
////////////////////////////////////////
public int Recv(ref string tcpRead)
{
tcpByte = tcpSock.Available;
if (tcpByte > tcpRecv.Length - tcpIndx)
tcpByte = tcpRecv.Length - tcpIndx;
tcpByte = tcpSock.Receive(tcpRecv, tcpIndx, tcpByte,
SocketFlags.Partial);
tcpRead = Encoding.ASCII.GetString
(tcpRecv, tcpIndx, tcpByte);
tcpIndx += tcpByte;
return tcpRead.Length;
}
public int RecvLn(ref string tcpRead)
{
tcpRead = Encoding.ASCII.GetString
(tcpRecv, 0, tcpIndx);
tcpIndx = 0;
return tcpRead.Length;
}
public int Send(string tcpWrite)
{
return tcpSock.Send(Encoding.ASCII.GetBytes(tcpWrite));
}
public int SendLn(string tcpWrite)
{
return tcpSock.Send(Encoding.ASCII.GetBytes(tcpWrite + "\r\n"));
}
}
[STAThread]
static void Main()
{
Thread Server1 = new Thread(RunServer);
Server1.Start();
}
static void RunServer()
{
///class IPHostEntry : Stores information about the Host and is required
///for IPEndPoint.
///class IPEndPoint : Stores information about the Host IP Address and
///the Port number.
///class TcpSock : Invokes the constructor and creates an instance.
///class ArrayList : Stores a dynamic array of Client TcpSock objects.
IPHostEntry Iphe = Dns.Resolve(Dns.GetHostName());
IPEndPoint Ipep = new IPEndPoint(Iphe.AddressList[0], 4444);
Socket Server = new Socket(Ipep.Address.AddressFamily,SocketType.Stream, ProtocolType.Tcp);
///Initialize
///Capacity : Maximux number of clients able to connect.
///Blocking : Determines if the Server TcpSock will stop code execution
///to receive data from the Client TcpSock.
///Bind : Binds the Server TcpSock to the Host IP Address and the Port Number.
///Listen : Begin listening to the Port; it is now ready to accept connections.
ArrayList Client = new ArrayList();
string[,] Users = new string[1000,9];
string rln = null;
string[] Data;
Client.Capacity = 1000;
Server.Blocking = false;
Server.Bind(Ipep);
Server.Listen(32);
Console.WriteLine("Server 1 {0}: listening to port {1}", Dns.GetHostName(), Ipep.Port);
////////////////////////////////////////////////////////////////////////////////////////////
///Main loop
///1. Poll the Server TcpSock; if true then accept the new connection.
///2. Poll the Client TcpSock; if true then receive data from Clients.
while (true)
{
//Accept - new connection
#region new connection
if (Server.Poll(0, SelectMode.SelectRead))
{
int i = Client.Add(new TcpSock());
((TcpSock)Client[i]).tcpSock = Server.Accept();
Console.WriteLine("Client " + i + " connected.");
Users[i, 0] = i.ToString();
}
#endregion
for (int i = 0; i < Client.Count; i++)
{
//check for incoming data
if (((TcpSock)Client[i]).tcpSock.Poll(0, SelectMode.SelectRead))
{
//receive incoming data
if (((TcpSock)Client[i]).Recv(ref rln) > 0)
{
Console.WriteLine(rln.ToString());
Data = rln.Split('|');
// 1) initial connection
#region InitialConnection
if (Data[0] == "0000")
{
}
}
}
}
}
}
You will need to not use synchronous functions but asynchrounus functions like Socket.BeginReceive
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
public static partial class TcpServer
{
public static void Main()
{
// Setup listener on "localhost" port 12000
IPAddress ipAddr = Dns.GetHostEntry("localhost").AddressList[0];
TcpListener server = new TcpListener(ipAddr, 12000);
server.Start(); // Network driver can now allow incoming requests
// Accept up to 1 client per CPU simultaneously
Int32 numConcurrentClients = Environment.ProcessorCount;
for (Int32 n = 0; n
private static Byte[] ProcessData(Byte[] inputData)
{
String inputString = Encoding.UTF8.GetString(inputData, 1, inputData[0]);
String outputString = inputString.ToUpperInvariant();
Console.WriteLine("Input={0}", inputString);
Console.WriteLine(" Output={0}", outputString);
Console.WriteLine();
Byte[] outputStringBytes = Encoding.UTF8.GetBytes(outputString);
Byte[] outputData = new Byte[1 + outputStringBytes.Length];
outputData[0] = (Byte)outputStringBytes.Length;
Array.Copy(outputStringBytes, 0, outputData, 1, outputStringBytes.Length);
return outputData;
}
}
public static partial class TcpServer
{
private sealed class ClientConnectionApm
{
private TcpListener m_server;
private TcpClient m_client;
private Stream m_stream;
private Byte[] m_inputData = new Byte[1];
private Byte m_bytesReadSoFar = 0;
public ClientConnectionApm(TcpListener server)
{
m_server = server;
m_server.BeginAcceptTcpClient(AcceptCompleted, null);
}
private void AcceptCompleted(IAsyncResult ar)
{
// Connect to this client
m_client = m_server.EndAcceptTcpClient(ar);
// Accept another client
new ClientConnectionApm(m_server);
// Start processing this client
m_stream = m_client.GetStream();
// Read 1 byte from client which contains length of additional data
m_stream.BeginRead(m_inputData, 0, 1, ReadLengthCompleted, null);
}
private void ReadLengthCompleted(IAsyncResult result)
{
// If client closed connection; abandon this client request
if (m_stream.EndRead(result) == 0) { m_client.Close(); return; }
// Start to read 'length' bytes of data from client
Int32 dataLength = m_inputData[0];
Array.Resize(ref m_inputData, 1 + dataLength);
m_stream.BeginRead(m_inputData, 1, dataLength, ReadDataCompleted, null);
}
private void ReadDataCompleted(IAsyncResult ar)
{
// Get number of bytes read from client
Int32 numBytesReadThisTime = m_stream.EndRead(ar);
// If client closed connection; abandon this client request
if (numBytesReadThisTime == 0) { m_client.Close(); return; }
// Continue to read bytes from client until all bytes are in
m_bytesReadSoFar += (Byte)numBytesReadThisTime;
if (m_bytesReadSoFar
private void WriteDataCompleted(IAsyncResult ar)
{
// After result is written to client, close the connection
m_stream.EndWrite(ar);
m_client.Close();
}
}
}
First of all: Stop using non-blocking sockets. In .NET you should either stick to the synchronous methods Receive/Send or asynchronous methods BeginReceive/BeginSend.
You should only stick with sync methods if you will have only a handful of clients. Then launch each new client in a new thread. This is the easiest option to get everthing running.
Simply do like this:
public void AcceptClients()
{
TcpListener listener = new TcpListener(IPAddress.Any, 5566);
listener.Start();
while (_serverRunning)
{
var socket = listener.AcceptSocket();
new Thread(ClientFunc).Start(socket);
}
}
public void ClientFun(object state)
{
var clientSocket = (Socket)state;
var buffer = new byte[65535];
while (_serverRunning)
{
//blocking read.
clientSocket.Receive(buffer, 0, buffer.Length, SocketFlags.None);
//check packet.
// handle packet
// send respons.
clientSocket.Send(alalalal);
}
}
You should refactor the methods so that they follow SRP. The code is just a small guide to get you going.