I am trying to learn C# programming language. I have a very simple question here. I wanted to make TCPServer and TCPClient. but I couldn't quite do what I wanted to do. What I want is to have 4 clients on 1 server and they can talk to each other. I want the names of the people speaking to be determined individually. Please can anyone help with this? (Sorry for bad english)
/Server Code/
namespace SimpleTcpSrvr
{
class Program
{
//private static object mTcpClient;
static void Main(string[] args)
{
Console.OutputEncoding = Encoding.UTF8;
int asd;
byte[] data = new byte[1024];
IPEndPoint asd2 = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1302);
Socket newsocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
newsocket.Bind(asd2);
newsocket.Listen(100);
Console.WriteLine("waiting for connection...");
Socket client = newsocket.Accept();
IPEndPoint clientep = (IPEndPoint)client.RemoteEndPoint;
var socket = (Socket)client;
Console.WriteLine((string.Format("New connection: " + socket.RemoteEndPoint.ToString())));
string welcome = "Chat Server";
data = Encoding.UTF8.GetBytes(Welcome my chat server);
client.Send(data, data.Length, SocketFlags.None);
string input;
while (true)
{
data = new byte[1024];
asd = client.Receive(data);
if (asd == 0)
break;
Console.WriteLine("TCPClient: " + Encoding.UTF8.GetString(data, 0, asd));
input = Console.ReadLine();
Console.SetCursorPosition(0, Console.CursorTop - 1);
Console.WriteLine("You: " + input);
client.Send(Encoding.UTF8.GetBytes(input));
}
Console.WriteLine("{0}'sinin bağlantısı kesildi.", clientep.Address);
client.Close();
newsocket.Close();
Console.ReadLine();
}
/Client Code/
namespace TCPClient
{
public class TcpClient
{
static void Main(string[] args)
{
Console.OutputEncoding = Encoding.ASCII;
byte[] data = new byte[1024];
string input, stringData;
IPEndPoint asd2 = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1302);
Socket newsocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
newsocket.Connect(asd2);
}
catch (SocketException e)
{
Console.WriteLine("cant connect server");
Console.WriteLine(e.ToString());
return;
}
int asd = newsocket.Receive(data);
stringData = Encoding.UTF8.GetString(data, 0, asd);
Console.WriteLine(stringData);
while (true)
{
input = Console.ReadLine();
Console.SetCursorPosition(0, Console.CursorTop - 1);
Console.WriteLine("You: " + input);
newsocket.Send(Encoding.UTF8.GetBytes(input));
data = new byte[1024];
asd = newsocket.Receive(data);
stringData = Encoding.UTF8.GetString(data, 0, asd);
byte[] utf8string = Encoding.UTF8.GetBytes(stringData);
Console.WriteLine("TCPServer:" + stringData);
}
Console.WriteLine("connection lost from server...");
newsocket.Shutdown(SocketShutdown.Both);
newsocket.Close();
Console.WriteLine("disconnected!");
Console.ReadLine();
}
}
}
Firstly, it has to be said, there are a million-and-one edge cases when working with sockets - unless you are actually writing a new transport-protocol to run over TCP, you'd be much better off investing your time into learning an existing transport such as HTTP or gRPC.
With that disclaimer out of the way:
Use TcpListener() instead of Socket() in your server.
Use TcpClient() instead of Socket() in your client.
Your server needs to be able to simultaneously handle multiple clients, for this, use the Task-based Asyncronous Pattern (TAP).
So in your server, you need an instance of TcpClient() for every connection that your server accepts().
Start with a place to store all of your Tasks, e.g.,
static List<Task> Tasks = new();
Next you need a TcpListener which accepts incomming connections and spawns a Task to manage the TcpClient associated with that connection e.g.,
static async Task RunServerAsync()
{
TcpListener tcpListener = new(IPAddress.Loopback, 9999);
tcpListener.Start();
while (true)
{
var tcpClient = await tcpListener.AcceptTcpClientAsync();
Tasks.Add(Task.Run(() => RunClientAsync(tcpClient)));
}
}
A simple TcpClient Task would look something like this
static async Task RunClientAsync(TcpClient tcpClient)
{
Console.WriteLine($"Connection from: [{tcpClient.Client.RemoteEndPoint}]");
var reader = new StreamReader(tcpClient.GetStream());
while (true)
{
var line = await reader.ReadLineAsync();
Console.WriteLine($"{tcpClient.Client.RemoteEndPoint}: {line}");
}
}
You can tie this together in a Main() like this:
static async Task Main(string[] args)
{
await Task.Run(() => RunServerAsync());
}
Now you have a very simple echo-line server that will accept connections from as many clients as you can throw at it.
To wrap it up, you could use the TAP to create clients, for your testing, maybe something like:
static async Task RunClientAsync(string message)
{
var tcpClient = new TcpClient("127.0.0.1", 9999);
StreamWriter sw = new(tcpClient.GetStream());
tcpClient.NoDelay = true;
while(true)
{
await sw.WriteLineAsync(message);
await sw.FlushAsync();
await Task.Delay(1000);
}
}
And of course you'd need to update your Main to support this, e.g.,
static async Task Main(string[] args)
{
_ = Task.Run(() => RunServerAsync());
await Task.Delay(1000); // give the server a sec to start
_ = Task.Run(() => RunClientAsync("This is from client1"));
_ = Task.Run(() => RunClientAsync("Client2 is here!!"));
_ = Task.Run(() => RunClientAsync("And I am client3"));
await Task.Delay(int.MaxValue);
}
Of course in a real application you'd never fire and forget your Tasks like that.
Full code for the sake of completeness:
class Program
{
static List<Task> Tasks = new();
static async Task RunClientAsync(TcpClient tcpClient)
{
Console.WriteLine($"Connection from: [{tcpClient.Client.RemoteEndPoint}]");
var reader = new StreamReader(tcpClient.GetStream());
while (true)
{
var line = await reader.ReadLineAsync();
Console.WriteLine($"{tcpClient.Client.RemoteEndPoint}: {line}");
}
}
static async Task RunServerAsync()
{
TcpListener tcpListener = new(IPAddress.Loopback, 9999);
tcpListener.Start();
while (true)
{
var tcpClient = await tcpListener.AcceptTcpClientAsync();
Tasks.Add(Task.Run(() => RunClientAsync(tcpClient)));
}
}
static async Task Main(string[] args)
{
_ = Task.Run(() => RunServerAsync());
await Task.Delay(1000); // give the server a sec to start
_ = Task.Run(() => RunClientAsync("This is from client1"));
_ = Task.Run(() => RunClientAsync("Client2 is here!!"));
_ = Task.Run(() => RunClientAsync("And I am client3"));
await Task.Delay(int.MaxValue);
}
static async Task RunClientAsync(string message)
{
var tcpClient = new TcpClient("127.0.0.1", 9999);
StreamWriter sw = new(tcpClient.GetStream());
tcpClient.NoDelay = true;
while(true)
{
await sw.WriteLineAsync(message);
await sw.FlushAsync();
await Task.Delay(1000);
}
}
}
Related
I have a requirement to use C# for a system that will do the following:
Connect to a remote host from a class method Method1
Continuously send requests to the remote host in 10 seconds intervals to maintain the connection established in step 1 in another class method Method2
In another class method, Method3, listen to the same port from where the requests in steps 1 and 2 were sent
But the problem I have is that when I try step 3, I get the exception
Address already in use
The following is my code showing the 3 methods
public static async Task Method1()
{
TcpClient _client = new TcpClient();
_client = new TcpClient();
await _client.ConnectAsync("IPAddress", 1234);
var localEndpoint = (IPEndPoint)_client.Client.LocalEndPoint;
sourcePort = localEndpoint.Port;
AppStatics.SourcePort = sourcePort;
var _stream = _client.GetStream();
await _stream.WriteAsync("...");
Task.Run(() => Method2(_stream));
Method3();
}
public static async Task Method2(NetworkStream stream)
{
//Start trying to connect to the remote server here
Console.WriteLine("Checking the connection with the USSD gateway...");
var _shakeTimer = new System.Timers.Timer(10000);
_shakeTimer.Elapsed += async (object source, ElapsedEventArgs e) => await SendNetworkConnectionCheck(stream);
_shakeTimer.AutoReset = true;
_shakeTimer.Enabled = true;
}
private static async Task<bool> SendNetworkConnectionCheck(NetworkStream stream)
{
stream.Write("...");
}
public static void Method3()
{
TcpListener listener = new TcpListener(IPAddress.Any, AppStatics.SourcePort);
listener.ExclusiveAddressUse = false;
listener.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
try
{
listener.Stop();
listener.Start();
while (true)
{
TcpClient acceptTask = listener.AcceptTcpClient();
TcpClient incomingClient = acceptTask;
}
}
} catch (SocketException sex)
{
if (sex.SocketErrorCode == SocketError.AddressAlreadyInUse)
{
listener.Stop();
listener = new TcpListener(IPAddress.Any, AppStatics.SourcePort);
listener.ExclusiveAddressUse = false;
listener.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
listener.Start();
}else
{
Console.WriteLine(sex.InnerException?.Message ?? sex.Message);
}
}
catch (Exception ex)
{
Console.WriteLine("There was error while trying to listen/handle incoming message");
string errMsg = ex.InnerException?.Message ?? ex.Message;
Console.WriteLine(errMsg);
Console.WriteLine(ex.StackTrace?.ToString() ?? ex.ToString());
}
}
I will appreciate any guidance to get this resolved.
Thank you.
I'm trying to create a C# Socket multi-user server (and eventually client).
I want this server to be able to accept multiple clients (who all join and leave at different random moments) and at the same time displays their data (that the server received).
Here is my SocketMultiServer code:
using System.Net.Sockets;
using System.Text;
using System;
using System.Threading;
// Threading
Thread MainThread = Thread.CurrentThread;
Console.Title = "Multi Server";
// Aanmaken van server
TcpListener listener = new TcpListener(System.Net.IPAddress.Any, 6969);
listener.Start(5);
Console.WriteLine("Server online...");
// 2 threads
Thread ListenerThread = new Thread(o => Listener(listener));
Thread ReceiverThread = new Thread(o => Receiver());
//Thread ReceiverThread = new Thread(o => Receiver(NetworkStream stream));
ListenerThread.Start();
ReceiverThread.Start();
static void Listener(TcpListener listener)
{
Console.WriteLine("TEST 2");
TcpClient client = listener.AcceptTcpClient();
Console.WriteLine("Client connected...");
NetworkStream stream = client.GetStream();
}
static void Receiver(NetworkStream stream)
{
while (true)
{
byte[] buffer = new byte[1024];
stream.Read(buffer, 0, buffer.Length);
int recv = 0;
foreach (byte b in buffer)
{
if (b != 0)
{
recv++;
}
}
string request = Encoding.UTF8.GetString(buffer, 0, recv);
Console.WriteLine(request);
}
}
I'm having the error: "Error CS7036 There is no argument given that corresponds to the required formal parameter 'stream' of 'Receiver(NetworkStream)' " at l17
Thread ReceiverThread = new Thread(o => Receiver());
My Client code (work in progress)
using System.Net.Sockets;
using System.Text;
using System;
TcpClient client = new TcpClient("127.0.0.1", 6969);
Console.WriteLine("Connected...");
Console.Write("Username > ");
string username = Console.ReadLine();
string username_ = username + (": ");
while (true)
{
Console.WriteLine("Message to send > ");
string msg = Console.ReadLine();
if (msg == "exit()")
{
break;
}
else
{
// msg converten
int byteCount = Encoding.ASCII.GetByteCount(msg + 1);
byte[] sendData = new byte[byteCount];
sendData = Encoding.ASCII.GetBytes(username_ + msg);
NetworkStream stream = client.GetStream();
stream.Write(sendData, 0, sendData.Length);
}
}
Does someone have a fix? I'm quite new to C#
Thanks in advance!
Your primary issue is that you need to pass NetworkStream to Receiver.
However, this is not the way to do a multi-receive server anyway. You are best off using Task and async.
CancellationTokenSource cancellation = new CancellationTokenSource();
static async Task Main()
{
Console.Title = "Multi Server";
Console.WriteLine("Press ENTER to stop server...");
var task = Task.Run(RunServer);
Console.ReadLine(); // wait for ENTER
cancellation.Cancel();
await task;
}
static async Task RunServer()
{
TcpListener listener;
try
{
listener = new TcpListener(IPAddress.Any, 6969);
listener.Start(5);
Console.WriteLine("Server online...");
while (!cancellation.IsCancellationRequested)
{
var client = await listener.AcceptTcpClientAsync();
Console.WriteLine("Client connected...");
Task.Run(async () => await Receiver(client), cancellation.Token);
}
}
catch (OperationCancelException)
{ //
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
if (listener?.Active == true)
listener.Stop();
}
}
static async Task Receiver(TcpClient client)
{
try
{
using client;
using var stream = client.GetStream();
var buffer = new byte[1024];
while (!cancellation.IsCancellationRequested)
{
var bytesReceived = await stream.ReadAsync(buffer, 0, buffer.Length);
if (bytesReceived == 0)
break;
string request = Encoding.UTF8.GetString(buffer, 0, bytesReceived);
Console.WriteLine(request);
}
}
catch (OperationCancelException)
{ //
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
You should have similar async code for the client. Don't forget to dispose everything with using
I need to forward the port of running service in k8s cluster. So I have use the example provided in github repo to do port forward for specific service. Now I would like to use the example in my test but when I call port forward method then I always get web socket exception but if I written the same code in console application then I don't get any exception it run perfectly fine.
private async Task<bool> ForwardPortOperation(string podName, int[] originalPort, int forwardPort)
{
var pod = GetPodObject(podName);
var webSocket = await _config.GetK8SClient().WebSocketNamespacedPodPortForwardAsync(pod.Metadata.Name, pod.Metadata.NamespaceProperty, originalPort, WebSocketProtocol.V4BinaryWebsocketProtocol);
var demux = new StreamDemuxer(webSocket);
demux.Start();
var stream = demux.GetStream((byte?)0, (byte?)0);
IPAddress ipAddress = IPAddress.Loopback;
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, forwardPort);
Socket listener = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
listener.Bind(localEndPoint);
listener.Listen(100);
Socket handler = null;
var accept = Task.Run(() =>
{
while (true)
{
handler = listener.Accept();
var bytes = new byte[4096];
while (true)
{
int bytesRec = handler.Receive(bytes);
stream.Write(bytes, 0, bytesRec);
if (bytesRec == 0 || Encoding.Default.GetString(bytes, 0, bytesRec).IndexOf("<EOF>", StringComparison.InvariantCultureIgnoreCase) > -1)
{
break;
}
listener.Close();
}
}
});
var copy = Task.Run(() =>
{
var buff = new byte[4096];
while (true)
{
var read = stream.Read(buff, 0, 4096);
handler.Send(buff, read, 0);
}
});
await accept;
await copy;
return true;
}
Port forward method:
public bool PortForward(string podName, int[] originalPort, int forwardPort)
{
return Task.Run(() => ForwardPortOperation(podName, originalPort, forwardPort)).Result;
}
Nunit test project:
[Test]
public void VerifyPortForward()
{
new Pod(_config).PortForward("web_service_application", new int[3100], 1615);
}
How can I run such async method in background? so that once port forward successful then I can continue to another test.
Exception:
https://gist.github.com/gittadesushil/bc3bf008b7a4fc62c33e97ab1fbf687f
I assume the method PortForward should be rewritten to be asynchronous in the following way:
public async Task<bool> PortForward(string podName, int[] originalPort, int forwardPort)
{
return await Task.Run(() => ForwardPortOperation(podName, originalPort, forwardPort));
}
After that you can write a NUnit test:
[Test]
public async Task VerifyPortForward()
{
var pod = new Pod(_config);
var result = await pod.PortForward("web_service_application", new int[3100], 1615);
// TODO: assert the result
}
I would create a tcp server with TcpListener, but I don't know what's the best solution to do that.
I tried with 3 examples. See below.
Example 1
(I used BeginAcceptTcpClient)
class Program
{
static void Main(string[] args)
{
var endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 4567);
var listener = new TcpListener(endPoint);
listener.Start();
AcceptTcpClient(listener);
while (true)
{
}
}
public static void AcceptTcpClient(TcpListener listener)
{
listener.BeginAcceptTcpClient(ClientConnected, listener);
}
public static void ClientConnected(IAsyncResult asyncResult)
{
var listener = (TcpListener)asyncResult.AsyncState;
var client = listener.EndAcceptTcpClient(asyncResult);
AcceptTcpClient(listener);
DoAsync(client);
}
}
Example 2
(I used BeginAcceptTcpClient with AutoResetEvent)
class Program1
{
private static readonly AutoResetEvent CONNECTION_WAIT_HANDLE = new AutoResetEvent(false);
static void Main(string[] args)
{
var endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 4567);
var listener = new TcpListener(endPoint);
listener.Start();
while (true)
{
listener.BeginAcceptTcpClient(ClientConnectedHandle, listener);
CONNECTION_WAIT_HANDLE.WaitOne();
CONNECTION_WAIT_HANDLE.Reset();
}
}
public static void ClientConnectedHandle(IAsyncResult asyncResult)
{
var listener = (TcpListener)asyncResult.AsyncState;
var client = listener.EndAcceptTcpClient(asyncResult);
CONNECTION_WAIT_HANDLE.Set();
DoAsync(client);
}
}
Example 3
(I used AcceptTcpClientAsync)
class Program2
{
static async Task Main(string[] args)
{
var endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 4567);
var listener = new TcpListener(endPoint);
listener.Start();
while (true)
{
var client = await listener.AcceptTcpClientAsync();
DoAsync(client);
}
}
public static void AcceptTcpClient(TcpListener listener)
{
listener.BeginAcceptTcpClient(ClientConnected, listener);
}
public static void ClientConnected(IAsyncResult asyncResult)
{
var listener = (TcpListener)asyncResult.AsyncState;
var client = listener.EndAcceptTcpClient(asyncResult);
AcceptTcpClient(listener);
DoAsync(client);
}
}
I think the best solution is the last (Example 3) but I'm not sure. What do you think of that?
This is the code that I'm using in my project. It's a receive only asynchronous server but you can modify it to your liking according to your needs in Task.Run(). I have commented out the code so that you can understand how it works.
static async Task Main(string[] args)
{
await RunServer();
}
static async Task RunServer()
{
TcpListener Listener = new TcpListener(IPAddress.Any, YOURPORTHERE); // Set your listener
Listener.Start(); // Start your listener
while (true) // Permanent loop, it may not be the best solution
{
TcpClient Client = await Listener.AcceptTcpClientAsync(); // Waiting for a connection
_ = Task.Run(() => { // Connection opened. Queues the specified job to run in the ThreadPool, meanwhile the server is ready to accept other connections in parallel
try
{
var Stream = Client.GetStream(); // (read-only) get data bytes
if (Stream.CanRead) // Verify if the stream can be read.
{
byte[] Buffer = new byte[Client.ReceiveBufferSize]; // Initialize a new empty byte array with the data length.
StringBuilder SB = new StringBuilder();
do // Start converting bytes to string
{
int BytesReaded = Stream.Read(Buffer, 0, Buffer.Length);
SB.AppendFormat("{0}", Encoding.ASCII.GetString(Buffer, 0, BytesReaded));
} while (Stream.DataAvailable); // Until stream data is available
if (SB != null) // Stream data is ready and converted to string
// Do some stuffs
}
}
catch (Exception Ex) // In case of errors catch it to avoid the app crash
{
ConsoleMessage.Error(Ex.ToString()); // Detailed exception
}
});
}
}
I am using .NET framework to create a server, which listens on two ports on localhost. It is a simple console application.
It works when I keep connecting to one of the ports, but after I connect to first, another does not respond. First still is alive.
Here is my code:
static void Main(string[] args)
{
IPAddress hostIP = Dns.GetHostAddresses("127.0.0.1")[0];
List<TcpListener> listeners = new List<TcpListener>()
{
new TcpListener(hostIP, 6060),
new TcpListener(hostIP, 6061)
};
foreach (TcpListener listener in listeners)
{
listener.Start();
}
try
{
while (true)
{
Socket socket = AcceptAnyConnection(listeners).Result;
NetworkStream stream = new NetworkStream(socket);
byte[] bytes = Encoding.UTF8.GetBytes(DateTime.Now.ToString());
stream.Write(bytes, 0, bytes.Length);
//stream.Close();
socket.Close();
}
}
finally
{
foreach (TcpListener listener in listeners)
{
listener.Stop();
}
}
}
private static async Task<Socket> AcceptAnyConnection(List<TcpListener> listeners)
{
List<Task<Socket>> tasks = new List<Task<Socket>>();
foreach (TcpListener listener in listeners)
{
tasks.Add(AcceptConnection(listener));
}
Task<Socket> completedTask = await Task.WhenAny(tasks);
return await completedTask;
}
private static async Task<Socket> AcceptConnection(TcpListener listener)
{
Socket socket = await listener.AcceptSocketAsync();
return socket;
}
await Task.WhenAny() blocks if I connect to another port.
I must be doing something wrong, but I am not sure what.
BTW, I did try the same with .NET Core console application, and it works fine.
Thanks
I'd suggest refactoring your code to something like this, and taking it from there. That is, run an infinite loop for each listener. That avoids problems with making sure that you only call AcceptTcpClientAsync once at a time for each client.
(Note there's no code to actually stop the listeners. Also completely untested - please use it only as an indication of the sort of approach to take)
static void Main(string[] args)
{
IPAddress hostIP = Dns.GetHostAddresses("127.0.0.1")[0];
List<TcpListener> listeners = new List<TcpListener>()
{
new TcpListener(hostIP, 6060),
new TcpListener(hostIP, 6061)
};
var listenerTasks = listeners.Select(x => RunTcpListener(x)).ToArray();
Task.WaitAll(listenerTasks);
}
private static async Task RunTcpListener(TcpListener listener)
{
listener.Start();
try
{
while (true)
{
using (var client = await listener.AcceptTcpClientAsync())
{
var stream = client.GetStream();
byte[] bytes = Encoding.UTF8.GetBytes(DateTime.Now.ToString());
stream.Write(bytes, 0, bytes.Length);
client.Close();
}
}
}
finally
{
listener.Stop();
}
}
Here is my code, after I followed a suggestion by canton7 to move the task list outside of loop and move add and remove tasks "as we go". Probably, I will have to look at it to clean it up, but the idea works:
static void Main(string[] args)
{
IPAddress hostIP = Dns.GetHostAddresses("127.0.0.1")[0];
List<TcpListener> listeners = new List<TcpListener>()
{
new TcpListener(hostIP, 6060),
new TcpListener(hostIP, 6061)
};
ProcessConnections(listeners).Wait();
}
private async static Task SendData(Socket socket)
{
NetworkStream stream = new NetworkStream(socket);
byte[] bytes = Encoding.UTF8.GetBytes(DateTime.Now.ToString());
await stream.WriteAsync(bytes, 0, bytes.Length);
socket.Close();
}
private static async Task ProcessConnections(List<TcpListener> listeners)
{
foreach (TcpListener listener in listeners)
{
listener.Start();
}
try
{
List<Task<Socket>> tasks = new List<Task<Socket>>();
foreach (TcpListener listener in listeners)
{
tasks.Add(AcceptConnection(listener));
}
while (true)
{
int i = Task.WaitAny(tasks.ToArray());
Socket socket = await tasks[i];
await SendData(socket);
tasks.RemoveAt(i);
tasks.Insert(i, AcceptConnection(listeners[i]));
}
}
finally
{
foreach (TcpListener listener in listeners)
{
listener.Stop();
}
}
}
private static async Task<Socket> AcceptConnection(TcpListener listener)
{
Socket socket = await listener.AcceptSocketAsync();
return socket;
}