The example shown on the following page doesn't work:
Using c# ClientWebSocket with streams
It hangs on the following line:
await ws.ConnectAsync(serverUri, CancellationToken.None);
It appears the connection is not made.
Please indicate the simplest modification to make the following code work. I do not wish to use any 3rd party tools or libraries.
private static async Task DoClientWebSocket()
{
using (ClientWebSocket ws = new ClientWebSocket())
{
Uri serverUri = new Uri("wss://echo.websocket.org/");
await ws.ConnectAsync(serverUri, CancellationToken.None);
while (ws.State == WebSocketState.Open)
{
string msg = "hello123";
ArraySegment<byte> bytesToSend = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msg));
await ws.SendAsync(bytesToSend, WebSocketMessageType.Text, true, CancellationToken.None);
ArraySegment<byte> bytesReceived = new ArraySegment<byte>(new byte[1024]);
WebSocketReceiveResult result = await ws.ReceiveAsync(bytesReceived, CancellationToken.None);
Console.WriteLine(Encoding.UTF8.GetString(bytesReceived.Array, 0, result.Count));
}
}
}
You are correct. You don't need to add any header in order to use wss://echo.websocket.org/. Your code run just fine at my end. But I'll suggest one improvement to include timeout for your ConnectAsync, SendAsync and ReceiveAsync calls so that it do not get stuck for long.
I have restricted code to call SendAsync to just 5 times so that its easier to verify output.
[Edited:] Include logic to receive complete response by calling `ReceiveAsync multiple times.
private static async Task DoClientWebSocket()
{
using (ClientWebSocket ws = new ClientWebSocket())
{
Uri serverUri = new Uri("wss://echo.websocket.org/");
//Implementation of timeout of 5000 ms
var source = new CancellationTokenSource();
source.CancelAfter(5000);
await ws.ConnectAsync(serverUri, source.Token);
var iterationNo = 0;
// restricted to 5 iteration only
while (ws.State == WebSocketState.Open && iterationNo++ < 5)
{
string msg = "hello0123456789123456789123456789123456789123456789123456789";
ArraySegment<byte> bytesToSend =
new ArraySegment<byte>(Encoding.UTF8.GetBytes(msg));
await ws.SendAsync(bytesToSend, WebSocketMessageType.Text,
true, source.Token);
//Receive buffer
var receiveBuffer = new byte[200];
//Multipacket response
var offset = 0;
var dataPerPacket = 10; //Just for example
while (true)
{
ArraySegment<byte> bytesReceived =
new ArraySegment<byte>(receiveBuffer, offset, dataPerPacket);
WebSocketReceiveResult result = await ws.ReceiveAsync(bytesReceived,
source.Token);
//Partial data received
Console.WriteLine("Data:{0}",
Encoding.UTF8.GetString(receiveBuffer, offset,
result.Count));
offset += result.Count;
if (result.EndOfMessage)
break;
}
Console.WriteLine("Complete response: {0}",
Encoding.UTF8.GetString(receiveBuffer, 0,
offset));
}
}
}
static void Main(string[] args)
{
var taskWebConnect = Task.Run(() => DoClientWebSocket());
taskWebConnect.Wait();
}
Output on command prompt:
Data:hello01234
Data:5678912345
Data:6789123456
Data:7891234567
Data:8912345678
Data:9123456789
Complete response: hello0123456789123456789123456789123456789123456789123456789
Related
I need WebSocket code for implement structure of my client. I will create WebSocket server for my client with receive by client from ex: binance websocket
Just part of connect to binance websocket need implement.
ASP.NET Core 5 C#
private async Task Echo(HttpContext context, WebSocket webSocket)
{
var buffer = new byte[1024 * 4];
WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
while (!result.CloseStatus.HasValue)
{
await webSocket.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None);
result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
}
await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
}
I did something like that. I created 2 WebSocket servers, one acting as a proxy to the other. You can check it out, maybe it works for you or at least you can find some answers there. It is a bit disordered because I did it as a research, so ask me if you need more info.
https://github.com/RenanDiaz/WebSockets
public override async Task OnConnected(WebSocket socket)
{
await base.OnConnected(socket);
if (_client == null)
{
_client = new ClientWebSocket();
await _client.ConnectAsync(new Uri("ws://localhost:5001/chat"), CancellationToken.None);
var thread = new Thread(new ThreadStart(ReceiveMessageFromAPIServer));
thread.Start();
}
}
private async void ReceiveMessageFromAPIServer()
{
var buffer = new byte[1024 * 4];
while (_client != null)
{
var result = await _client.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
if (result.MessageType == WebSocketMessageType.Close)
{
await _client.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);
break;
}
var messageString = Encoding.UTF8.GetString(buffer, 0, result.Count);
var message = JsonConvert.DeserializeObject<IncomingAPIServerMessage>(messageString);
await SendMessageToAll(message);
}
}
I am receiving JSON through a websocket. At least: I am partially. Using an online websocket service I receive the full JSON response (all the HTML markup is ignored). When I look at the JSON that I receive in my console I can see the HTML markup (viewing it with the HTML viewer during debugging removes the HTML) but it ends abruptly (incomplete data).
My buffer has plenty of space and I am using async-await to (supposedly) wait for the entire response to come in before continuing.
private async Task Receive()
{
var buffer = new byte[4096 * 20];
while (_socket.State == WebSocketState.Open)
{
var response = await _socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
if (response.MessageType == WebSocketMessageType.Close)
{
await
_socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Close response received",
CancellationToken.None);
}
else
{
var result = Encoding.UTF8.GetString(buffer);
var a = buffer[1000];
var b = buffer[10000];
var c = buffer[50000];
var d = buffer[81000];
Console.WriteLine(result);
var responseObject = JsonConvert.DeserializeObject<Response>(result, _requestParameters.ResponseDataType);
OnSocketReceive.Invoke(this, new SocketEventArgs {Response = responseObject });
buffer = new byte[4096 * 20];
}
}
}
Things to note: The buffer is perfectly big enough and b, c and d are never filled. I should also note that this only happens for the 1-questions-newest-tag-java request, 155-questions-active works perfectly fine.
After doing some digging I have found that response.CloseStatus and response.CloseStatusDescription are always null, response.Count is always 1396 (copy-pasting the result in Word does show that there are always 1396 characters) and response.EndOfMessage is false.
Digging through some source code I have found that the DefaultReceiveBufferSize is 16 * 1024 (big enough) and the WebSocketGetDefaultKeepAliveInterval() refers to an external implementation (but the debugger shows 00:00:30).
It is not a matter of timeout since the debugger halts at the same moment the online service receives its response.
Why is my method continuing to execute when the socket has not yet received all data?
Just to complete #Noseratio response, the code would be something like this:
ArraySegment<Byte> buffer = new ArraySegment<byte>(new Byte[8192]);
WebSocketReceiveResult result= null;
using (var ms = new MemoryStream())
{
do
{
result = await socket.ReceiveAsync(buffer, CancellationToken.None);
ms.Write(buffer.Array, buffer.Offset, result.Count);
}
while (!result.EndOfMessage);
ms.Seek(0, SeekOrigin.Begin);
if (result.MessageType == WebSocketMessageType.Text)
{
using (var reader = new StreamReader(ms, Encoding.UTF8))
{
// do stuff
}
}
}
Cheers.
I might be wrong, but I don't think you're always supposed to receive a complete WebSocket message at once. The server may be sending the message in chunks (that'd correspond to calling SendAsync with endOfMessage: false).
So, do await _socket.ReceiveAsync() in a loop and accumulate the received chunks, until WebSocketReceiveResult.EndOfMessage is true or an error has occured.
On a side note, you probably should be using WebSocket.CreateClientBuffer instead of new ArraySegment<byte>(buffer).
// Read the bytes from the web socket and accumulate all into a list.
var buffer = new ArraySegment<byte>(new byte[1024]);
WebSocketReceiveResult result = null;
var allBytes = new List<byte>();
do
{
result = await webSocket.ReceiveAsync(buffer, CancellationToken.None);
for (int i = 0; i < result.Count; i++)
{
allBytes.Add(buffer.Array[i]);
}
}
while (!result.EndOfMessage);
// Optional step to convert to a string (UTF-8 encoding).
var text = Encoding.UTF8.GetString(allBytes.ToArray(), 0, allBytes.Count);
Following Noseratio's answer I have implemented a temporary buffer that will construct the data of the entire message.
var temporaryBuffer = new byte[BufferSize];
var buffer = new byte[BufferSize * 20];
int offset = 0;
WebSocketReceiveResult response;
while (true)
{
response = await _socket.ReceiveAsync(
new ArraySegment<byte>(temporaryBuffer),
CancellationToken.None);
temporaryBuffer.CopyTo(buffer, offset);
offset += response.Count;
temporaryBuffer = new byte[BufferSize];
if (response.EndOfMessage)
{
break;
}
}
Full implementation here
Try this:
try
{
WebSocketReceiveResult result;
string receivedMessage = "";
var message = new ArraySegment<byte>(new byte[4096]);
do
{
result = await WebSocket.ReceiveAsync(message, DisconectToken);
if (result.MessageType != WebSocketMessageType.Text)
break;
var messageBytes = message.Skip(message.Offset).Take(result.Count).ToArray();
receivedMessage += Encoding.UTF8.GetString(messageBytes);
}
while (!result.EndOfMessage);
if (receivedMessage != "{}" && !string.IsNullOrEmpty(receivedMessage))
{
ResolveWebSocketResponse.Invoke(receivedMessage, Connection);
Console.WriteLine("Received: {0}", receivedMessage);
}
}
catch (Exception ex)
{
var mes = ex.Message;
}
I want to get data from this wss://ws-feed.gdax.com
I don't know anything about websocket. I am reading some tutorials and it uses terms like websocket server, TCP, etc which I have no idea about. Can anyone please advice how should I proceed, how to write a c# code to get data from the above.
This is the document which I reading to fetch real time data - https://docs.gdax.com/#websocket-feed
Started by creating a window app. Read here that the WebSocketSharp library can be used to connect WebSockets so installed it and so far written this code:
using (var ws = new WebSocket("wss://ws-feed.gdax.com"))
{
ws.Connect();
string json = "{\"type\": \"subscribe\", \"product_ids\": [\"BTC-USD\"]}";
ws.Send(json); //gives error -Function evaluation disabled because a previous function evaluation timed out. You must continue execution to reenable function evaluation.
}
Any help would be much appreciated.
ClientWebSocket socket = new ClientWebSocket();
Task task = socket.ConnectAsync(new Uri("wss://ws-feed.gdax.com"), CancellationToken.None);
task.Wait();
Thread readThread = new Thread(
delegate(object obj)
{
byte[] recBytes = new byte[1024];
while (true) {
ArraySegment<byte> t = new ArraySegment<byte>(recBytes);
Task<WebSocketReceiveResult> receiveAsync = socket.ReceiveAsync(t, CancellationToken.None);
receiveAsync.Wait();
string jsonString = Encoding.UTF8.GetString(recBytes);
Console.Out.WriteLine("jsonString = {0}", jsonString);
recBytes = new byte[1024];
}
});
readThread.Start();
string json = "{\"product_ids\":[\"btc-usd\"],\"type\":\"subscribe\"}";
byte[] bytes = Encoding.UTF8.GetBytes(json);
ArraySegment<byte> subscriptionMessageBuffer = new ArraySegment<byte>(bytes);
socket.SendAsync(subscriptionMessageBuffer, WebSocketMessageType.Text, true, CancellationToken.None);
Console.ReadLine();
Basically, what you do is in the right direction. Just check websocket state before you read the message.
The below example is from https://github.com/sefbkn/gdax.netcore, with little modification
var webSocketClient = new ClientWebSocket();
var cancellationToken = new CancellationToken();
await webSocketClient.ConnectAsync(new Uri("wss://ws-feed.gdax.com"), cancellationToken).ConfigureAwait(false);
if (webSocketClient.State == WebSocketState.Open)
{
var requestString = JsonConvert.SerializeObject(new {
type = "subscribe",
product_ids = new[]{"ETH-EUR"},
channels = new[]{"ticker"}
});
var requestBytes = UTF8Encoding.UTF8.GetBytes(requestString);
var subscribeRequest = new ArraySegment<byte>(requestBytes);
var sendCancellationToken = new CancellationToken();
await webSocketClient.SendAsync(subscribeRequest, WebSocketMessageType.Text, true, sendCancellationToken).ConfigureAwait(false);
while (webSocketClient.State == WebSocketState.Open)
{
var receiveCancellationToken = new CancellationToken();
using(var stream = new MemoryStream(1024))
{
var receiveBuffer = new ArraySegment<byte>(new byte[1024*8]);
WebSocketReceiveResult webSocketReceiveResult;
do
{
webSocketReceiveResult = await webSocketClient.ReceiveAsync(receiveBuffer, receiveCancellationToken).ConfigureAwait(false);
await stream.WriteAsync(receiveBuffer.Array, receiveBuffer.Offset, receiveBuffer.Count);
} while(!webSocketReceiveResult.EndOfMessage);
var message = stream.ToArray().Where(b => b != 0).ToArray();
messageReceived(Encoding.ASCII.GetString(message, 0, message.Length));
}
}
}
I'm sending 10 messages from a client to a server in a loop, and then responses back from the server to the client using TPL's FromAsync (targeting .NET 4.0)
After the last message is sent from the client, I'm trying to measure the total time taken until the final response is received. To do this, I call Task.WaitAll but I get an AggregateException who's inner exception says "A task was cancelled" for all the tasks. The server is receiving the requests.
Code:
private static double MeasureAsyncTPL(List<string> stringList)
{
var stopwatch = new Stopwatch();
stopwatch.Start();
var tasks = new Task[stringList.Count];
for (int i = 0; i < stringList.Count; i++)
{
string source = stringList[i];
tasks[i] = SendMessageToServerAsync(source);
//SendMessageToServerAsync(source);
}
Task.WaitAll(tasks);
stopwatch.Stop();
return stopwatch.Elapsed.TotalMilliseconds;
}
static Task SendMessageToServerAsync(string message)
{
Task task;
var byteArray = MessageToByteArray(message, Encoding.UTF8);
using (var tcpClient = new TcpClient())
{
tcpClient.Connect("127.0.0.1", 5000);
using (var networkStream = tcpClient.GetStream())
{
task = Write(networkStream,byteArray,0);
Task continuation = task.ContinueWith(ant => Read(ant, networkStream), TaskContinuationOptions.NotOnFaulted | TaskContinuationOptions.AttachedToParent);
return continuation;
}
}
}
private static Task Write(NetworkStream stream, byte[] buffer, int offset)
{
return Task.Factory.FromAsync(stream.BeginWrite, stream.EndWrite, buffer, offset, buffer.Length, null);
}
private static Task Read(Task write, NetworkStream stream)
{
byte[] data = new byte[50];
return Task<int>.Factory.FromAsync(stream.BeginRead, stream.EndRead, data, 0, data.Length, null);
}
The exception is being picked up inside MeasureAsyncTPL on the line Task.WaitAll(tasks). How can I fix this exception?
Second question - is FromAsync inside my Read method guaranteed to return the entire message from the server? Or do I need to call it multiple times while keeping track of a the size of the byte array that the server sent?
You are disposing of the networkStream and tcpClient before the write and read operations start or have time to work.
With .NET 4.0, you need to do something as complex as this (this is something to start with, it needs more work):
var byteArray = MessageToByteArray(message, Encoding.UTF8);
var tcpClient = new TcpClient();
NetworkStream networkStream = null;
try
{
tcpClient.Connect("127.0.0.1", 5000);
networkStream = tcpClient.GetStream();
}
catch
{
((IDisposable)tcpClient).Dispose();
throw;
}
byte[] read_buffer = new byte[50];
Action dispose_action = () =>
{
((IDisposable)tcpClient).Dispose();
networkStream.Dispose();
};
var write_task = networkStream.WriteAsync(byteArray, 0, byteArray.Length);
write_task
.ContinueWith(wt =>
{
var read_task = networkStream.ReadAsync(read_buffer, 0, read_buffer.Length);
read_task.ContinueWith(rt =>
{
//See if rt task is successful and if so, process read data here
dispose_action();
});
},
TaskContinuationOptions.OnlyOnRanToCompletion);
write_task.ContinueWith(wt => dispose_action, TaskContinuationOptions.NotOnRanToCompletion);
The main idea of the code above is that you don't dispose of the TCP client and the network stream object until the read/write operations are done.
Imagine how complex this code would become if you want to read multiple times in some kind of loop.
With .NET 4.5, you can use async and await to do something (simpler) like this:
static async Task SendMessageToServerAsync(string message)
{
var byteArray = MessageToByteArray(message, Encoding.UTF8);
using (var tcpClient = new TcpClient())
{
tcpClient.Connect("127.0.0.1", 5000);
using (var networkStream = tcpClient.GetStream())
{
await networkStream.WriteAsync(byteArray, 0, byteArray.Length);
byte[] read_buffer = new byte[50];
int read = await networkStream.ReadAsync(read_buffer, 0, read_buffer.Length);
// do something with the read_buffer
}
}
}
I am receiving JSON through a websocket. At least: I am partially. Using an online websocket service I receive the full JSON response (all the HTML markup is ignored). When I look at the JSON that I receive in my console I can see the HTML markup (viewing it with the HTML viewer during debugging removes the HTML) but it ends abruptly (incomplete data).
My buffer has plenty of space and I am using async-await to (supposedly) wait for the entire response to come in before continuing.
private async Task Receive()
{
var buffer = new byte[4096 * 20];
while (_socket.State == WebSocketState.Open)
{
var response = await _socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
if (response.MessageType == WebSocketMessageType.Close)
{
await
_socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Close response received",
CancellationToken.None);
}
else
{
var result = Encoding.UTF8.GetString(buffer);
var a = buffer[1000];
var b = buffer[10000];
var c = buffer[50000];
var d = buffer[81000];
Console.WriteLine(result);
var responseObject = JsonConvert.DeserializeObject<Response>(result, _requestParameters.ResponseDataType);
OnSocketReceive.Invoke(this, new SocketEventArgs {Response = responseObject });
buffer = new byte[4096 * 20];
}
}
}
Things to note: The buffer is perfectly big enough and b, c and d are never filled. I should also note that this only happens for the 1-questions-newest-tag-java request, 155-questions-active works perfectly fine.
After doing some digging I have found that response.CloseStatus and response.CloseStatusDescription are always null, response.Count is always 1396 (copy-pasting the result in Word does show that there are always 1396 characters) and response.EndOfMessage is false.
Digging through some source code I have found that the DefaultReceiveBufferSize is 16 * 1024 (big enough) and the WebSocketGetDefaultKeepAliveInterval() refers to an external implementation (but the debugger shows 00:00:30).
It is not a matter of timeout since the debugger halts at the same moment the online service receives its response.
Why is my method continuing to execute when the socket has not yet received all data?
Just to complete #Noseratio response, the code would be something like this:
ArraySegment<Byte> buffer = new ArraySegment<byte>(new Byte[8192]);
WebSocketReceiveResult result= null;
using (var ms = new MemoryStream())
{
do
{
result = await socket.ReceiveAsync(buffer, CancellationToken.None);
ms.Write(buffer.Array, buffer.Offset, result.Count);
}
while (!result.EndOfMessage);
ms.Seek(0, SeekOrigin.Begin);
if (result.MessageType == WebSocketMessageType.Text)
{
using (var reader = new StreamReader(ms, Encoding.UTF8))
{
// do stuff
}
}
}
Cheers.
I might be wrong, but I don't think you're always supposed to receive a complete WebSocket message at once. The server may be sending the message in chunks (that'd correspond to calling SendAsync with endOfMessage: false).
So, do await _socket.ReceiveAsync() in a loop and accumulate the received chunks, until WebSocketReceiveResult.EndOfMessage is true or an error has occured.
On a side note, you probably should be using WebSocket.CreateClientBuffer instead of new ArraySegment<byte>(buffer).
// Read the bytes from the web socket and accumulate all into a list.
var buffer = new ArraySegment<byte>(new byte[1024]);
WebSocketReceiveResult result = null;
var allBytes = new List<byte>();
do
{
result = await webSocket.ReceiveAsync(buffer, CancellationToken.None);
for (int i = 0; i < result.Count; i++)
{
allBytes.Add(buffer.Array[i]);
}
}
while (!result.EndOfMessage);
// Optional step to convert to a string (UTF-8 encoding).
var text = Encoding.UTF8.GetString(allBytes.ToArray(), 0, allBytes.Count);
Following Noseratio's answer I have implemented a temporary buffer that will construct the data of the entire message.
var temporaryBuffer = new byte[BufferSize];
var buffer = new byte[BufferSize * 20];
int offset = 0;
WebSocketReceiveResult response;
while (true)
{
response = await _socket.ReceiveAsync(
new ArraySegment<byte>(temporaryBuffer),
CancellationToken.None);
temporaryBuffer.CopyTo(buffer, offset);
offset += response.Count;
temporaryBuffer = new byte[BufferSize];
if (response.EndOfMessage)
{
break;
}
}
Full implementation here
Try this:
try
{
WebSocketReceiveResult result;
string receivedMessage = "";
var message = new ArraySegment<byte>(new byte[4096]);
do
{
result = await WebSocket.ReceiveAsync(message, DisconectToken);
if (result.MessageType != WebSocketMessageType.Text)
break;
var messageBytes = message.Skip(message.Offset).Take(result.Count).ToArray();
receivedMessage += Encoding.UTF8.GetString(messageBytes);
}
while (!result.EndOfMessage);
if (receivedMessage != "{}" && !string.IsNullOrEmpty(receivedMessage))
{
ResolveWebSocketResponse.Invoke(receivedMessage, Connection);
Console.WriteLine("Received: {0}", receivedMessage);
}
}
catch (Exception ex)
{
var mes = ex.Message;
}