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);
}
}
Related
I wrote a program for the fire department to receive data from the control center.
When receiving status data, it works perfectly. But now when we would have received the first alarm via this WebSocket interface, the following error occurred:
System.Net.WebSockets.WebSocketException (0x80004005): The remote party closed the WebSocket connection without completing the close handshake.
at System.Net.WebSockets.ManagedWebSocket.ThrowIfEOFUnexpected(Boolean throwOnPrematureClosure)
at System.Net.WebSockets.ManagedWebSocket.EnsureBufferContainsAsync(Int32 minimumRequiredBytes, CancellationToken cancellationToken, Boolean throwOnPrematureClosure)
at System.Net.WebSockets.ManagedWebSocket.ReceiveAsyncPrivate[TWebSocketReceiveResultGetter,TWebSocketReceiveResult](Memory`1 payloadBuffer, CancellationToken cancellationToken, TWebSocketReceiveResultGetter resultGetter)
at FF.Service.Services.XYZService.GetDataAsync(Boolean isRetrying) in C:\Users\XXX\source\repos\FF.Service\FF.Service\Services\XYZService.cs:line 108
But I don't find the error in my code:
using (ClientWebSocket socket = new ClientWebSocket())
{
// set login tokens as request headers
socket.Options.SetRequestHeader("master_token", masterToken);
socket.Options.SetRequestHeader("sub_token", subToken);
// read certificate string from file and prepare for certificate creation
string certificateContent = File.ReadAllText(Path.Combine(Program.AssemblyDirectory, "ff-cloud.pem"))
.Trim()
.Replace("-----BEGIN CERTIFICATE-----", null)
.Replace("-----END CERTIFICATE-----", null);
// create certificate and add to web socket options
X509Certificate2 cert = new X509Certificate2(Convert.FromBase64String(certificateContent));
socket.Options.ClientCertificates.Add(cert);
// ignore certificate errors
socket.Options.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true;
// set buffer and buffer size
int bufferSize = 8192;
byte[] buffer = new byte[bufferSize];
// connect the web socket to the remote server
await socket.ConnectAsync(new Uri(fullServerAddress), CancellationToken.None);
// work while connection is open
while (socket.State == System.Net.WebSockets.WebSocketState.Open)
{
State = WebSocketState.Open;
WebSocketReceiveResult receiveResult;
MemoryStream outputStream = new MemoryStream(bufferSize);
do
{
// receive data
// IN THE NEXT LINE OCCURS THE ERROR!!!!
receiveResult = await socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
if (receiveResult.MessageType != WebSocketMessageType.Close)
outputStream.Write(buffer, 0, receiveResult.Count);
}
// read while end of message isn't reached
while (!receiveResult.EndOfMessage);
// set the output stream position to 0 - to read from the beginning
outputStream.Position = 0;
// read the message
StreamReader streamReader = new StreamReader(outputStream);
string message = streamReader.ReadToEnd();
LogService.GetInstance().Log(message, LogService.LogTypes.AllData);
// check if the message is alarm data
if (message.Contains("alarm_data"))
{
try
{
// deserialize received data to alarm data
FF.AlarmData.Rootobject rootobject =
JsonSerializer.Deserialize<FF.AlarmData.Rootobject>(message);
LogService.GetInstance().Log("Successfully received alarm data!", LogService.LogTypes.Success);
// fire the alarm received event
if (AlarmReceived != null)
AlarmReceived(this, new AlarmEventArgs(rootobject));
}
catch (Exception ex)
{
LogService.GetInstance().Log($"Error at receiveing alarm data! ({ex.Message})", LogService.LogTypes.Error);
}
}
// check if the message is a radio status
else if (message.Contains("radio_status"))
{
try
{
// deserialize received data to radio status
FF.StatusData.Rootobject rootobject =
JsonSerializer.Deserialize<FF.StatusData.Rootobject>(message);
LogService.GetInstance().Log("Successfully received status data!", LogService.LogTypes.Success);
// fire the status received event
if (StatusReceived != null)
StatusReceived(this, new StatusEventArgs(rootobject));
}
catch (Exception ex)
{
LogService.GetInstance().Log($"Error at receiveing status data! ({ex.Message})", LogService.LogTypes.Error);
}
}
// break the loop if the received message is a close message
if (receiveResult.MessageType == WebSocketMessageType.Close)
break;
}
LogService.GetInstance().Log("Connection lost!", LogService.LogTypes.Warning);
try
{
LogService.GetInstance().Log("Try to close connection!", LogService.LogTypes.Information);
// close web socket connection
await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, null, CancellationToken.None);
}
catch (Exception ex)
{
LogService.GetInstance().Log($"Error on closing connection: {ex.ToString()}", LogService.LogTypes.Warning);
}
}
The error occurs int the line unter the comment "IN THE NEXT LINE OCCURS THE ERROR!!!!". Unfortunatelly there is no way to receive alarm data only for testing.
Does someone know what I'm doing wrong?
Thank you in forward for your answers
Regards Matthias
I am trying to create a bot which that listen to an WebSocket URL with C# and ASP.Net Core 2.2.
But I’m new in WebSocket area.
I read Microsoft documentation about WebSocket and ClientWebSocket to solve my problem. but there are not help to me.
How my app can listen to an external WebSocket URL and react to incoming messages ?
I tried below code but get "Cannot create an instance of the abstract class or interface 'WebSocket'." error.
using (var ws = new WebSocket("wss://ws.example.com"))
{
ws.OnMessage += (sender, e) =>
Console.WriteLine("Message received" + e.Data);
ws.OnError += (sender, e) =>
Console.WriteLine("Error: " + e.Message);
ws.Connect();
Console.ReadKey(true);
}
This should do it in the base case scenario.
public class Listener
{
public void StopListening()
{
this.src.Cancel();
}
private Task listenTask;
private CancellationTokenSource src=new CancellationTokenSource();
public Task Listen(string url)
{
listenTask = Task.Run(async () =>
{
try
{
byte[] buffer = new byte[1024];
await socket.ConnectAsync(new Uri(url), CancellationToken.None);
while (true)
{
WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
string data = Encoding.UTF8.GetString(buffer, 0, result.Count);
Console.WriteLine(data);
}
}
catch (Exception ex)
{
//treat exception
}
},src.Token);
}
}
However if you plan to create multiple Listener objects ( in the context of a HttpController that on a route opens sockets ) then things change.
For quite a lot of time I struggled with finding a working solution to connect an android device and an UWP application (on PC) with either an IP connection or bluetooth. The main issue is to find a set of code or example which is simple enough to get into but is guaranteed to work (so that my efforts are not futile, which was the case for more than a week now).
What is clear is that there is no possibility for a "code pair" (as of client-server), as the libraries used and the way the code structures are built must be vastly different. A further problem is that bluetooth does not seem to allow loopback connections, which causes even more issues with testing. Another issue is possibly outdated example projects. Also it's hard to find xamarin/c# solutions, and I didn't want to get into Android Studio and Java (my project is the UWP one, the android part is just for testing). These are simply too many layers of difficulties to get into for me.
The goal for now (and thus also my question asking for help) is a basic operation:
Send a plain message or datastream from Xamarin-Android (as client) to UWP (as server) and have a response for receiving it - via bluetooth.
Let's ignore device searching now (if possible), let's just use IP/MAC address directly. From there on everything should fall into place. All necessary capabilities/declarations are set and devices are paired.
I would be really grateful for any help.
I found out the solution myself, so here is how it went:
First of all, remember to define all necessary declarations and capabilities for bluetooth. This will explicitly focus on the code part.
For the Xamarin/Android client part. The website which was really helpful is this one. Also try out the quite well known chat sample for Xamarin. CreateMessage is a method to create debug messages on the local device which can be displayed. I kept it very simple, because my project is primarily about the UWP part. All of this was enclosed in a try { } catch { } clause, but I leave it out now due to having even more indentations and brackets.
using Java.Util;
using System.Text;
using System.IO;
using Android.Runtime;
using System.Threading.Tasks;
TestClass
{
// The UUIDs will be displayed down below if not known.
const string TARGET_UUID = "00001105-0000-1000-8000-00805f9b34fb";
BluetoothSocket socket = null;
OutputStreamInvoker outStream = null;
InputStreamInvoker inStream = null;
void Connect ()
{
BluetoothAdapter adapter = BluetoothAdapter.DefaultAdapter;
if (adapter == null) CreateMessage ("No Bluetooth adapter found.");
else if (!adapter.IsEnabled) CreateMessage ("Bluetooth adapter is not enabled.");
List<BluetoothDevice> L = new List<BluetoothDevice> ();
foreach (BluetoothDevice d in adapter.BondedDevices)
{
CreateMessage ("D: " + d.Name + " " + d.Address + " " + d.BondState.ToString ());
L.Add (d);
}
BluetoothDevice device = null;
device = L.Find (j => j.Name == "PC-NAME");
if (device == null) CreateMessage ("Named device not found.");
else
{
CreateMessage ("Device has been found: " + device.Name + " " + device.Address + " " + device.BondState.ToString ());
}
socket = device.CreateRfcommSocketToServiceRecord (UUID.FromString (TARGET_UUID));
await socket.ConnectAsync ();
if (socket != null && socket.IsConnected) CreateMessage ("Connection successful!");
else CreateMessage ("Connection failed!");
inStream = (InputStreamInvoker) socket.InputStream;
outStream = (OutputStreamInvoker) socket.OutputStream;
if (socket != null && socket.IsConnected)
{
Task t = new Task (() => Listen (inStream));
t.Start ();
}
else throw new Exception ("Socket not existing or not connected.");
}
}
Now we enter the part with the bytes and pain. I used this format to transmit messages: [4 bytes of uint for message length] [1 byte per character]. What is important is that you use the same byte to uint conversion, because the order of bytes or how it went in general had differences in the UWP specific methods. If your word length is not what it is supposed to be (instead of ~23 something like 3000000+), that is a problem. Reading bytes which do not exist (yet) can mean exceptions or even merciless crashes despite using try { } catch { } clauses.
The following method sends the message in the format mentioned above. As said, it is among the most simple ways to do this, so I won't mention how things can be done better.
private async void SendMessage (string message)
{
uint messageLength = (uint) message.Length;
byte[] countBuffer = BitConverter.GetBytes (messageLength);
byte[] buffer = Encoding.UTF8.GetBytes (message);
await outStream.WriteAsync (countBuffer, 0, countBuffer.Length);
await outStream.WriteAsync (buffer, 0, buffer.Length);
}
Usage: Run method 1, and then method 2. You can also do a SendMessage within method 1 at the end (when it is already connected).
Now to the part about listening for messages/responses. In the first method you will see this one was run via a Task, so that it does not block the method it is started it. Maybe there are Xamarin/Android specific ways to solve that, but it does not matter to me, so I simply circumvented that.
private async void Listen (Stream inStream)
{
bool Listening = true;
CreateMessage ("Listening has been started.");
byte[] uintBuffer = new byte[sizeof (uint)]; // This reads the first 4 bytes which form an uint that indicates the length of the string message.
byte[] textBuffer; // This will contain the string message.
// Keep listening to the InputStream while connected.
while (Listening)
{
try
{
// This one blocks until it gets 4 bytes.
await inStream.ReadAsync (uintBuffer, 0, uintBuffer.Length);
uint readLength = BitConverter.ToUInt32 (uintBuffer, 0);
textBuffer = new byte[readLength];
// Here we know for how many bytes we are looking for.
await inStream.ReadAsync (textBuffer, 0, (int) readLength);
string s = Encoding.UTF8.GetString (textBuffer);
CreateMessage ("Received: " + s);
}
catch (Java.IO.IOException e)
{
CreateMessage ("Error: " + e.Message);
Listening = false;
break;
}
}
CreateMessage ("Listening has ended.");
}
This was only half the work. For the UWP server part, I will simply post my current code, which is way more clean and requires no editing for this.
using System;
using System.Text;
using System.Threading.Tasks;
using Windows.Devices.Bluetooth.Rfcomm;
using Windows.Networking.Sockets;
using Windows.Storage.Streams;
namespace BT
{
public sealed class BluetoothConnectionHandler
{
RfcommServiceProvider provider;
bool isAdvertising = false;
StreamSocket socket;
StreamSocketListener socketListener;
DataWriter writer;
DataReader reader;
Task listeningTask;
public bool Listening { get; private set; }
// I use Actions for transmitting the output and debug output. These are custom classes I created to pack them more conveniently and to be able to just "Trigger" them without checking anything. Replace this with regular Actions and use their invoke methods.
public ActionSingle<string> MessageOutput { get; private set; } = new ActionSingle<string> ();
public ActionSingle<string> LogOutput { get; private set; } = new ActionSingle<string> ();
// These were in the samples.
const uint SERVICE_VERSION_ATTRIBUTE_ID = 0x0300;
const byte SERVICE_VERSION_ATTRIBUTE_TYPE = 0x0a; // UINT32
const uint SERVICE_VERSION = 200;
const bool DO_RESPONSE = true;
public async void StartServer ()
{
// Initialize the provider for the hosted RFCOMM service.
provider = await RfcommServiceProvider.CreateAsync (RfcommServiceId.ObexObjectPush);
// Create a listener for this service and start listening.
socketListener = new StreamSocketListener ();
socketListener.ConnectionReceived += OnConnectionReceived;
await socketListener.BindServiceNameAsync (provider.ServiceId.AsString (), SocketProtectionLevel.BluetoothEncryptionAllowNullAuthentication);
// Set the SDP attributes and start advertising.
InitializeServiceSdpAttributes (provider);
provider.StartAdvertising (socketListener);
isAdvertising = true;
}
public void Disconnect ()
{
Listening = false;
if (provider != null) { if (isAdvertising) provider.StopAdvertising (); provider = null; } // StopAdvertising relentlessly causes a crash if not advertising.
if (socketListener != null) { socketListener.Dispose (); socketListener = null; }
if (writer != null) { writer.DetachStream (); writer.Dispose (); writer = null; }
if (reader != null) { reader.DetachStream (); reader.Dispose (); reader = null; }
if (socket != null) { socket.Dispose (); socket = null; }
if (listeningTask != null) { listeningTask = null; }
}
public async void SendMessage (string message)
{
// There's no need to send a zero length message.
if (string.IsNullOrEmpty (message)) return;
// Make sure that the connection is still up and there is a message to send.
if (socket == null || writer == null) { LogOutput.Trigger ("Cannot send message: No clients connected."); return; } // "No clients connected, please wait for a client to connect before attempting to send a message."
uint messageLength = (uint) message.Length;
byte[] countBuffer = BitConverter.GetBytes (messageLength);
byte[] buffer = Encoding.UTF8.GetBytes (message);
LogOutput.Trigger ("Sending: " + message);
writer.WriteBytes (countBuffer);
writer.WriteBytes (buffer);
await writer.StoreAsync ();
}
private void InitializeServiceSdpAttributes (RfcommServiceProvider provider)
{
DataWriter w = new DataWriter ();
// First write the attribute type.
w.WriteByte (SERVICE_VERSION_ATTRIBUTE_TYPE);
// Then write the data.
w.WriteUInt32 (SERVICE_VERSION);
IBuffer data = w.DetachBuffer ();
provider.SdpRawAttributes.Add (SERVICE_VERSION_ATTRIBUTE_ID, data);
}
private void OnConnectionReceived (StreamSocketListener listener, StreamSocketListenerConnectionReceivedEventArgs args)
{
provider.StopAdvertising ();
isAdvertising = false;
provider = null;
listener.Dispose ();
socket = args.Socket;
writer = new DataWriter (socket.OutputStream);
reader = new DataReader (socket.InputStream);
writer.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;
reader.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;
//StartListening ();
LogOutput.Trigger ("Connection established.");
listeningTask = new Task (() => StartListening ());
listeningTask.Start ();
// Notify connection received.
}
private async void StartListening ()
{
LogOutput.Trigger ("Starting to listen for input.");
Listening = true;
while (Listening)
{
try
{
// Based on the protocol we've defined, the first uint is the size of the message. [UInt (4)] + [Message (1*n)] - The UInt describes the length of the message.
uint readLength = await reader.LoadAsync (sizeof (uint));
// Check if the size of the data is expected (otherwise the remote has already terminated the connection).
if (!Listening) break;
if (readLength < sizeof (uint))
{
Listening = false;
Disconnect ();
LogOutput.Trigger ("The connection has been terminated.");
break;
}
uint messageLength = reader.RReadUint (); //
LogOutput.Trigger ("messageLength: " + messageLength.ToString ());
// Load the rest of the message since you already know the length of the data expected.
readLength = await reader.LoadAsync (messageLength);
// Check if the size of the data is expected (otherwise the remote has already terminated the connection).
if (!Listening) break;
if (readLength < messageLength)
{
Listening = false;
Disconnect ();
LogOutput.Trigger ("The connection has been terminated.");
break;
}
string message = reader.ReadString (messageLength);
MessageOutput.Trigger ("Received message: " + message);
if (DO_RESPONSE) SendMessage ("abcdefghij");
}
catch (Exception e)
{
// If this is an unknown status it means that the error is fatal and retry will likely fail.
if (SocketError.GetStatus (e.HResult) == SocketErrorStatus.Unknown)
{
Listening = false;
Disconnect ();
LogOutput.Trigger ("Fatal unknown error occurred.");
break;
}
}
}
LogOutput.Trigger ("Stopped to listen for input.");
}
}
}
Usage is the following:
Create an instance of BluetoothConnectionHandler.
Set up the MessageOutput and/or LogOutput (read the comment in the code regarding this).
Run its StartServer method.
To send a message, use its SendMessage method.
The extension method for the RReadUint:
public static uint RReadUint (this DataReader reader)
{
uint a = 0;
byte[] x = new byte[sizeof (uint)];
reader.ReadBytes (x);
a = BitConverter.ToUInt32 (x, 0);
return a;
}
This should contain everything needed to do what I asked for... in hintsight I see there was no simple answer possible. From here on everything can get improved, as it is meant as the possibly most basic way to have bluetooth communication between UWP and Xamarin/Android.
In case you have questions about this, feel free to ask in the comment sections.
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()
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.