StreamSocket, DataWriter.StoreAsync(), DataReader.LoadAsync() -- Asynchronous problems - c#

I'm creating a Win 8 store app in which I connect to a server, written in Java, using StreamSocket. When I run the app in debug, with breakpoints on StreamSocket.ConnectAsync(...), DataWriter.StoreAsync(), and DataReader.LoadAsync(...), it connects, sends the message, and receives a message back. However, once I remove any one of my breakpoints, that method doesn't do it's job. How can I can fix this issue? Here is my code:
public async void Connect()
{
try
{
await socket.ConnectAsync(new Windows.Networking.HostName(ip),
"50000", SocketProtectionLevel.PlainSocket);
Connected = true;
}
catch (Exception e)
{
if (SocketError.GetStatus(e.HResult) == SocketErrorStatus.Unknown)
{
throw;
}
Windows.UI.Popups.MessageDialog md =
new Windows.UI.Popups.MessageDialog("Error: " + e.Message);
return;
}
return;
}
public async void HandShake()
{
try
{
//output
writer = new DataWriter(socket.OutputStream);
writer.UnicodeEncoding =
Windows.Storage.Streams.UnicodeEncoding.Utf8;
byte[] nameBytes = Encoding.UTF8.GetBytes(Name.ToCharArray());
writer.WriteBytes(nameBytes);
await writer.StoreAsync();
await writer.FlushAsync();
writer.DetachStream();
writer.Dispose();
//input
reader = new DataReader(socket.InputStream);
reader.InputStreamOptions = InputStreamOptions.Partial;
reader.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;
uint bytesAvailable = await reader.LoadAsync(4096);
byte[] byArray = new byte[bytesAvailable];
reader.ReadBytes(byArray);
string temp = Encoding.UTF8.GetString(byArray, 0,
Convert.ToInt32(bytesAvailable));
temp = temp.Substring(0, temp.Length - 1);
if (temp == "NAME OK")
{
GoodName = true;
}
reader.DetachStream();
reader.Dispose();
}
catch (Exception e)
{
//await Task.WhenAll(tasks.ToArray());
if (SocketError.GetStatus(e.HResult) == SocketErrorStatus.Unknown)
{
throw;
}
Windows.UI.Popups.MessageDialog md =
new Windows.UI.Popups.MessageDialog("Error: " + e.Message);
md.ShowAsync();
}
}

LoadAsync by default will not block until all the requested bytes have been read. You are probably receiving a partial message.
You'll need to implement whatever kind of message framing your protocol uses, as I describe on my blog.
P.S. Avoid async void. It really complicates your error handling.

I changed the return type of Connect() to Task. Then called it as such, await Connect(); I put send and receive code in separate methods and did the same. My issue was an asynchronous problem and this fixed it.

Related

StreamSocketListener Recive Multiple Messages

This is my code, can you help me to change the code so that I can recive multiple messages? At the moment I can just recive one question then the client must reconnect.
I hope you can help me.
public string PortNumber = "1337";
public MainPage()
{
this.InitializeComponent();
StartServer();
}
private async void StartServer()
{
try
{
var streamSocketListener = new Windows.Networking.Sockets.StreamSocketListener();
// The ConnectionReceived event is raised when connections are received.
streamSocketListener.ConnectionReceived += this.StreamSocketListener_ConnectionReceived;
// Start listening for incoming TCP connections on the specified port. You can specify any port that's not currently in use.
await streamSocketListener.BindServiceNameAsync(this.PortNumber);
this.serverListBox.Items.Add("server is listening...");
}
catch (Exception ex)
{
Windows.Networking.Sockets.SocketErrorStatus webErrorStatus = Windows.Networking.Sockets.SocketError.GetStatus(ex.GetBaseException().HResult);
this.serverListBox.Items.Add(webErrorStatus.ToString() != "Unknown" ? webErrorStatus.ToString() : ex.Message);
}
}
private async void StreamSocketListener_ConnectionReceived(Windows.Networking.Sockets.StreamSocketListener sender, Windows.Networking.Sockets.StreamSocketListenerConnectionReceivedEventArgs args)
{
string request;
using (var streamReader = new StreamReader(args.Socket.InputStream.AsStreamForRead()))
{
request = await streamReader.ReadLineAsync();
}
await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => this.TB1.Text=(string.Format("server received the request: \"{0}\"", request)));
// Echo the request back as the response.
using (Stream outputStream = args.Socket.OutputStream.AsStreamForWrite())
{
using (var streamWriter = new StreamWriter(outputStream))
{
await streamWriter.WriteLineAsync(request);
await streamWriter.FlushAsync();
}
}
}
You should always listen the upcoming message in the StreamSocketListener.ConnectionReceived Event, this event will only trigger when a connection was received on the StreamSocketListener object. If you want to always receive the sent data, you should always read it in the StreamSocketListener.ConnectionReceived Event.
Here is the sample code in the official StreamSocket:
In the Scenario1_Start.xaml.cs, the OnConnection is same as your StreamSocketListener_ConnectionReceived method. You can also learn more from the official sample.
private async void OnConnection(
StreamSocketListener sender,
StreamSocketListenerConnectionReceivedEventArgs args)
{
DataReader reader = new DataReader(args.Socket.InputStream);
try
{
while (true)
{
// Read first 4 bytes (length of the subsequent string).
uint sizeFieldCount = await reader.LoadAsync(sizeof(uint));
if (sizeFieldCount != sizeof(uint))
{
// The underlying socket was closed before we were able to read the whole data.
return;
}
// Read the string.
uint stringLength = reader.ReadUInt32();
uint actualStringLength = await reader.LoadAsync(stringLength);
if (stringLength != actualStringLength)
{
// The underlying socket was closed before we were able to read the whole data.
return;
}
// Display the string on the screen. The event is invoked on a non-UI thread, so we need to marshal
// the text back to the UI thread.
NotifyUserFromAsyncThread(
String.Format("Received data: \"{0}\"", reader.ReadString(actualStringLength)),
NotifyType.StatusMessage);
}
}
catch (Exception exception)
{
// If this is an unknown status it means that the error is fatal and retry will likely fail.
if (SocketError.GetStatus(exception.HResult) == SocketErrorStatus.Unknown)
{
throw;
}
NotifyUserFromAsyncThread(
"Read stream failed with error: " + exception.Message,
NotifyType.ErrorMessage);
}
}

C# WebSocket.SendAsync() randomly gets stuck

I have used the following code to send using the System.Net.WebSocket from WPF after socket has connected
try
{
Console.WriteLine("Sending...");
await _ws.SendAsync(new ArraySegment<byte>(packet.GetBytes()), WebSocketMessageType.Binary, true, CancellationToken.None);
Console.WriteLine("Sent...");
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
Calling code
if (!ValidateSettings()) return;
var hostname = TbHostname.Text.Trim();
var tcpport = TbTcpPort.Text.Trim();
_ws = new AchiWebSocket();
_streamTimer = new System.Threading.Timer(async s =>
{
var socket = (AchiWebSocket)s;
if (!_semaWs.Wait(0)) return;
UpdateBuffer();
var buffer = GetFrameBuffer();
var packet = new BinaryPacket(buffer.GetBytes());
if(socket.WebSocketState == null || socket.WebSocketState == WebSocketState.Closed)
await socket.Connect(new Uri("ws://" + hostname + "/superrfb"));
try
{
await socket.SendAsync(packet);
}
catch(Exception e)
{
Console.WriteLine("--" + e.Message);
}
finally
{
_semaWs.Release();
}
}, _ws, 0, 70);
Receiving Code (Asp.Net Core)
public async Task StartReceiveAsync(Action<Packet> onReceive)
{
WebSocketReceiveResult result;
var buffer = new byte[4 * 1024];
var stream = new MemoryStream();
do
{
result = await _ws.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
await stream.WriteAsync(buffer, 0, result.Count);
if (result.EndOfMessage)
{
var packet = BinaryPacket.FromRaw(stream.ToArray());
onReceive.Invoke(packet);
}
}
while (!result.CloseStatus.HasValue);
Dispose();
}
I do receive some data but the socket gets stuck in SendAsync after a few packets. It doesn't return even after waiting several minutes.
Ok I figured it out. My onReceive.Invoke() function was throwing exception sometimes causing the server to stop receiving. This made the receive buffer fill up and WebSocket.SendAsync to stuck and wait until the buffer is free. After wrapping the onReceive.Invoke() in try catch, the code is working fine now.
try
{
onReceive.Invoke(packet);
}
catch(Exception e)
{
Debug.WriteLine(e.Message);
}

c# NetworkStream disposed over tcp/ip

I'm hoping someone can tell me why I'm getting an object disposed exception in my tcpListener/tcpClient code.
In the acceptConnections and connectToServer methods I use the keepalive method to tell me when I get disconnected and it works fine.
However, if I uncomment the for loop for my sendMsg method I will get an ObjectDisposedException on the server and an IOException on the client.
The tcpClient.getStream()'s NetworkStream in SendMsg seems to be the issue but I am unsure why it would get a disposed stream. Do I need 2 threads to work with it?
static void Main(string[] args)
{
server.Listen();
server.AcceptConnections();
client.ConnectToServer();
//for (int i = 0; i < 5; i++) {
// Thread.Sleep(3000);
// server.SendMsg("SENT MSG");
//}
Console.ReadLine();
}
public async void SendMsg(String message) {
try {
NetworkStream networkStream = tcpClient.GetStream();
using (var writer = new StreamWriter(networkStream)) {
await writer.WriteLineAsync(message);
Console.WriteLine("msg sent");
};
} catch (Exception e) {
}
}
private async void KeepAlive(TcpClient tcpClient) {
bool clientConnected = true;
using (NetworkStream networkStream = tcpClient.GetStream())
using (var reader = new StreamReader(networkStream))
using (var writer = new StreamWriter(networkStream)) {
writer.AutoFlush = true;
char keepalive = '0';
while (clientConnected) {
try {
await writer.WriteLineAsync(keepalive);
string dataFromClient = await reader.ReadLineAsync();
Console.WriteLine("Server: " + dataFromClient);
Thread.Sleep(500);
} catch (IOException e){
} catch(ObjectDisposedException e) {
clientConnected = false;
clientsConnected--;
} catch (Exception e){
}
}
}
}
EDIT: posting my AcceptConnections method as well
public async void AcceptConnections() {
while (true) {
while (clientsConnected <= maxConnections) {
try {
tcpClient = await tcpListener.AcceptTcpClientAsync();
KeepAlive(tcpClient);
} catch (Exception e) {
Console.WriteLine("TOP EXCEPTION :: " + e);
}
clientsConnected++;
Console.WriteLine("SERVER Clients connected: " + clientsConnected);
}
}
}
Your SendMsg method uses using on a StreamWriter. The default for a StreamWriter is to cascade the dispose, so this will close the NetworkStream. If that isn't your intent, you need to pass leaveOpen: true to the constructor overload.
Frankly though, there's no reason to use StreamWriter here - I would suggest dealing with the Stream and Encoding APIs directly. One advantage of StreamWriter is that internally it might re-use a buffer for the byte[] work, but that "advantage" is moot if you're only using it for one Write before disposing it, and can be readily achieved with a buffer pool.

How to gracefully close a two-way WebSocket in .Net

I have a WebSocket server that accepts a stream of binary data from a client and responds with another stream of text data for every 4MB read. The server uses IIS 8 and asp.net web api.
Server
public class WebSocketController : ApiController
{
public HttpResponseMessage Get()
{
if (!HttpContext.Current.IsWebSocketRequest)
{
return new HttpResponseMessage(HttpStatusCode.BadRequest);
}
HttpContext.Current.AcceptWebSocketRequest(async (context) =>
{
try
{
WebSocket socket = context.WebSocket;
byte[] requestBuffer = new byte[4194304];
int offset = 0;
while (socket.State == WebSocketState.Open)
{
var requestSegment = new ArraySegment<byte>(requestBuffer, offset, requestBuffer.Length - offset);
WebSocketReceiveResult result = await socket.ReceiveAsync(requestSegment, CancellationToken.None);
if (result.MessageType == WebSocketMessageType.Close)
{
// Send one last response before closing
var response = new ArraySegment<byte>(Encoding.UTF8.GetBytes("Server got " + offset + " bytes\n"));
await socket.SendAsync(response, WebSocketMessageType.Text, true, CancellationToken.None);
// Close
await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
break;
}
offset += result.Count;
if (offset == requestBuffer.Length)
{
// Regular response
var response = new ArraySegment<byte>(Encoding.UTF8.GetBytes("Server got 4194304 bytes\n"));
await socket.SendAsync(response, WebSocketMessageType.Text, true, CancellationToken.None);
offset = 0;
}
}
}
catch (Exception ex)
{
// Log and continue
}
});
return new HttpResponseMessage(HttpStatusCode.SwitchingProtocols);
}
}
The c# client uses the ClientWebSocket class to connect to the server and send requests. It creates a task for receiving responses from the server that runs in parallel with the request sending. When it is done sending the requests it calls CloseAsync on the socket and then waits for the Receive task to complete.
Client
using System;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace WebSocketClient
{
class Program
{
static void Main(string[] args)
{
try
{
CallWebSocketServer().Wait();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
static async Task CallWebSocketServer()
{
using (ClientWebSocket socket = new ClientWebSocket())
{
await socket.ConnectAsync(new Uri("ws://localhost/RestWebController"), CancellationToken.None);
byte[] buffer = new byte[128 * 1024];
Task receiveTask = Receive(socket);
for (int i = 0; i < 1024; ++i)
{
await socket.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Binary, true, CancellationToken.None);
}
await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
receiveTask.Wait();
Console.WriteLine("All done");
}
}
static async Task Receive(ClientWebSocket socket)
{
try
{
byte[] recvBuffer = new byte[64 * 1024];
while (socket.State == WebSocketState.Open)
{
var result = await socket.ReceiveAsync(new ArraySegment<byte>(recvBuffer), CancellationToken.None);
Console.WriteLine("Client got {0} bytes", result.Count);
Console.WriteLine(Encoding.UTF8.GetString(recvBuffer, 0, result.Count));
if (result.MessageType == WebSocketMessageType.Close)
{
Console.WriteLine("Close loop complete");
break;
}
}
}
catch (Exception ex)
{
Console.WriteLine("Exception in receive - {0}", ex.Message);
}
}
}
}
The problem is that the client blocks at the CloseAsync call.
What would be the correct way of gracefully closing the WebSocket in this scenario?
Figured this out.
Server
Basically, I had to call the ClientWebSocket.CloseOutputAsync (instead of the CloseAsync) method to tell the framework no more output is going to be sent from the client.
await socket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
Client
Then in the Receive function, I had to allow for socket state WebSocketState.CloseSent to receive the Close response from the server
static async Task Receive(ClientWebSocket socket)
{
try
{
byte[] recvBuffer = new byte[64 * 1024];
while (socket.State == WebSocketState.Open || socket.State == WebSocketState.CloseSent)
{
var result = await socket.ReceiveAsync(new ArraySegment<byte>(recvBuffer), CancellationToken.None);
Console.WriteLine("Client got {0} bytes", result.Count);
Console.WriteLine(Encoding.UTF8.GetString(recvBuffer, 0, result.Count));
if (result.MessageType == WebSocketMessageType.Close)
{
Console.WriteLine("Close loop complete");
break;
}
}
}
catch (Exception ex)
{
Console.WriteLine("Exception in receive - {0}", ex.Message);
}
}
i suggest you to look at these links:
asynchronous server:
https://msdn.microsoft.com/en-us/library/fx6588te%28v=vs.110%29.aspx
asynchronous client:
https://msdn.microsoft.com/en-us/library/bew39x2a(v=vs.110).aspx
recently i implementled something similar with these links as an example. the methods "BeginReceive" (for server) and "BeginConnect" (for client) start each a new thread. so there won't be anything that blocks

How to read and send data to client from server?

I'm trying to make a server client using a local console server on my pc and a client on windows phone 8.1. The problem that I have is that I don't know how to read the incoming data from the client. I've searched the internet and read serveral microsoft tutorials but they do not explain how to read the incoming data in the server. Here's what I have.
Client on windows phone 8.1:
private async void tryConnect()
{
if (connected)
{
StatusLabel.Text = "Already connected";
return;
}
try
{
// serverHostnameString = "127.0.0.1"
// serverPort = "1330"
StatusLabel.Text = "Trying to connect ...";
serverHost = new HostName(serverHostnameString);
// Try to connect to the
await clientSocket.ConnectAsync(serverHost, serverPort);
connected = true;
StatusLabel.Text = "Connection established" + Environment.NewLine;
}
catch (Exception exception)
{
// If this is an unknown status,
// it means that the error is fatal and retry will likely fail.
if (SocketError.GetStatus(exception.HResult) == SocketErrorStatus.Unknown)
{
throw;
}
StatusLabel.Text = "Connect failed with error: " + exception.Message;
// Could retry the connection, but for this simple example
// just close the socket.
closing = true;
// the Close method is mapped to the C# Dispose
clientSocket.Dispose();
clientSocket = null;
}
}
private async void sendData(string data)
{
if (!connected)
{
StatusLabel.Text = "Must be connected to send!";
return;
}
UInt32 len = 0; // Gets the UTF-8 string length.
try
{
StatusLabel.Text = "Trying to send data ...";
// add a newline to the text to send
string sendData = "jo";
DataWriter writer = new DataWriter(clientSocket.OutputStream);
len = writer.MeasureString(sendData); // Gets the UTF-8 string length.
// Call StoreAsync method to store the data to a backing stream
await writer.StoreAsync();
StatusLabel.Text = "Data was sent" + Environment.NewLine;
// detach the stream and close it
writer.DetachStream();
writer.Dispose();
}
catch (Exception exception)
{
// If this is an unknown status,
// it means that the error is fatal and retry will likely fail.
if (SocketError.GetStatus(exception.HResult) == SocketErrorStatus.Unknown)
{
throw;
}
StatusLabel.Text = "Send data or receive failed with error: " + exception.Message;
// Could retry the connection, but for this simple example
// just close the socket.
closing = true;
clientSocket.Dispose();
clientSocket = null;
connected = false;
}
}
(from http://msdn.microsoft.com/en-us/library/windows/apps/xaml/jj150599.aspx)
And the server:
public class Server
{
private TcpClient incomingClient;
public Server()
{
TcpListener listener = new TcpListener(IPAddress.Parse("127.0.0.1"), 1330);
listener.Start();
Console.WriteLine("Waiting for connection...");
while (true)
{
//AcceptTcpClient waits for a connection from the client
incomingClient = listener.AcceptTcpClient();
//start a new thread to handle this connection so we can go back to waiting for another client
Thread thread = new Thread(HandleClientThread);
thread.IsBackground = true;
thread.Start(incomingClient);
}
}
private void HandleClientThread(object obj)
{
TcpClient client = obj as TcpClient;
Console.WriteLine("Connection found!");
while (true)
{
//how to read and send data back?
}
}
}
It comes to the point where the server prints 'Connection found!', but I don't know how to go further.
Any help is appreciated!
EDIT:
Now my handleclientthread method looks like this:
private void HandleClientThread(object obj)
{
TcpClient client = obj as TcpClient;
netStream = client.GetStream();
byte[] rcvBuffer = new byte[500]; // Receive buffer
int bytesRcvd; // Received byte count
int totalBytesEchoed = 0;
Console.WriteLine("Connection found!");
while (true)
{
while ((bytesRcvd = netStream.Read(rcvBuffer, 0, rcvBuffer.Length)) > 0)
{
netStream.Write(rcvBuffer, 0, bytesRcvd);
totalBytesEchoed += bytesRcvd;
}
Console.WriteLine(totalBytesEchoed);
}
}
But it still doesn't write the bytes to the console
So... after a lot of searching the internet I have found a solution...
Server: to read from the server and send data back to the phone:
// method in a new thread, for each connection
private void HandleClientThread(object obj)
{
TcpClient client = obj as TcpClient;
netStream = client.GetStream();
Console.WriteLine("Connection found!");
while (true)
{
// read data
byte[] buffer = new byte[1024];
int totalRead = 0;
do
{
int read = client.GetStream().Read(buffer, totalRead, buffer.Length - totalRead);
totalRead += read;
} while (client.GetStream().DataAvailable);
string received = Encoding.ASCII.GetString(buffer, 0, totalRead);
Console.WriteLine("\nResponse from client: {0}", received);
// do some actions
byte[] bytes = Encoding.ASCII.GetBytes(received);
// send data back
client.GetStream().WriteAsync(bytes, 0, bytes.Length);
}
}
Phone(client): to send messages from the phone and read the messages from server:
private async void sendData(string dataToSend)
// import for AsBuffer(): using System.Runtime.InteropServices.WindowsRuntime;
{
if (!connected)
{
StatusLabel.Text = "Status: Must be connected to send!";
return;
}
try
{
byte[] data = GetBytes(dataToSend);
IBuffer buffer = data.AsBuffer();
StatusLabel.Text = "Status: Trying to send data ...";
await clientSocket.OutputStream.WriteAsync(buffer);
StatusLabel.Text = "Status: Data was sent" + Environment.NewLine;
}
catch (Exception exception)
{
if (SocketError.GetStatus(exception.HResult) == SocketErrorStatus.Unknown)
{
throw;
}
StatusLabel.Text = "Status: Send data or receive failed with error: " + exception.Message;
closing = true;
clientSocket.Dispose();
clientSocket = null;
connected = false;
}
readData();
}
private async void readData()
{
StatusLabel.Text = "Trying to receive data ...";
try
{
IBuffer buffer = new byte[1024].AsBuffer();
await clientSocket.InputStream.ReadAsync(buffer, buffer.Capacity, InputStreamOptions.Partial);
byte[] result = buffer.ToArray();
StatusLabel.Text = GetString(result);
}
catch (Exception exception)
{
if (SocketError.GetStatus(exception.HResult) == SocketErrorStatus.Unknown)
{
throw;
}
StatusLabel.Text = "Receive failed with error: " + exception.Message;
closing = true;
clientSocket.Dispose();
clientSocket = null;
connected = false;
}
}
The 'await clientSocket.InputStream.ReadAsync(buffer, buffer.Capacity, InputStreamOptions.Partial)' command in the readData method was very unclear for me. I didn't know you had to make a new buffer, and the ReadAsync-method fills it(as i inderstand it). Found it here: StreamSocket.InputStreamOptions.ReadAsync hangs when using Wait()

Categories

Resources