Named Pipes not working for asynchronous duplex communication - c#

Somehow I am not able to get named pipes work for duplex communication between client and server for .Net app.
Duplex communication works fine when I go for sequential messaging, but when I make it random i.e., server and client can ping each other at any random time, it just doesn't work.
The other posts are not much helpful either - c# Full Duplex Asynchronous Named Pipes .NET
I am attaching my code as below:
-Server code:
namespace Server
{
class Program
{
static void Main(string[] args)
{
var namedPipeServerStream = new NamedPipeServerStream("myPipe",
PipeDirection.InOut, 1, PipeTransmissionMode.Message, PipeOptions.Asynchronous);
Task.Run(() => StartListeningAsync(namedPipeServerStream, (msg) => Console.WriteLine(msg)));
Task.Run(() => SendMessageAsync(namedPipeServerStream));
Console.ReadLine();
}
public static async Task SendMessageAsync(NamedPipeServerStream namedPipeServer)
{
using (var stream = new StreamWriter(namedPipeServer))
{
while (true)
{
await Task.Delay(2000);
try
{
var serialized = JsonConvert.SerializeObject($"Server {DateTime.Now}");
byte[] messageBytes = Encoding.UTF8.GetBytes(serialized);
if (!namedPipeServer.IsConnected)
{
namedPipeServer.WaitForConnection();
Console.WriteLine("Client connected");
}
await namedPipeServer.WriteAsync(messageBytes, 0, messageBytes.Length);
await namedPipeServer.FlushAsync();
namedPipeServer.WaitForPipeDrain();
}
catch (Exception exception)
{
Console.WriteLine($"Exception:{exception}");
}
}
}
}
public static async Task StartListeningAsync(NamedPipeServerStream namedPipeServer, Action<string> messageRecieved)
{
while (true)
{
try
{
StringBuilder messageBuilder = new StringBuilder();
string messageChunk = string.Empty;
byte[] messageBuffer = new byte[1024];
do
{
if (!namedPipeServer.IsConnected)
{
namedPipeServer.WaitForConnection();
Console.WriteLine("Client connected");
}
await namedPipeServer.ReadAsync(messageBuffer, 0, messageBuffer.Length);
messageChunk = Encoding.UTF8.GetString(messageBuffer);
messageBuilder.Append(messageChunk);
messageBuffer = new byte[messageBuffer.Length];
} while (!namedPipeServer.IsMessageComplete);
if (messageRecieved != null)
{
messageRecieved(JsonConvert.DeserializeObject<string>(messageBuilder.ToString()));
}
}
catch (Exception exception)
{
Console.WriteLine($"Exception:{exception}");
}
}
}
}
}
Client code:
namespace Client
{
class Program
{
static void Main(string[] args)
{
var namedPipeClientStream = new NamedPipeClientStream(".", "server", PipeDirection.InOut, PipeOptions.Asynchronous,
TokenImpersonationLevel.Impersonation);
Task.Run(() => StartListeningAsync(namedPipeClientStream, (msg) => Console.WriteLine(msg)));
Task.Run(() => SendMessageAsync(namedPipeClientStream));
Console.ReadLine();
}
public static async Task SendMessageAsync(NamedPipeClientStream namedPipeClient)
{
using (var stream = new StreamWriter(namedPipeClient))
{
while (true)
{
try
{
await Task.Delay(3000);
var serialized = JsonConvert.SerializeObject($"Client {DateTime.Now}");
byte[] messageBytes = Encoding.UTF8.GetBytes(serialized);
if (!namedPipeClient.IsConnected)
{
namedPipeClient.Connect();
namedPipeClient.ReadMode = PipeTransmissionMode.Message;
Console.WriteLine("Client connected");
}
await namedPipeClient.WriteAsync(messageBytes, 0, messageBytes.Length);
await namedPipeClient.FlushAsync();
namedPipeClient.WaitForPipeDrain();
}
catch (Exception exception)
{
Console.WriteLine($"Exception:{exception}");
}
}
}
}
public static async Task StartListeningAsync(NamedPipeClientStream namedPipeClient, Action<string> messageRecieved)
{
using (var streamReader = new StreamReader(namedPipeClient))
{
while (true)
{
try
{
StringBuilder messageBuilder = new StringBuilder();
string messageChunk = string.Empty;
byte[] messageBuffer = new byte[1024];
do
{
if (!namedPipeClient.IsConnected)
{
namedPipeClient.Connect();
namedPipeClient.ReadMode = PipeTransmissionMode.Message;
}
await namedPipeClient.ReadAsync(messageBuffer, 0, messageBuffer.Length);
messageChunk = Encoding.UTF8.GetString(messageBuffer);
messageBuilder.Append(messageChunk);
messageBuffer = new byte[messageBuffer.Length];
} while (!namedPipeClient.IsMessageComplete);
if (messageRecieved != null)
{
messageRecieved(JsonConvert.DeserializeObject<string>(messageBuilder.ToString()));
}
}
catch (Exception exception)
{
Console.WriteLine($"Exception:{exception}");
}
}
}
}
}
}

Related

How can I set listener for clientwebsocket in c#?

ClientWebSocket socket = new ClientWebSocket();
socket.ConnectAsync(new Uri(socketURL), CancellationToken.None);
I have created ClientWebSocket using given code above in c#.
Now I want to listen to the data received through this socket.
How can I set listener for that?
Use await Task.WhenAll(Receive(socket ), Send(socket )); and define the followings:
static async Task Send(ClientWebSocket webSocket);
static async Task Receive(ClientWebSocket webSocket);
Example from github:paulbatum/WebSocket-Samples
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Client
{
class Client
{
private static object consoleLock = new object();
private const int sendChunkSize = 256;
private const int receiveChunkSize = 64;
private const bool verbose = true;
private static readonly TimeSpan delay = TimeSpan.FromMilliseconds(1000);
static void Main(string[] args)
{
Thread.Sleep(1000);
Connect("ws://localhost/wsDemo").Wait();
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
public static async Task Connect(string uri)
{
ClientWebSocket webSocket = null;
try
{
webSocket = new ClientWebSocket();
await webSocket.ConnectAsync(new Uri(uri), CancellationToken.None);
await Task.WhenAll(Receive(webSocket), Send(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();
}
}
}
private static async Task Send(ClientWebSocket webSocket)
{
var random = new Random();
byte[] buffer = new byte[sendChunkSize];
while (webSocket.State == WebSocketState.Open)
{
random.NextBytes(buffer);
await webSocket.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Binary, false, CancellationToken.None);
LogStatus(false, buffer, buffer.Length);
await Task.Delay(delay);
}
}
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
{
LogStatus(true, buffer, result.Count);
}
}
}
private static void LogStatus(bool receiving, byte[] buffer, int length)
{
lock (consoleLock)
{
Console.ForegroundColor = receiving ? ConsoleColor.Green : ConsoleColor.Gray;
Console.WriteLine("{0} {1} bytes... ", receiving ? "Received" : "Sent", length);
if (verbose)
Console.WriteLine(BitConverter.ToString(buffer, 0, length));
Console.ResetColor();
}
}
}
}

TcpClient asyncreceive is blocking

I created a tcp server and a tcp client. I tried to run the client async but had some problems.
Now when I call the function with await ReceiveAsync(id) the whole program gets blocked. I have to start the function in a new task Task.Run(() => ReceiveAsync()), then it works fine.
Now, I thought when I use the async version of readlineasync I can call the function with await ReceiveAsync() and everything works without blocking. How can I implement the function correct to receive continuous data from the server, without blocking the program and without creating a new task?
Server
main.cs
namespace Server
{
class Program
{
static void Main(string[] args)
{
// Start the server
TcpHelper.StartServer(5678);
TcpHelper.Listen(); // Start listening.
}
}
}
TcpHelper.cs
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace Server
{
public class TcpHelper
{
private static TcpListener listener { get; set; }
private static bool accept { get; set; } = false;
public static void StartServer(int port)
{
IPAddress address = IPAddress.Parse("127.0.0.1");
listener = new TcpListener(address, port);
listener.Start();
accept = true;
Console.WriteLine($"Server started. Listening to TCP clients at 127.0.0.1:{port}");
}
public static void Listen()
{
if (listener != null && accept)
{
// Continue listening.
while (true)
{
Console.WriteLine("Waiting for client...");
var clientTask = listener.AcceptTcpClientAsync(); // Get the client
if (clientTask.Result != null)
{
Console.WriteLine("Client connected. Waiting for data.");
var client = clientTask.Result;
string message = "";
while (message != null && !message.StartsWith("quit"))
{
//for (int i = 0; i < 100; i++)
//{
// byte[] data = Encoding.ASCII.GetBytes("Send next data: [enter 'quit' to terminate] ");
// client.GetStream().Write(data, 0, data.Length);
// Thread.Sleep(4000);
//}
byte[] data = Encoding.ASCII.GetBytes("Send next data: [enter 'quit' to terminate] \n");
client.GetStream().Write(data, 0, data.Length);
byte[] buffer = new byte[1024];
client.GetStream().Read(buffer, 0, buffer.Length);
message = Encoding.ASCII.GetString(buffer);
Console.WriteLine(message);
}
Console.WriteLine("Closing connection.");
client.GetStream().Dispose();
}
}
}
}
}
}
Client
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
namespace TestTcpSocket
{
class Program
{
static void Main(string[] args)
{
MainAsync().Wait();
}
static async Task MainAsync()
{
TcpClient client = Connect(IPAddress.Parse("127.0.0.1"), 5678).Result;
//await ReceiveAsync(client); // Blocks the whole program
Task.Run(() => ReceiveAsync(client)); // Works
string line;
while ((line = Console.ReadLine()) != null)
{
await SendAsync(client, line);
}
}
private static async Task<TcpClient> Connect(IPAddress address, int port)
{
TcpClient client = new TcpClient();
await client.ConnectAsync(address, port);
return client;
}
private static async Task SendAsync(TcpClient client, string message)
{
NetworkStream networkStream = client.GetStream();
StreamWriter writer = new StreamWriter(networkStream);
StreamReader reader = new StreamReader(networkStream);
writer.AutoFlush = true;
await writer.WriteLineAsync(message);
}
private static async Task ReceiveAsync(TcpClient client)
{
NetworkStream networkStream = client.GetStream();
StreamWriter writer = new StreamWriter(networkStream);
StreamReader reader = new StreamReader(networkStream);
writer.AutoFlush = true;
while (true)
{
string response = await reader.ReadLineAsync();
}
}
}
}

How I can get the AspNetWebSocketContext from the current context?

I am implementing ASP.net websocket server using Microsoft webscoket. I have a function which sends data to the client. Below is the class.
public class MyWebSocketHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
if (context.IsWebSocketRequest)
{
context.AcceptWebSocketRequest(DoTalking);
}
}
public bool IsReusable
{
get
{
return false;
}
}
public async Task DoTalking(AspNetWebSocketContext context)
{
WebSocket socket = context.WebSocket;
while (true)
{
ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[1024]);
WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
if (socket.State == WebSocketState.Open)
{
string userMessage = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);
userMessage = "Message from client : " + userMessage;
}
else
{
break;
}
}
}
public async Task SendToClient(AspNetWebSocketContext context)
{
WebSocket socket = context.WebSocket;
//WebSocket socket = context.WebSocket;
ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[1024]);
buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(message));
await socket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
}
public void callSendToClient()
{
var task = SendToClient(Problem is here!);
task.Wait();
}
private string message { get; set; }
}
}
My problem is how to get the AspNetWebSocketContext when I call the SendToClient method ? I am stuck at this point. Actually I want to call SendToClient() method from another .aspx page. Need some help.

TCP/IP multiple clients connection in C#

I wrote client and server apps, there are those codes:
Client:
using System.Net.Sockets;
using System.Net;
using System.IO;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace Client
{
class Program
{
private static TcpClient client = new TcpClient();
private static StreamReader reader;
private static StreamWriter writer;
private static bool refresh;
private static List<string> messages = new List<string>();
public static void Main()
{
Console.Title = "Client";
do //try to connect
{
Console.WriteLine("Connecting to server...");
try
{
client.Connect(IPAddress.Parse("127.0.0.1"), 8080);
}
catch (SocketException) { }
Thread.Sleep(10);
} while (!client.Connected);
// \/ CONNECTED \/
Console.WriteLine("Connected.");
reader = new StreamReader(client.GetStream());
writer = new StreamWriter(client.GetStream());
var sendTask = Task.Run(() => SendMessage()); //task for sending messages
var recieveTask = Task.Run(() => RecieveMessage()); //task for recieving messages
var updateConvTask = Task.Run(() => UpdateConversation()); //task for update console window
Task.WaitAll(sendTask, recieveTask); //wait for end of all tasks
}
private static void SendMessage()
{
string msgToSend = string.Empty;
do
{
Console.WriteLine("Enter a message to send to the server");
msgToSend = Console.ReadLine();
writer.WriteLine(msgToSend);
writer.Flush();
} while (!msgToSend.Equals("Exit"));
EndConnection();
}
private static void RecieveMessage()
{
try
{
while (client.Connected)
{
//Console.Clear();
string msg = reader.ReadLine();
if(msg != string.Empty)
{
if (msg == "%C") //special message from server, clear messages if recieve it
{
messages.Clear();
}
else
{
messages.Add(msg);
refresh = true; //refresh console window
}
}
//Console.Clear();
//Console.WriteLine(msgFromServer);
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
private static void UpdateConversation()
{
//string conversationTmp = string.Empty;
try
{
while (true)
{
if (refresh) //only if refresh
{
refresh = false;
Console.Clear();
messages.ForEach(msg => Console.WriteLine(msg)); //write all messages
Console.WriteLine();
}
}
}
catch (Exception) { }
}
private static void EndConnection()
{
reader.Close();
writer.Close();
client.Close();
}
}
}
Server:
using System;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Server
{
class Program
{
private static List<Client> clients = new List<Client>();
private static TcpListener listener = null;
private static StreamReader reader = null;
private static StreamWriter writer = null;
private static List<Task> clientTasks = new List<Task>();
private static List<string> messages = new List<string>();
public static void Main()
{
Console.Title = "Server";
try
{
listener = new TcpListener(IPAddress.Parse("127.0.0.1"), 8080);
listener.Start();
Console.WriteLine("Server started...");
var connectTask = Task.Run(() => ConnectClients());
//var listenTask = Task.Run(() => ListenClients());
Task.WaitAll(connectTask);
}
catch (Exception e)
{
Console.WriteLine(e);
}
finally
{
if (listener != null)
{
listener.Stop();
}
}
}
private static void ConnectClients()
{
Console.WriteLine("Waiting for incoming client connections...");
while (true)
{
if (listener.Pending()) //if someone want to connect
{
clients.Add(new Client(listener.AcceptTcpClient(), "Client: " + (clients.Count + 1)));
Console.WriteLine(clients[clients.Count - 1].clientName + " connected to server.");
clientTasks.Add(Task.Run(() => HandleClient(clients[clients.Count - 1]))); //start new task for new client
}
}
}
private static void HandleClient(Client TCPClient)
{
string s = string.Empty;
writer = new StreamWriter(TCPClient.client.GetStream());
reader = new StreamReader(TCPClient.client.GetStream());
try
{
while (!(s = reader.ReadLine()).Equals("Exit") || (s == null))
{
if(!TCPClient.client.Connected)
{
Console.WriteLine("Client disconnected.");
clients.Remove(TCPClient);
}
Console.WriteLine("From client: " + TCPClient.clientName + " -> " + s);
messages.Add(TCPClient.clientName + ": " + s); //save new message
//Console.WriteLine(s);
foreach (Client c in clients) //refresh all connected clients
{
c.writer.WriteLine("%C"); //clear client
foreach (string msg in messages)
{
c.writer.WriteLine(msg);
c.writer.Flush();
}
}
}
CloseServer();
}
catch (Exception e) { Console.WriteLine(e); }
}
private static void CloseServer()
{
reader.Close();
writer.Close();
clients.ForEach(tcpClient => tcpClient.client.Close());
}
}
}
Client class code:
class Client
{
public TcpClient client;
public StreamWriter writer; //write to client
public string clientName;
public Client(TcpClient client, string clientName)
{
this.client = client;
reader = new StreamReader(client.GetStream());
writer = new StreamWriter(client.GetStream());
this.clientName = clientName;
}
}
Clients send messages to the server that store all of them and next send back the entire conversation to all clients.
Client class contains information about the connected client, a server has a list of Client instances.
For one client it works well, but when I have two clients, in begin it works too, but after a few messages one client send messages to them two, and another client can't send messages.
Please help, I'm new in TCP communication.
I think that you would synchronize Tasks: https://www.google.pl/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=synchronizing+tasks+c%23

Xamarin ClientWebSocket... Can't re-connect after connection lost

I am developing Android app using ClientWebSocket.
When I start the app, everything works correctly if the server is running.
After I stop the server, the client can't be re-connected to the server and can't receive messages. I noticed that the status of clientwebsocket remains "Open" after I stop the server!
If I start the app then start the server, the client can't connect!
This is the code:
string ip = "192.168.1.142";
int port = 9000;
private const int ReceiveChunkSize = 1024;
private const int SendChunkSize = 1024;
private ClientWebSocket _ws;
private readonly Uri _uri;
private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
private readonly CancellationToken _cancellationToken;
Preparing the client:
_ws = new ClientWebSocket ();
_ws.Options.KeepAliveInterval = TimeSpan.FromSeconds (20);
_uri = new Uri ("ws://"+ip+":"+port);
_cancellationToken = _cancellationTokenSource.Token;
Connection Method:
public async void ConnectAsync()
{
await Task.Run (() => {
try {
var tk = _ws.ConnectAsync (_uri, _cancellationTokenSource.Token);
tk.Wait(4000);
if (tk.IsCompleted) {
//CallOnConnected ();
StartListen ();
}
}
catch
{
}
});
}
Listen for income messages:
private async void StartListen()
{
var buffer = new byte[ReceiveChunkSize];
try
{
while (_ws.State == WebSocketState.Open)
{
var stringResult = new StringBuilder();
WebSocketReceiveResult result;
do
{
result = await _ws.ReceiveAsync(new ArraySegment<byte>(buffer), _cancellationToken);
if (result.MessageType == WebSocketMessageType.Close)
{
await
_ws.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
//CallOnDisconnected();
}
else
{
var str = Encoding.UTF8.GetString(buffer, 0, result.Count);
stringResult.Append(str);
}
} while (!result.EndOfMessage);
//CallOnMessage(stringResult);
}
}
catch (Exception)
{
//CallOnDisconnected();
}
finally
{
_ws.Dispose();
}
}
In the MainActivity, I use a timer for re-connect:
void Try_Connect(){
if ((my_clientwebsocket.Connection_Status == System.Net.WebSockets.WebSocketState.Open)|(my_clientwebsocket.Connection_Status == System.Net.WebSockets.WebSocketState.Connecting)) {
return;
}
new Thread (new ThreadStart (delegate {
RunOnUiThread (() => {
try {
my_clientwebsocket.ConnectAsync();
} catch {
}
});
})).Start ();
}
What is the wrong?!
Thanks for help

Categories