c# sockets handling multiple clients - c#

I have the following code which I want to implement as my server. As I understand it is async. and should allow connections from multiple clients...
public void Start()
{
TcpListener listener = new TcpListener(IPAddress.Any, 10250);
listener.Start();
Console.WriteLine("Listening...");
while (true)
{
IAsyncResult res = listener.BeginAcceptTcpClient(HandleAsyncConnection, listener);
connectionWaitHandle.WaitOne();
}
}
private void HandleAsyncConnection(IAsyncResult res)
{
TcpListener listener = (TcpListener)res.AsyncState;
TcpClient client = listener.EndAcceptTcpClient(res);
connectionWaitHandle.Set();
StringBuilder sb = new StringBuilder();
var data = new byte[client.ReceiveBufferSize];
using (NetworkStream ns = client.GetStream())
{
// Test reply
Byte[] replyData = System.Text.Encoding.ASCII.GetBytes(DateTime.Now.ToString());
ns.Write(replyData, 0, replyData.Length);
ns.Flush();
ns.Close();
}
client.Close();
}
I have a test app which simply fires requests to my server. As you can see in the code the server just replies with its date/time. The test app sends say 20 requests which are simply test strings. For each of these requests it opens a socket, sends the data to my server and then closes the socket again.
This works fine with one test app running. However, if I open two test apps the second one cannot connect to the server. I thought because I am handling the request async. and because my test app opens then closes the socket before each call I could handle requests from multiple clients?

Edit
If using >=.Net4.5, it's better to use the new network methods that then permit the adoption of async and await. As such, it might be better to follow the example I provided in this post as a starting point.
Original Post
The following code demonstrates how to accept multiple clients asynchronously without spinning off a new thread per connection.
private TcpListener listener;
public void Start()
{
listener = new TcpListener(IPAddress.Any, 10250);
listener.Start();
Console.WriteLine("Listening...");
StartAccept();
}
private void StartAccept()
{
listener.BeginAcceptTcpClient(HandleAsyncConnection, listener);
}
private void HandleAsyncConnection(IAsyncResult res)
{
StartAccept(); //listen for new connections again
TcpClient client = listener.EndAcceptTcpClient(res);
//proceed
}
You can use this pattern for most async operations.

The way you did it, there is no benefit compared to using AcceptTcpClient. Simply loop and create a new thread for each accepted connection:
public void Start()
{
TcpListener listener = new TcpListener(IPAddress.Any, 10250);
listener.Start();
Console.WriteLine("Listening...");
while (canRun)
{
var client = listener.AcceptTcpClient();
new Thread(ClientThread).Start(client);
}
}
private void ClientThread(IAsyncResult res)
{
TcpClient client = (TcpClient)res.AsyncState;
StringBuilder sb = new StringBuilder();
var data = new byte[client.ReceiveBufferSize];
using (NetworkStream ns = client.GetStream())
{
// Test reply
Byte[] replyData = System.Text.Encoding.ASCII.GetBytes(DateTime.Now.ToString());
ns.Write(replyData, 0, replyData.Length);
ns.Flush();
ns.Close();
}
client.Close();
}
A golden rule when using asynchronous methods is to NOT block the operation. Blocking would defeat the purpose of using async ops.
public void Start()
{
TcpListener listener = new TcpListener(IPAddress.Any, 10250);
listener.Start();
Console.WriteLine("Listening...");
listener.BeginAcceptTcpClient(OnAccept, listener);
}
private void OnAccept(IAsyncResult res)
{
TcpListener listener = (TcpListener)res.AsyncState;
TcpClient client = listener.EndAcceptTcpClient(res);
StringBuilder sb = new StringBuilder();
var data = new byte[client.ReceiveBufferSize];
using (NetworkStream ns = client.GetStream())
{
// Test reply
Byte[] replyData = System.Text.Encoding.ASCII.GetBytes(DateTime.Now.ToString());
ns.Write(replyData, 0, replyData.Length);
ns.Flush();
ns.Close();
}
client.Close();
}

Related

TcpListener backlog concept misunderstanding

I'm trying to understand the backlog parameter of TcpListener class but I struggle on how to achieve maximum number of pending connections at same time so I can test it.
I have a sample async server and client code. MSDN says that the backlog is the maximum length of the pending connections queue. I made the server listen for connections all the time and the client is connecting 30 times. What I expect is after the 20th request to throw a SocketException in the client because the backlog is set to 20. Why doesn't it block it?
My second misunderstanding is do I really need to put my logic of the accepted connection in a new thread assuming there is a slow operation which takes around 10 seconds e.g. sending a file over the TCP? Currently, I put my logic in a new Thread, I know it's not the best solution and instead I should use a ThreadPool but the question is principal. I tested it by changing the client side's loop to 1000 iterations and if my logic is not in a new thread, the connections were getting blocked after the 200th connection probably because Thread.Sleep slows the main thread each time by 10 seconds and the main thread is responsible for all the accept callbacks. So basically, I explain it myself as the following: if I want to use the same concept, I have to put my AcceptCallback logic in a new thread like I did or I have to do something like the accepted answer here: TcpListener is queuing connections faster than I can clear them. Am I right?
Server code:
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace Server
{
class Program
{
private static readonly ManualResetEvent _mre = new ManualResetEvent(false);
static void Main(string[] args)
{
TcpListener listener = new TcpListener(IPAddress.Any, 80);
try
{
listener.Start(20);
while (true)
{
_mre.Reset();
Console.WriteLine("Waiting for a connection...");
listener.BeginAcceptTcpClient(new AsyncCallback(AcceptCallback), listener);
_mre.WaitOne();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private static void AcceptCallback(IAsyncResult ar)
{
_mre.Set();
TcpListener listener = (TcpListener)ar.AsyncState;
TcpClient client = listener.EndAcceptTcpClient(ar);
IPAddress ip = ((IPEndPoint)client.Client.RemoteEndPoint).Address;
Console.WriteLine($"{ip} has connected!");
// Actually I changed it to ThreadPool
//new Thread(() =>
//{
// Console.WriteLine("Sleeping 10 seconds...");
// Thread.Sleep(10000);
// Console.WriteLine("Done");
//}).Start();
ThreadPool.QueueUserWorkItem(new WaitCallback((obj) =>
{
Console.WriteLine("Sleeping 10 seconds...");
Thread.Sleep(10000);
Console.WriteLine("Done");
}));
// Close connection
client.Close();
}
}
}
Client code:
using System;
using System.Net.Sockets;
namespace Client
{
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 30; i++)
{
Console.WriteLine($"Connecting {i}");
using (TcpClient client = new TcpClient()) // because once we are done, we have to close the connection with close.Close() and in this way it will be executed automatically by the using statement
{
try
{
client.Connect("localhost", 80);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
Console.ReadKey();
}
}
}
Edit: Since my second question might be a little bit confusing, I will post my code which includes sent messages and the question is should I leave it like that or put the NetworkStream in a new thread?
Server:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace Server
{
class Program
{
private static readonly ManualResetEvent _mre = new ManualResetEvent(false);
static void Main(string[] args)
{
// MSDN example: https://learn.microsoft.com/en-us/dotnet/framework/network-programming/asynchronous-server-socket-example
// A better solution is posted here: https://stackoverflow.com/questions/2745401/tcplistener-is-queuing-connections-faster-than-i-can-clear-them
TcpListener listener = new TcpListener(IPAddress.Any, 80);
try
{
// Backlog limit is 200 for Windows 10 consumer edition
listener.Start(5);
while (true)
{
// Set event to nonsignaled state
_mre.Reset();
Console.WriteLine("Waiting for a connection...");
listener.BeginAcceptTcpClient(new AsyncCallback(AcceptCallback), listener);
// Wait before a connection is made before continuing
_mre.WaitOne();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private static void AcceptCallback(IAsyncResult ar)
{
// Signal the main thread to continue
_mre.Set();
TcpListener listener = (TcpListener)ar.AsyncState;
TcpClient client = listener.EndAcceptTcpClient(ar);
IPAddress ip = ((IPEndPoint)client.Client.RemoteEndPoint).Address;
Console.WriteLine($"{ip} has connected!");
using (NetworkStream ns = client.GetStream())
{
byte[] bytes = Encoding.Unicode.GetBytes("test");
ns.Write(bytes, 0, bytes.Length);
}
// Use this only with backlog 20 in order to test
Thread.Sleep(5000);
// Close connection
client.Close();
Console.WriteLine("Connection closed.");
}
}
}
Client:
using System;
using System.Net.Sockets;
using System.Text;
namespace Client
{
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 33; i++)
{
Console.WriteLine($"Connecting {i}");
using (TcpClient client = new TcpClient()) // once we are done, the using statement will do client.Close()
{
try
{
client.Connect("localhost", 80);
using (NetworkStream ns = client.GetStream())
{
byte[] bytes = new byte[100];
int readBytes = ns.Read(bytes, 0, bytes.Length);
string result = Encoding.Unicode.GetString(bytes, 0, readBytes);
Console.WriteLine(result);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
Console.ReadKey();
}
}
}
The listen backlog is defined in RFC 6458 and tells the OS the maximum number of sockets allowed in the accept queue.
Incoming connections are placed in this queue by the TCP/IP stack and removed when the server calls Accept to handle the new connection.
In your question, both versions of the server code call Accept in a loop from the main thread, and wait for AcceptCallback to start before making another accept call. This results in quite fast draining of the queue.
To demonstrate listen queue overflow, its easiest to slow down your server's rate of accepting - E.g. slow it down to zero:
var serverEp = new IPEndPoint(IPAddress.Loopback, 34567);
var serverSocket = new TcpListener(serverEp);
serverSocket.Start(3);
for (int i = 1; i <= 10; i++)
{
var clientSocket = new TcpClient();
clientSocket.Connect(serverEp);
Console.WriteLine($"Connected socket {i}");
}
In your examples you could just add a sleep at the end of the Accept loop in the main thread, and increase the connection rate.
In the real world, the optimal backlog depends on:
The rate that the clients / internet / OS can fill the queue
The rate that the OS / server can process the queue
I don't recommend using Thread directly, here's how the server looks using Task and Socket Task Extensions:
static async Task Main(string[] args)
{
var server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
server.Bind(new IPEndPoint(IPAddress.Any, 80));
server.Listen(5);
while (true)
{
var client = await server.AcceptAsync();
var backTask = ProcessClient(client);
}
}
private static async Task ProcessClient(Socket socket)
{
using (socket)
{
var ip = ((IPEndPoint)(socket.RemoteEndPoint)).Address;
Console.WriteLine($"{ip} has connected!");
var buffer = Encoding.Unicode.GetBytes("test");
await socket.SendAsync(buffer, SocketFlags.None);
}
Console.WriteLine("Connection closed.");
}

TCPListener in windows form

I am trying to write a TCP listener that can connect to multiple clients and send and receive data.
Some of my code -
Calling server -
private void Form1_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'cresijCamDataSet1.CentralControl' table. You can move, or remove it, as needed.
this.centralControlTableAdapter1.Fill(this.cresijCamDataSet1.CentralControl);
s = new Server();
Thread th = new Thread(s.Run);
th.Start();
}
Run Method -
public async void Run()
{
tcp = new TcpListener(IPAddress.Any, 1200);
tcp.Start();
while (true)
{
try
{
TcpClient client = await tcp.AcceptTcpClientAsync();
Thread th = new Thread(()=>{
Process(client);
}) ;
}
catch (Exception ex)
{
string m = ex.Message;
}
}
}
private async Task Process(TcpClient tcpClient)
{
bool hasItem = clients.Contains(tcpClient);
if(hasItem == false)
{
clients.Add(tcpClient);
}
IPEndPoint iPEndPoint =(IPEndPoint) tcpClient.Client.RemoteEndPoint;
string ip = ((IPEndPoint)tcpClient.Client.RemoteEndPoint).Address.ToString();
NetworkStream stream = tcpClient.GetStream();
byte[] receivedBytes = new byte[tcpClient.ReceiveBufferSize];
stream.Read(receivedBytes, 0, receivedBytes.Length);
f.UpdateData(receivedBytes, ip);
}
Sender Method to send data -
public void Sender(byte[] data, TcpClient client)
{
NetworkStream stream = client.GetStream();
stream.Write(data, 0, data.Length);
}
As you can see I have called Run() method in formLoad. But this all is not working as I dont have much knowledge of threads.
This method is not continuous. The server is not listening to clients always. Can someone help me with this. I need asynchronuous tcp listener that can listen to incoming clients and that too in windows form. Console Server I have.

TCP/IP Continuously receive message without closing the connection

I've been watching the following pair of videos on how to create a TCP/IP connection : Server and Client
What I need to do is create a game (flipcard) in which I send only 2 coordinates for a matrix. Nothing more. Or less.
(the code will follow)
From what I've observed, he closes and reopens the connection, everytime he send a message. It's working. But what do I modify in the code to keep the connection open and detect when a message arrived ?
All my google-searches brought me to these 2 methods:
I have had luck using the socket object directly (rather than the TCP client). (But I do not want to use sockets)
Also uses sockets
When I click to start the server
private void bStartServer_Click(object sender, EventArgs e)
{
Thread tcpServerRunThread = new Thread(new ThreadStart(TCPServerRun));
tcpServerRunThread.Start();
}
Server Runs and waits for a connection
private void TCPServerRun()
{
TcpListener tcpListener = new TcpListener(IPAddress.Any, 2016);
tcpListener.Start();
updateUI("Listening");
while (true)
{
TcpClient client = tcpListener.AcceptTcpClient();
updateUI("Connected");
Thread tcpHandlerThread = new Thread(new ParameterizedThreadStart(tcpHandler));
tcpHandlerThread.Start(client);
}
}
I handle my message
private void tcpHandler(object client)
{
TcpListener tcpListener = new TcpListener(IPAddress.Any, 5004);
TcpClient mClient = (TcpClient)client;
NetworkStream stream = mClient.GetStream();
byte[] message = new byte[1024];
stream.Read(message,0, message.Length);
updateUI("New message = " + Encoding.ASCII.GetString(message));
stream.Close();
mClient.Close();
}
NOTE: updateUI is a function made by him to update a listbox item
Client side - almost like the server side
`private void button1_Click(object sender, EventArgs e)
{
Thread mThread = new Thread(new ThreadStart(ConnectAsClient));
mThread.Start();
}
private void ConnectAsClient()
{
// aici putem inlocui cu adresa de IP dorita
//client.Connect(IPAddress.Parse(textBox.Text), 5004);
client = new TcpClient();
//client.Connect(IPAddress.Parse("127.0.0.1"), 2016); // for when I'm not connected to network
client.Connect(IPAddress.Parse("my_ip_here"), 2016); // for when I am connected to the network
updateUI("connected");
NetworkStream stream = client.GetStream();
string s = "Hello world!";
byte[] message = Encoding.ASCII.GetBytes(s);
stream.Write(message, 0, message.Length);
this.updateUI("Message sent!");
stream.Close();
// client.Close();
}`
If I'm not wrong, everytime he connects again, he creates a new connection, and not open the old one, right?
(It's my first time using TCP/IP, learning on my own, so I'd rather not use sockets, if possible)
-----------------------------------------------------------------------
Full link to my code (slighty modified from the videos provided at the beginning):
TCPClient
TCPServer
You are reconnecting every time you send the message. Use two different methods for this; one for connecting to the server and then another one for actually sending the message. Like so:
TcpClient client;
private void ConnectAsClient()
{
//client.Connect(IPAddress.Parse(textBox.Text), 5004);
client = new TcpClient();
//client.Connect(IPAddress.Parse("127.0.0.1"), 2016);
client.Connect(IPAddress.Parse("my_ip_here"), 2016);
updateUI("connected");
}
void SendMessage()
{
NetworkStream stream = client.GetStream();
string s = "Hello world!";
byte[] message = Encoding.ASCII.GetBytes(s);
stream.Write(message, 0, message.Length);
this.updateUI("Message sent!");
}

TCP IP Listener in windows Service

I'm trying to create a windows service that needs to run in the background and listen for incoming traffic (a normal and regular TCP listener)
my code is:
private TcpListener server;
public void startServer()
{
// EventLog.WriteEntry(source, "connected on: " + ipAddress.ToString() + " port: " + Service1.Port.ToString());
server = new TcpListener(IPAddress.Parse("127.0.0.1"), Service1.Port);
server.Start();
while (true)
{
var client = server.AcceptTcpClient();
new Thread(work).Start(client);
}
public void work(object client)
{
string msg = null;
var clientLocal = (TcpClient)client;
using (NetworkStream ns = clientLocal.GetStream())
using (StreamReader sr = new StreamReader(ns))
{
byte[] msgFullArray = new UTF8Encoding(true).GetBytes(msg);
fs.Write(msgFullArray, 0, msg.Length);
}
now if you don't look at the work method at all as whenever i start my service it freezes whenever i try to start it at my :
var client = server.AcceptTcpClient();
meaning my service never gets to use the Thread or my Work method..
i can see from previous logging that it enters my while loop and then just times out the service
In your OnStart Method you have to instantiate a server class.
protected override void OnStart(string[] args)
{
// Create the Server Object ans Start it.
server = new TCPServer();
server.StartServer();
}
that is responsible to handle the connections to the server by creating a new Thread (so that it is a non-blocking process)
public void StartServer()
{
if (m_server!=null)
{
// Create a ArrayList for storing SocketListeners before
// starting the server.
m_socketListenersList = new ArrayList();
// Start the Server and start the thread to listen client
// requests.
m_server.Start();
m_serverThread = new Thread(new ThreadStart(ServerThreadStart));
m_serverThread.Start();
// Create a low priority thread that checks and deletes client
// SocktConnection objcts that are marked for deletion.
m_purgingThread = new Thread(new ThreadStart(PurgingThreadStart));
m_purgingThread.Priority=ThreadPriority.Lowest;
m_purgingThread.Start();
}
}
for each socket that it will be listening by a TCPListener.
private void ServerThreadStart()
{
// Client Socket variable;
Socket clientSocket = null;
TCPSocketListener socketListener = null;
while(!m_stopServer)
{
try
{
// Wait for any client requests and if there is any
// request from any client accept it (Wait indefinitely).
clientSocket = m_server.AcceptSocket();
// Create a SocketListener object for the client.
socketListener = new TCPSocketListener(clientSocket);
// Add the socket listener to an array list in a thread
// safe fashon.
//Monitor.Enter(m_socketListenersList);
lock(m_socketListenersList)
{
m_socketListenersList.Add(socketListener);
}
//Monitor.Exit(m_socketListenersList);
// Start a communicating with the client in a different
// thread.
socketListener.StartSocketListener();
}
catch (SocketException se)
{
m_stopServer = true;
}
}
}
Here it is the full project article.

TcpClient/TcpServer/Listener, Server stops reading or client stops after 30 seconds

Client
class Client
{
public TcpClient client;
public StreamWriter server;
public ServerPlayer serverPlayer;
public Player player;
public void Connect(Player p)
{
player = p;
serverPlayer = new ServerPlayer();
client = new TcpClient(AddressFamily.InterNetwork);
client.Connect("Don't wory my IPV4 Is Here", 8888);
NetworkStream stream = client.GetStream();
server = new StreamWriter(stream);
Timer t = new Timer(Send, null, 0, 10);
}
public void Send(Object o)
{
server.WriteLine("Hello I am bob");
server.Flush();
}
}
Server
class TcpServerConnection
{
private static TcpListener tcpListener;
static void Main(string[] args)
{
tcpListener = new TcpListener(IPAddress.Any, 8888);
tcpListener.Start();
Console.WriteLine("Server started.");
while (true)
{
//blocks until a client has connected to the server
TcpClient client = tcpListener.AcceptTcpClient();
//create a thread to handle communication
//with connected client
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.Start(client);
}
}
private static void HandleClientComm(object client)
{
while (true)
{
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
StreamReader server = new StreamReader(clientStream);
Console.WriteLine(server.ReadLine());
}
}
}
Problem
Track of events:
Started!
Hello I am bob
Hello I am bob
(Many Hello I am bobs later)
Hello I am bob
(Hello I am bobs just stopped)
(About 30 seconds)
Don't know if it because the client stops sending or server stops receiving or both!? But once this is ran about 30 seconds into this the server stops getting the send information. No error is thrown simply it just doesn't send.
Found out it was my internet. After my google-fu. I set my port for my server to be TCP open. Found out my router was getting suspicious after a spam of messages going into a random port. IP:IPV4 PORT:8888 SETTINGS:OPEN
Ok in your ServerConnection object the first while loop is fine. but the one in your handler is going to cause some problems try this:
private static void HandleClientComm(object client)
{
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
using(var stream = new StreamReader(clientStream))
{
while (stream.Peek() >= 0)
{
Console.WriteLine(server.ReadLine());
}
}
}
Since you are creating one and only one connection to the Server, and then sending messages constantly in the Client, accordingly when handling the client messages in the Server program, you should accept a TcpClient and then read messages in a loop, instead of accepting a Tcplient and reading a message all in a loop.
private static void HandleClientComm(object client)
{
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
StreamReader server = new StreamReader(clientStream);
while (true)
{
Console.WriteLine(server.ReadLine());
}
}

Categories