I've been writing a server for an app of mine. Due to suggestions, I decided to use HttpListener to listen for incoming connections in an async method. My current code is as following:
public static async void StartServerAsync()
{
while (true)
{
Console.WriteLine("Waiting for client.. ");
var context = await listener.GetContextAsync();
Console.WriteLine("Client connected!");
// ReSharper disable once CSharpWarnings::CS4014
Task.Factory.StartNew(() => ProcessClient(context));
}
listener.Close();
}
This method is started with this:
public static void ServerBoot()
{
listener.Prefixes.Add("http://localhost:1000/");
listener.Start();
StartServerAsync();
}
The ProcessClient() method is as following:
private static void ProcessClient(HttpListenerContext context)
{
try
{
var request = context.Request;
string response;
using (var reader = new StreamReader(request.InputStream, request.ContentEncoding))
{
response = reader.ReadToEnd();
}
Console.WriteLine("Got command: {0}", response);
}
catch (WebException)
{
Console.WriteLine("Error reading string, closing..");
return;
}
}
Right now it's only supposed to get the string posted. However, when I run the client with this code:
Console.WriteLine(" -- Bagrut Client -- ");
Console.Write("Enter IP of server to connect to: ");
// ReSharper disable once AssignNullToNotNullAttribute
var ip = Console.ReadLine();
WebClient client = new WebClient();
var response = client.UploadString(ip, "query");
Console.WriteLine("Type of response is {0}", response);
the server does not do anything. As you can see in ProcessClient(), and in the server loop itself, it should at least say something when a client connects. However, when the code is run, nothing happens. Am I doing something wrong?
EDIT: new code:
public static void ServerBoot()
{
HttpListener listener = new HttpListener();
listener.Prefixes.Add("http://localhost:1337/");
listener.Start();
StartServerAsync(listener).ContinueWith(task => { });
}
private static void ProcessClient(HttpListenerContext context)
{
try
{
var request = context.Request;
string response;
using (var reader = new StreamReader(request.InputStream, request.ContentEncoding))
{
response = reader.ReadToEnd();
}
Console.WriteLine("Got command: {0}", response);
}
catch (WebException)
{
Console.WriteLine("Error reading string, closing..");
return;
}
}
private static async Task StartServerAsync(HttpListener listener)
{
while (true)
{
Console.WriteLine("Waiting for client.. ");
var context = await listener.GetContextAsync();
Console.WriteLine("Client connected!");
// ReSharper disable once CSharpWarnings::CS4014
Task.Factory.StartNew(() => StartServerAsync(listener));
ProcessClient(context);
await StartServerAsync(listener);
}
listener.Close();
}
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 want to receive message from websocket (broker's websocket to get live stock data) after I send some message to server. I created dummy websocket server in Nodejs by which I can receive message from server but when I try to use client's websocket, it is not working.
Please note : I am able to connect to client's websocket.
Below are methods which I have used to connect, send and receive
Connect method
public static async Task Connect(string uri)
{
ClientWebSocket webSocket = null;
try
{
webSocket = new ClientWebSocket();
webSocket.Options.SetRequestHeader("x-session-token", "efcb0a89db75d4faa147035461224182");
await webSocket.ConnectAsync(new Uri(uri), CancellationToken.None);
await Task.WhenAll(Send(webSocket), Receive(webSocket));
}
catch (Exception ex)
{
Console.WriteLine("Exception: {0}", ex);
}
finally
{
if (webSocket != null)
webSocket.Dispose();
Console.WriteLine();
lock (consoleLock)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("WebSocket closed.");
Console.ResetColor();
}
}
}
For send, I want to send JSON data to server so that it will return me result accordingly. below is Send method
private static async Task Send(ClientWebSocket webSocket)
{
while (webSocket.State == WebSocketState.Open)
{
Symbol[] sym =
{
new Symbol
{
symbol = "1330_NSE"
}
};
RequestBody requestBody = new RequestBody()
{
request = new Request
{
streaming_type = "quote",
data = new Data()
{
symbols = sym
},
request_type = "subscribe",
response_format = "json"
}
};
var json = JsonConvert.SerializeObject(requestBody);
var sendBuffer = new ArraySegment<Byte>(Encoding.UTF8.GetBytes(json));
await webSocket.SendAsync(sendBuffer, WebSocketMessageType.Text, true, CancellationToken.None);
await Task.Delay(delay);
}
}
Below is receive method
private static async Task Receive(ClientWebSocket webSocket)
{
byte[] buffer = new byte[receiveChunkSize];
while (webSocket.State == WebSocketState.Open)
{
var result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
if (result.MessageType == WebSocketMessageType.Close)
{
await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
}
else
{
string message = Encoding.UTF8.GetString(buffer, 0, result.Count);
Console.WriteLine(message);
}
}
}
when I try to run it comes up to websocket.ReceiveAsync function and does nothing after it
var result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
I think, it is not waiting to receive messages from server?
Also I want to know if there is any way by which I can confirm that message I send from send method get sent to server or not ?
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 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;
}
I have async tcp server that can accept multiple clients at the same time. The scenarios where client requests data from server are served well. Now I am trying to implement the situation in which server has to find a particular client and send some data to it i.e. the client is connected but has not requested data but server wants to send some data to it. How can I find the thread that is already running between the server and client and place data on it?
Here is server code:
public async void RunServerAsync()
{
tcpListener.Start();
while (true)
{
try
{
var client = await tcpListener.AcceptTcpClientAsync();
Accept(client);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
private async void Accept(TcpClient client)
{
//get client information
String clientEndPoint = client.Client.RemoteEndPoint.ToString();
Console.WriteLine("Client connected at " + clientEndPoint );
await Task.Yield ();
try
{
using (client)
using (NetworkStream stream = client.GetStream())
{
byte[] dataReceived = new byte[100];
while (true) //read input stream
{
try
{
int x = await stream.ReadAsync(dataReceived, 0, dataReceived.Length);
if (x != 0)
{
//pass on data for processing
byte[] dataToSend = await ProcessData(dataReceived);
//send response,if any, to the client
if (dataToSend != null)
{
await stream.WriteAsync(dataToSend, 0, dataToSend.Length);
ConsoleMessages.DisplayDataSent(dataReceived, dataToSend);
}
}
}
catch (ObjectDisposedException)
{
stream.Close();
}
}
}
} //end try
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}//end Accept(TcpClient client)
You need to keep track of your clients. For example:
ConcurrentDictionary<Guid, TcpClient> _clients = new ConcurrentDictionary<Guid, TcpClient>();
public async void RunServerAsync()
{
tcpListener.Start();
while (true)
{
try
{
var client = await tcpListener.AcceptTcpClientAsync();
var clientId = Guid.NewGuid();
Accept(clientId, client);
_clients.TryAdd(clientId, client);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
public Task SendAsync(Guid clientId, Byte[] buffer, Int32 offset, Int32 count)
{
TcpClient client;
if (_clients.TryGetValue(clientId, out client))
return client.GetStream().WriteAsync(buffer, offset, count);
// client disconnected, throw exception or just ignore
return Task.FromResult<Object>(null);
}
public Boolean TryGetClient(Guid clientId, out TcpClient client)
{
return _clients.TryGetValue(clientId, out client);
}
private async void Accept(Guid clientId, TcpClient client)
{
//get client information
String clientEndPoint = client.Client.RemoteEndPoint.ToString();
Console.WriteLine("Client connected at " + clientEndPoint);
await Task.Yield();
try
{
using (client)
using (NetworkStream stream = client.GetStream())
{
byte[] dataReceived = new byte[100];
while (true) //read input stream
{
try
{
int x = await stream.ReadAsync(dataReceived, 0, dataReceived.Length);
if (x != 0)
{
//pass on data for processing
byte[] dataToSend = await ProcessData(dataReceived);
//send response,if any, to the client
if (dataToSend != null)
{
await stream.WriteAsync(dataToSend, 0, dataToSend.Length);
ConsoleMessages.DisplayDataSent(dataReceived, dataToSend);
}
}
}
catch (ObjectDisposedException)
{
stream.Close();
}
}
}
} //end try
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
// deregister client
_clients.TryRemove(clientId, out client);
}
}//end Accept(TcpClient client)
TCP is bi-directional, so either side can send data whenever they want.
What you need to do is store a reference to the TcpClient on Accept, something like:
//Class Level
List<TcpClient> connectedClients = List<TcpClient>();
private async void Accept(TcpClient client)
{
connectedClients.Add(client);
...
}
public SendMessage(int index, String message)
{
//pseudo-code
connectedClients[index].Send(message);
}
Normally I will raise an event on connect so whoever is using the class can get the new client's index. The send message code is pseudo-code, there are good examples on MSDN of how to actually perform the send.