How to Fix the async request and response to a websocket - c#

The following is the piece of code that i am using to communicate with a websocket.
The webscoket uses a XML type of protocol for communication.
I am trying to send a series of request and waiting to receive a reponse.
Here is the following code:
static void Main(string[] args)
{
Thread.Sleep(1000);
Uri myUri = new Uri("ws://127.0.0.1:4848", UriKind.Absolute);
Connect(myUri).Wait();
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
public static async Task Connect(Uri uri)
{
ClientWebSocket webSocket = null;
try
{
webSocket = new ClientWebSocket();
await webSocket.ConnectAsync(uri, CancellationToken.None);
byte[] buffer;
byte[] receiveBuffer = new byte[receiveChunkSize];
string[] requestStrings =
{
"request1",
"request2",
"request3"
};
foreach (var request in requestStrings)
{
buffer = encoder.GetBytes(request);
Task sendRequest = Send(webSocket, buffer);
await sendRequest;
Task receiveResponse = Receive(webSocket);
await receiveResponse;
}
}
catch (Exception ex)
{
Console.WriteLine("Exception: {0}", ex);
}
}
static UTF8Encoding encoder = new UTF8Encoding();
private static async Task Send(ClientWebSocket webSocket, byte[] buffer)
{
await webSocket.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
LogStatus(false, buffer, buffer.Length);
}
private static async Task Receive(ClientWebSocket webSocket)
{
byte[] buffer = new byte[receiveChunkSize];
var result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
LogStatus(true, buffer, result.Count);
}
private static void LogStatus(bool receiving, byte[] buffer, int length)
{
lock (consoleLock)
{
Console.ForegroundColor = receiving ? ConsoleColor.Green : ConsoleColor.Gray;
if (verbose)
Console.WriteLine(encoder.GetString(buffer));
Console.ResetColor();
}
}
}
I am not getting any reponses from the websocket. I am not sure of what i am doing wrrong here. The output looks like the following:
Output:
request1
request2
request3

Related

ReceiveAsync not receiving websocket messages in C#

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 ?

C# No argument given that corresponds to the required formal parameter 'stream' of 'Receiver(NetworkStream) Error CS7036

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

Azure app service websocket buffer buffer size limits?

I have run into a problem where my websocket connection is functioning as expected locally, but not when deployed to azure app service. (.NET Core 3.0)
I am able to receive messages of any size locally, but the messages cap out at 4088 byte when deploying to azure.
Code example:
await Receive(socket, async (result, buffer) =>
{
Console.WriteLine("Message size: " + result.Count);
message = Encoding.UTF8.GetString(buffer, 0, result.Count);
});
private async Task Receive(WebSocket socket, Action<WebSocketReceiveResult, byte[]> handleMessage)
{
try
{
var buffer = new byte[1024 * 16];
while (socket.State == WebSocketState.Open)
{
WebSocketReceiveResult result = null;
using (var cts = new CancellationTokenSource(1200000))
{
result = await socket.ReceiveAsync(
buffer: new ArraySegment<byte>(buffer),
cancellationToken: cts.Token
);
}
handleMessage(result, buffer);
}
}
catch (Exception ex)
{
Log.Error(ex, "Exception occured when receiving message async");
}
}
Is there any kind of limit that can be changed in the app service?
I have already tried to set up a remote client sending messages both to azure app service and my local environment. This is only an issue with azure app service.
Fixed with:
private async Task Receive(WebSocket webSocket, Action<string> handleMessage)
{
try
{
while (webSocket.State == WebSocketState.Open)
{
var compoundBuffer = new List<byte>();
WebSocketReceiveResult messageReceiveResult = null;
byte[] buffer = new byte[4 * 1024];
do
{
using (var cts = new CancellationTokenSource(1200000))
{
messageReceiveResult = await webSocket.ReceiveAsync(
new ArraySegment<byte>(buffer),
cts.Token
);
}
if (messageReceiveResult.MessageType == WebSocketMessageType.Text)
{
byte[] readBytes = new byte[messageReceiveResult.Count];
Array.Copy(buffer, readBytes, messageReceiveResult.Count);
compoundBuffer.AddRange(readBytes);
}
} while (!messageReceiveResult.EndOfMessage);
string message = Encoding.UTF8.GetString(compoundBuffer.ToArray());
handleMessage(message);
}
}
catch (Exception ex)
{
Log.Error(ex, "Exception occured when receiving message async");
}
}

I have a problem getting response on websocket

I use the websocket API for speech recognition.
I send audio to the server and receive a response.
With this websocket API, it is possible to obtain voice recognition results while streaming voice data.
I can get the final recognition result, but I can not get the recognition result on the way.
The following shows the referenced code.
https://gist.github.com/arjun-g/75961830d363cc9265e4ac2ca095168b
After various trials, I found that line:85 was a problem.
This part seems to be waiting for the final result.
I may not have received the result on the way at all.
Please tell me why I can't get result on the way.
private async Task Connect(ClientWebSocket clientWebSocket)
{
CancellationTokenSource cts = new CancellationTokenSource();
clientWebSocket.Options.SetRequestHeader("Authorization", $"Bearer {this.accessToken}");
Uri connection = new Uri($"wss://hogehoge");
await clientWebSocket.ConnectAsync(connection, cts.Token);
}
The above is the part of the connect method.
Here is my whole code.
private async Task Connect(ClientWebSocket clientWebSocket)
{
CancellationTokenSource cts = new CancellationTokenSource();
clientWebSocket.Options.SetRequestHeader("Authorization", $"Bearer {this.accessToken}");
Uri connection = new Uri($"wss://hogehoge");
await clientWebSocket.ConnectAsync(connection, cts.Token);
}
static async Task SendAudio(ClientWebSocket ws)
{
ArraySegment<byte> closingMessage = new ArraySegment<byte>(Encoding.UTF8.GetBytes(
"{\"command\": \"recog-break\"}"
));
using (FileStream fs = File.OpenRead("audio.raw"))
{
byte[] b = new byte[3200];
while (fs.Read(b, 0, b.Length) > 0)
{
await ws.SendAsync(new ArraySegment<byte>(b), WebSocketMessageType.Binary, true, CancellationToken.None);
}
await ws.SendAsync(closingMessage, WebSocketMessageType.Text, true, CancellationToken.None);
}
}
// prints results until the connection closes or a delimeterMessage is recieved
private async Task HandleResults(ClientWebSocket ws)
{
var buffer = new byte[60000];
while (true)
{
var segment = new ArraySegment<byte>(buffer);
var result = await ws.ReceiveAsync(segment, CancellationToken.None);
if (result.MessageType == WebSocketMessageType.Close)
{
return;
}
int count = result.Count;
while (!result.EndOfMessage)
{
if (count >= buffer.Length)
{
await ws.CloseOutputAsync(WebSocketCloseStatus.InvalidPayloadData, "That's too long", CancellationToken.None);
return;
}
segment = new ArraySegment<byte>(buffer, count, buffer.Length - count);
result = await ws.ReceiveAsync(segment, CancellationToken.None);
count += result.Count;
}
var message = Encoding.UTF8.GetString(buffer, 0, count);
this.textBox2.AppendText(message);
}
}
private async void button1_Click_1(object sender, EventArgs e)
{
ClientWebSocket cws = new ClientWebSocket();
await this.Connect(cws);
await Task.WhenAll(SendAudio(cws), HandleResults(cws));
}

Can TCP server start communication with client

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.

Categories