C# tcp sockets defining clients - c#

I'm trying to setup a tcp .net socket network with Visual Studio 2010. So far it works I can connect clients up to it but currently I have no way of defining the clients that are connected. I need like an array of clients that are connected so I can be more specific about who i streamWrite to.
This is my server code I am copying all of this from http://www.codeproject.com/Articles/511814/Multi-client-per-one-server-socket-programming-in
SERVER CODE
static TcpListener tcpListener = new TcpListener(25000);
static void Listeners()
{
Socket socketForClient = tcpListener.AcceptSocket();
if (socketForClient.Connected)
{
Console.WriteLine("Client:"+socketForClient.RemoteEndPoint+" now connected to server.");
NetworkStream networkStream = new NetworkStream(socketForClient);
System.IO.StreamWriter streamWriter =
new System.IO.StreamWriter(networkStream);
System.IO.StreamReader streamReader =
new System.IO.StreamReader(networkStream);
Console.WriteLine("type your message to be recieved by client:");
string theString2 = Console.ReadLine();
streamWriter.WriteLine(theString2);
Console.WriteLine(theString2);
streamWriter.Flush();
while (true)
{
string theString = streamReader.ReadLine();
Console.WriteLine("Message recieved by client:" + theString);
if (theString == "exit")
break;
}
streamReader.Close();
networkStream.Close();
streamWriter.Close();
}
socketForClient.Close();
Console.WriteLine("Press any key to exit from server program");
Console.ReadKey();
}
public static void Main()
{
tcpListener.Start();
Console.WriteLine("************This is Server program************");
Console.WriteLine("Hoe many clients are going to connect to this server?:");
int numberOfClientsYouNeedToConnect = int.Parse(Console.ReadLine());
for (int i = 0; i < numberOfClientsYouNeedToConnect; i++)
{
Thread newThread = new Thread(new ThreadStart(Listeners));
newThread.Start();
}
}

If you want to stick to raw TCP Sockets, then you could pass a delegate/handler etc to the thread:
for (int i = 0; i < numberOfClientsYouNeedToConnect; i++)
{
Thread newThread = new Thread(new ParameterizedThreadStart(Listeners));
newThread.Start(i);
}
Your listener then needs to take an object to match the ParametrizedThreadStart see MSDN
However, if you are developing both ends (as I commented) I'd suggest something more abstract like ASP.NET SignalR or similar for such a scenario. It adds a bit overhead, but you get Server-To-Client and vice versa communication on a conveniently abstractioned level.

Related

Strange infinite loop in thread in c# using network sockets

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);

How to set up TcpListener to always listen and accept multiple connections?

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.

Why socket file transferring is slower than windows copy?

I have a problem about network file transferring.
Socket TCP/UDP uploading is slower than native windows copy when there are more than 1 clients.
I have some PC with 1Gbps network.
Here are the Windows copy cases.
One client copy from the server, the maximum upload speed is about 100mbps. (It should be higher than 100mbps, there is bottleneck in the route.)
Two clients copy from the server, the maximum upload speed is about 200mbps.
Three clients copy from the server, the maximum upload speed is about 300mbps.
Here are the Socket cases.
One client download from the server, the maximum upload speed is about 100mbps.
Two clients download from the server, the maximum upload speed is about 100mbps.
Three clients download from the server, the maximum upload speed is about 100mbps.
As you see, the socket server upload speed does not increase while the client number increases.
We made a simple program to test this issues. It encounters the same issues.
It's just very simple send and recv calling.
Please check the codes.
class Program
{
static List<TcpClient> sessions = new List<TcpClient>();
static void Main(string[] args)
{
bool isServer = false;
Console.WriteLine("Run as a server? (Y/N)");
string answer = Console.ReadLine();
if (answer.ToUpper().StartsWith("Y")) isServer = true;
if (isServer)
{
TcpListener listener = new TcpListener(IPAddress.Any, 13579);
Console.WriteLine("Listening at: " + ((IPEndPoint)listener.LocalEndpoint).ToString());
listener.Start();
Thread workerThread = new Thread(() =>
{
while (true)
{
lock (sessions)
{
foreach (var client in sessions)
{
if (client.Available > 0)
{
byte[] buffer = new byte[client.Available];
int length = client.Client.Receive(buffer);
string filePath = Encoding.UTF8.GetString(buffer, 0, length);
if (File.Exists(filePath))
{
foreach (var receiver in sessions)
receiver.Client.SendFile(filePath, null, null, TransmitFileOptions.UseKernelApc | TransmitFileOptions.WriteBehind);
}
}
}
}
Thread.Sleep(200);
}
});
workerThread.IsBackground = true;
workerThread.Start();
while (true)
{
TcpClient client = listener.AcceptTcpClient();
lock (sessions)
{
sessions.Add(client);
}
}
}
else
{
Console.WriteLine("Enter the server IP:");
string ipAddress = Console.ReadLine();
TcpClient client = new TcpClient(ipAddress, 13579);
Console.WriteLine("Enter the file path on remote server:");
string remoteFilePath = Console.ReadLine();
if(remoteFilePath != "")
client.Client.Send(Encoding.UTF8.GetBytes(remoteFilePath));
byte[] recvBuffer = new byte[32768];
while(true)
{
try
{
client.Client.Receive(recvBuffer, 32768, SocketFlags.None);
}
catch (SocketException e)
{
Console.WriteLine("Transfer interrupted: {0}", e.Message);
break;
}
}
}
}
}
This is blocking us to implement the socket tool with better performance.
Hope stackoverflow guys could help us out.
Thanks advanced.
Of course it's slower. you are using the same thread to poll all clients.
You should switch to the asynchronous methods in the server (BeginRead/EndRead)

Telnet Server in C# :AsyncConnection in C#

I am writing a telnet server When i Execute the following program my program is exiting
and it is displaying content in only 1 cmd.I have used TCP ASynchronously my content
is not displaying on 2cmd .Please help me regarding this issue.
public void Start()
{
Int32 port = 21;
IPAddress localAddr = IPAddress.Parse("127.0.0.1");
server = new TcpListener(localAddr, port);
server.Start();
Byte[] bytes = new Byte[256];
Console.WriteLine("Listening...");
StartAccept();
}
private void StartAccept()
{
// listener.BeginAcceptTcpClient(OnAccept, listener);
server.BeginAcceptTcpClient(HandleAsyncConnection, server);
}
private void HandleAsyncConnection(IAsyncResult res)
{
String data = null;
TcpListener listener = (TcpListener)res.AsyncState;
//listen for new connections again
TcpClient client = server.EndAcceptTcpClient(res);
Byte[] bytes = new Byte[256];
while (true)
{
server.Start();
// TcpClient client = server.AcceptTcpClient();
Console.WriteLine("Connected!");
data = null;
NetworkStream stream = client.GetStream();
int b, i, a;
string str = null;
string str1 = null;
string str3 = null;
int k = 0;
int c = 0;
if (stream.CanWrite)
{
if (c == 0)
{
`enter code here`
byte[] Mybuff = Encoding.ASCII.GetBytes("Please Enter USer ID and Password");
stream.Write(Mybuff, 0, Mybuff.Length);
//StartAccept();
c++;
}
else
{
byte[] Mybuff = Encoding.ASCII.GetBytes("Please Enter USer ID and Password");
stream.Write(Mybuff, 0, Mybuff.Length);
StartAccept();
}
}
}
}
Try to add a Console.ReadLine(); after StartAccept(); to keep the console running.
If I understand correctly, you're trying to get what you type into console 1 to appear in console 2. Or at least to get the same data to appear in both console windows as sent by telnet commands from another console window.
If this is the case and you're using the same code to setup your command consoles then this won't work locally due to port clashes. The first command console doesn't reliquish ownership of port 21 for the second console to use.
On a windows machine it is now possible to implement port sharing using some WCF functionality. See here for more information.
It is normally advisable to use port numbers that aren't close to any other program when writing your own application. Say 17657 instead of 21, but this may be coloured by what your application intends to do.

socket programming in C# server

bellow is my code for server, which runs successfully but small problem is, when i send data from client from twice it accepts once.
e.g. if i run this server and client also togethor; first time it accepts data from client, second time when again i ping from client side it does not accept data third time when i ping from client side it accepts data, fourth time when i ping from client it does not accept data, fifth time when i ping from client it accepts data, and so on.....
thanking you in advanced.
class Program
{
//static byte[] Buffer { get; set; }
//static Socket sck;
static void Main(string[] args)
{
while (true)
{
Socket sck;
sck = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sck.Bind(new IPEndPoint(0, 2000));
sck.Listen(10);
Socket accepted = sck.Accept();
byte [] Buffer = new byte[accepted.SendBufferSize];
int bytesRead = accepted.Receive(Buffer);
byte[] formatted = new byte[30];
for (int i = 0; i < 30; i++)
{
formatted[i] = Buffer[i];
}
string strData = Encoding.ASCII.GetString(formatted);
Console.Write(strData + "\r\n");
sck.Close();
accepted.Close();
}
}
}
This is not how you normally code a server. Usually, the listener stays up and just accepts new connections and closes them when done. It's possible that on the second attempt the client connects to your old listener just before you close it. Try keeping the listener open or else close the listener as soon as you accept a connection.
You need a TcpListner
http://msdn.microsoft.com/en-us/library/system.net.sockets.tcplistener(v=vs.71).aspx
Also, to handle many requests you need the server the process multiple requests on different threads. You'll need a thread pool. Look at ThreadPool.QueueUserWorkitem.
Here's a more complete C# TCP server example using that:
http://www.codeproject.com/KB/IP/dotnettcp.aspx
You need run the server into Thread
public void StartListener()
{
while (true)
{
mySocket = myListener.AcceptSocket();
Console.WriteLine("\r\nsocket type = {0}", mySocket.SocketType);
if (mySocket.Connected)
{
byte[] receive = new byte[1024];
mySocket.Receive(receive, 1024, 0);
string sBuffer = Encoding.ASCII.GetString(receive);
}
}
}
Then:
IPAddress IPaddress = Dns.Resolve(Dns.GetHostName()).AddressList[0];
TcpListener myListener = new TcpListener(IPaddress, 50);
myListener.Start();
Thread th = new Thread(new ThreadStart(StartListener));
th.Start();
More info:
TcpListener Class
Thread

Categories

Resources