I'm currently developing an UWP app which should have capability to be as a TCP server (using ports) so client can connect to it via other device and send requests and server responds with data.
I followed the Socket example on :Microsoft site, and got sample code working (in which server and client are both in same app)
I changed IP addresses and ports so i could use apps on 2 different machines with direct connection, I also made separate simple client application, using sample code from Here
Now problem is as follows: UWP app can successfully communicate with its own client method provided by Microsoft's sample, but is unable to communicate with console client program I made and was running on other. UWP can indeed connect with client and also send data, but it cannot receive data, the function streamReader.ReadLineAsync(); will wait infinitely long and that's all.
How do i make UWP app get the message client is sending and what i might be doing wrong ?
public sealed partial class MainPage : Page
{
static string PORT_NO = "1300";
const string SERVER_IP = "192.168.0.10";
public MainPage()
{
this.InitializeComponent();
outputText.Text = "Helloo";
StartConnection(SERVER_IP, PORT_NO);
//StartClient();
}
public async void StartConnection(string net_aadress, string port_nr)
{
try
{
var streamSocketListener = new 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(port_nr);
outputText.Text = "server is listening...";
}
catch (Exception ex)
{
Windows.Networking.Sockets.SocketErrorStatus webErrorStatus = Windows.Networking.Sockets.SocketError.GetStatus(ex.GetBaseException().HResult);
outputText.Text = (webErrorStatus.ToString() != "Unknown" ? webErrorStatus.ToString() : ex.Message);
}
}
private async void StreamSocketListener_ConnectionReceived(Windows.Networking.Sockets.StreamSocketListener sender, Windows.Networking.Sockets.StreamSocketListenerConnectionReceivedEventArgs args)
{
string request = "password";
string second;
/*
using (var streamReader = new StreamReader(args.Socket.InputStream.AsStreamForRead()))
{
request = await streamReader.ReadLineAsync();
}
*/
//await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => this.serverListBox.Items.Add(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();
}
}
using (var streamReader = new StreamReader(args.Socket.InputStream.AsStreamForRead()))
{
second = await streamReader.ReadLineAsync();
}
using (Stream outputStream = args.Socket.OutputStream.AsStreamForWrite())
{
using (var streamWriter = new StreamWriter(outputStream))
{
await streamWriter.WriteLineAsync(second);
await streamWriter.FlushAsync();
}
}
//await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => this.serverListBox.Items.Add(string.Format("server sent back the response: \"{0}\"", request)));
sender.Dispose();
//await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => this.serverListBox.Items.Add("server closed its socket"));
}
private async void StartClient()
{
try
{
// Create the StreamSocket and establish a connection to the echo server.
using (var streamSocket = new Windows.Networking.Sockets.StreamSocket())
{
// The server hostname that we will be establishing a connection to. In this example, the server and client are in the same process.
var hostName = new Windows.Networking.HostName("localhost");
//this.clientListBox.Items.Add("client is trying to connect...");
await streamSocket.ConnectAsync(hostName, PORT_NO);
//this.clientListBox.Items.Add("client connected");
// Send a request to the echo server.
string request = "Hello, World!";
using (Stream outputStream = streamSocket.OutputStream.AsStreamForWrite())
{
using (var streamWriter = new StreamWriter(outputStream))
{
await streamWriter.WriteLineAsync(request);
await streamWriter.FlushAsync();
}
}
//this.clientListBox.Items.Add(string.Format("client sent the request: \"{0}\"", request));
// Read data from the echo server.
string response;
using (Stream inputStream = streamSocket.InputStream.AsStreamForRead())
{
using (StreamReader streamReader = new StreamReader(inputStream))
{
response = await streamReader.ReadLineAsync();
}
}
await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
() =>
{
outputText.Text = "Client got back " + response;
}
);
}
//this.clientListBox.Items.Add("client closed its socket");
}
catch (Exception ex)
{
Windows.Networking.Sockets.SocketErrorStatus webErrorStatus = Windows.Networking.Sockets.SocketError.GetStatus(ex.GetBaseException().HResult);
//this.clientListBox.Items.Add(webErrorStatus.ToString() != "Unknown" ? webErrorStatus.ToString() : ex.Message);
}
}
}
Here is source code for Client application:
{
class Program
{
const int PORT_NUMBER = 1300;
const string SERVER_IP = "192.168.0.10";
static void Main(string[] args)
{
string textToSend = DateTime.Now.ToString();
string password = "Madis on loll";
string receiveddata;
try
{
Console.WriteLine("Client progrm started");
TcpClient client = new TcpClient(SERVER_IP, PORT_NUMBER);
NetworkStream nwStream = client.GetStream();
//System.Threading.Thread.Sleep(500);
//see, how long is packet
byte[] bytesToRead = new byte[client.ReceiveBufferSize];
int bytesRead = nwStream.Read(bytesToRead, 0, client.ReceiveBufferSize);
Console.WriteLine("Received : " + Encoding.ASCII.GetString(bytesToRead, 0, bytesRead));
byte[] password2 = ASCIIEncoding.ASCII.GetBytes(password);
Console.WriteLine("Sending : " + password);
nwStream.Write(password2, 0, password2.Length); //sending packet
byte[] receiveddata2 = new byte[client.ReceiveBufferSize];
int receiveddatalength = nwStream.Read(receiveddata2, 0, client.ReceiveBufferSize);
Console.WriteLine("Received : " + Encoding.ASCII.GetString(receiveddata2, 0, bytesRead));
}
catch (Exception ex)
{
Console.WriteLine("Connection error");
}
}
}
}
Found answer myself: main problem is with ReadLineAsync() in Server program: it waits and collects all the stream until it gets end of line character. In this case end of line was never sent and therefore server kept waiting infinitely.
Simplest fix was on Client side by simply adding end of line at the end of packet, like this:
before:
byte[] password2 = ASCIIEncoding.ASCII.GetBytes(password);
Console.WriteLine("Sending : " + password);
nwStream.Write(password2, 0, password2.Length); //sending packet
after:
byte[] newLine = Encoding.ASCII.GetBytes(Environment.NewLine);
byte[] password2 = ASCIIEncoding.ASCII.GetBytes(password);
Console.WriteLine("Sending : " + password);
nwStream.Write(password2, 0, password2.Length); //sending packet
nwStream.Write(newLine,0,newLine.Length);
Also 1 thing worth mentioning: current StreamSocketListener_ConnectionReceived is able to send only once, then it sets outputStream.CanWrite to false.
This can be solved by removing using() from writing and reading functions, like this:
before:
PS! Manually flushing is also replaced with autoflush.
using (Stream outputStream = args.Socket.OutputStream.AsStreamForWrite())
{
using (var streamWriter = new StreamWriter(outputStream))
{
await streamWriter.WriteLineAsync(request);
await streamWriter.FlushAsync();
}
}
after:
Stream outputStream = args.Socket.OutputStream.AsStreamForWrite();
var streamWriter = new StreamWriter(outputStream);
streamWriter.AutoFlush = true;
await streamWriter.WriteLineAsync(request);
Hope it helps someone someday.
Related
Here is my code:
A listener to wait for connection from client:
static void Main(string[] args)
{
IPAddress ipAddr = IPAddress.Parse(args[1]);
TcpListener listener = new TcpListener(ipAddr, Int32.Parse(args[2]));
listener.Start();
Console.WriteLine("Waiting for a connection.");
TcpClient client = listener.AcceptTcpClient();
Console.WriteLine("Client accepted.");
while (true)
{
NetworkStream stream = client.GetStream();
StreamReader sr = new StreamReader(client.GetStream());
StreamWriter sw = new StreamWriter(client.GetStream());
try
{
if (stream.DataAvailable)
{
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 received: " + request);
if (request != null)
{
string response = null;
response = apiQueryAndReponse(request, args[0]);
if (response != null)
{
byte[] byData = Encoding.ASCII.GetBytes(response);
stream.Write(byData, 0, byData.Length);
stream.Flush();
}
}
}
}
catch (Exception e)
{
Console.WriteLine("Something went wrong.");
Console.WriteLine(e.Message.ToString());
//sw.WriteLine(e.ToString());
}
}
}
Get and return the response:
private static string apiQueryAndReponse(string rec, String stagingfilepath)
{
String response = null;
if (rec.Contains("GetTesterInfo"))
{
response = getLatestStatusOK("GetTesterInfo", stagingfilepath);
if (response != null)
{
Console.WriteLine("Response: " + response + "," + fileline + "\n");
fileline++;
}
}
return response;
}
Read the text file and get the response:
private static String getLatestStatusOK(String key, String filedir)
{
using (var fs = new FileStream(filedir, FileMode.Open, FileAccess.Read))
{
using (var sr = new StreamReader(fs, Encoding.UTF8))
{
while ((stagingfiledata = sr.ReadLine()) != null)
{
try
{
if (stagingfiledata.Contains(key))
{
String[] data = stagingfiledata.Split(",");
response = data[2];
}
}
catch (Exception exp)
{
Console.WriteLine("err messageļ¼" + exp.Message);
}
}
}
}
return response;
}
What I trying to do here: I will read a text file and get response to reply to client. But the socket will disconnect after access the text file.(I have tried connect with client without call the text file access function). I want to maintain connection and read text file when it necessary.
There are a number of issues with this code.
Your primary issue: you are creating a new StreamReader and StreamWriter on each loop, and they dispose the underlying stream when they are garbage-collected.
You aren't even using those readers and writers, you may as well remove them
You are missing using in a number of places.
The number of bytes received is returned from the Read function, you do not have to guesstimate by checking for \0.
static void Main(string[] args)
{
IPAddress ipAddr = IPAddress.Parse(args[1]);
TcpListener listener = new TcpListener(ipAddr, Int32.Parse(args[2]));
listener.Start();
Console.WriteLine("Waiting for a connection.");
using TcpClient client = listener.AcceptTcpClient();
Console.WriteLine("Client accepted.");
using NetworkStream stream = client.GetStream();
while (true)
{
try
{
byte[] buffer = new byte[1024];
int recv = stream.Read(buffer, 0, buffer.Length);
string request = Encoding.UTF8.GetString(buffer, 0, recv);
Console.WriteLine("request received: " + request);
if (request != null)
{
string response = null;
response = apiQueryAndReponse(request, args[0]);
if (response != null)
{
byte[] byData = Encoding.UTF8.GetBytes(response);
stream.Write(byData, 0, byData.Length);
stream.Flush();
}
}
}
catch (Exception e)
{
Console.WriteLine("Something went wrong.");
Console.WriteLine(e.Message.ToString());
//sw.WriteLine(e.ToString());
}
}
}
There are other serious flaws with your design:
TCP does not guarantee that a single write will become a single read on the other end of the wire. Chunks of data may be split or combined. It's a stream, not a messaging protocol.
So you need a framing mechanism. The easiest one to use is to first pass the size of your data, then read that amount of bytes.
You are also not able to handle multiple clients. You need to hand off each one to a Task.
Corrollary to that, you should use async functions to improve performance and responsiveness.
You should also have a cancellation token which you can use if someone presses CTRL+C.
You probably shouldn't try to handle an exception and then continue. If an exception happens, log it and close the connection.
static CancellationTokenSource _cancellation = new();
static async Task Main(string[] args)
{
Console.CancelKeyPress += (sender, e) => _cancellation.Cancel();
IPAddress ipAddr = IPAddress.Parse(args[1]);
TcpListener listener = new TcpListener(ipAddr, Int32.Parse(args[2]));
listener.Start();
try
{
Console.WriteLine("Waiting for a connection.");
TcpClient client = await listener.AcceptTcpClientAsync(_cancellation.Token);
Console.WriteLine("Client accepted.");
Task.Run(() => HandleClient(client), _cancellation.Token);
}
catch (OperationCanceledException)
{ //
}
finally
{
listener.Stop();
}
}
private async Task HandleClient(TcpClient client)
{
using var _ = client;
await using NetworkStream stream = client.GetStream();
var lengthBuf = new byte[4];
try
{
while (true)
{
await stream.ReadExactlyAsync(lengthBuf, 0, 4, _cancellation.Token);
var length = BitConverter.ToInt32(lengthBuf, 0);
if(length > SomeMaxLengthHere || length <= 0)
throw new Exception("Too long");
byte[] buffer = new byte[length];
await stream.ReadExactly(buffer, 0, length, _cancellation.Token);
string request = Encoding.UTF8.GetString(buffer, 0, length);
Console.WriteLine("request received: " + request);
if (request != null)
{
string response = apiQueryAndReponse(request, args[0]);
if (response != null)
{
byte[] byData = Encoding.UTF8.GetBytes(response);
await stream.WriteAsync(byData, 0, byData.Length, _cancellation.Token);
await stream.FlushAsync(_cancellation.Token);
}
}
}
}
catch (OperationCanceledException)
{ //
}
catch (Exception e)
{
Console.WriteLine("Something went wrong.");
Console.WriteLine(e.Message.ToString());
//sw.WriteLine(e.ToString());
}
}
I'm trying to build a simple http proxy, which does four really basic things:
Accepts connection from web-browser (using TcpClient/TcpListener).
Reads request from its stream.
Reads hostname and initiates connection with host.
Loads content from webpage and forwards it back to the client.
The troubles i met with:
Sometimes page wouldn't load at all.
Sometimes browser gives me an error 'The content has wrong encryption'(in firefox).
Seldom i can see content corruption(plain text instead of HTML).
What i've done:
HttpListener class that contains methods for listening for incoming requests and invoking event OnNewRequestReceived:
public void Listen()
{
Listener.Start();
while (true)
{
var client = Listener.AcceptTcpClient();
Task.Run(() => StartReceivingData(client));
}
}
public void StartReceivingData(TcpClient client)
{
NetworkStream clientStream = client.GetStream();
var buffer = new byte[16000];
while (true)
{
try
{
if (!clientStream.CanRead)
return;
//connection is closed
if (clientStream.Read(buffer).Equals(0))
return;
OnNewRequestReceived?.Invoke(this, new RequestReceivedEventArgs() { User = client, Request = buffer });
} // when clientStream is disposed, exception is thrown.
catch { return; }
}
}
HttpClient class which basically contains a method that subscribes to event described above:
private void Listener_OnNewConnectionReceived(object sender, RequestReceivedEventArgs e)
{
string hostname = HttpQueryParser.GetHostName(e.Request);
NetworkStream proxyClientStream = e.User.GetStream();
try
{
if (firewall.CheckIfBlocked(hostname))
{
//send error page
e.User.GetStream().Write(Encoding.ASCII.GetBytes("<html><body style=\"padding:0; margin:0;\"><img style=\"padding:0; margin:0; width:100%; height:100%;\" src=\"https://www.hostinger.co.id/tutorial/wp-content/uploads/sites/11/2017/08/what-is-403-forbidden-error-and-how-to-fix-it.jpg\"</body></html>"));
return;
}
var targetServer = new TcpClient(hostname, 80);
NetworkStream targetServerStream = targetServer.GetStream();
targetServerStream.Write(e.Request);
var responseBuffer = new byte[32];
for (int offsetCounter = 0; true; ++offsetCounter)
{
var bytesRead = targetServerStream.Read(responseBuffer, 0, responseBuffer.Length);
// Console.WriteLine($"Read {bytesRead} from {hostname}.");
if (bytesRead.Equals(0))
return;
proxyClientStream.Write(responseBuffer, 0, responseBuffer.Length);
if (offsetCounter.Equals(0))
{
var headers = Encoding.UTF8.GetString(responseBuffer).Split("\r\n");
logger.Log(new HttpRequestEntry()
{
ResponseCode = headers[0].Substring(headers[0].IndexOf(" ") + 1),
Hostname = hostname
});
}
}
}
catch { return; }
finally { proxyClientStream.Dispose(); }
}
So, i'm guessing there's a problem with my buffer size, but changing it to higher values actually doesn't change anything .
Ok so i don't know what's the problem with my byte arrays was, but i made it work, using Stream.CopyTo , which i was quite surprized about - it works on two NetworkStreams.
Here's working method if you are curious:
private void Listener_OnNewConnectionReceived(object sender, RequestReceivedEventArgs e)
{
string hostname = HttpQueryParser.GetHostName(e.Request);
NetworkStream proxyClientStream = e.User.GetStream();
try
{
if (firewall.CheckIfBlocked(hostname))
{
//send error page
e.User.GetStream().Write(Encoding.ASCII.GetBytes("<html><body style=\"padding:0; margin:0;\"><img style=\"padding:0; margin:0; width:100%; height:100%;\" src=\"https://www.hostinger.co.id/tutorial/wp-content/uploads/sites/11/2017/08/what-is-403-forbidden-error-and-how-to-fix-it.jpg\"</body></html>"));
return;
}
var targetServer = new TcpClient(hostname, 80);
NetworkStream targetServerStream = targetServer.GetStream();
targetServerStream.Write(e.Request);
var responseBuffer = new byte[32];
//this is to capture status of http request and log it.
targetServerStream.Read(responseBuffer, 0, responseBuffer.Length);
proxyClientStream.Write(responseBuffer, 0, responseBuffer.Length);
var headers = Encoding.UTF8.GetString(responseBuffer).Split("\r\n");
logger.Log(new HttpRequestEntry()
{
ResponseCode = headers[0].Substring(headers[0].IndexOf(" ") + 1),
Hostname = hostname
});
targetServerStream.CopyTo(proxyClientStream);
}
catch { return; }
finally { proxyClientStream.Dispose(); }
}
I'm wanting to run a little socket server in C# to be accessed by a browser. I have a socket listener up and running on a specific port, and am trying to access it via the browser:
class WebSocketServer
{
private static string output = string.Empty;
public void CreateListener()
{
TcpListener tcpListener = null;
var ipAddress = Dns.GetHostEntry("localhost").AddressList[0];
try
{
tcpListener = new TcpListener(ipAddress, 1313);
tcpListener.Start();
output = "Waiting for a connection";
}
catch (Exception e)
{
throw;
}
var socketHelper = new SocketHelper();
while (true)
{
Thread.Sleep(10);
TcpClient tcpClient = tcpListener.AcceptTcpClient();
byte[] bytes = new byte[256];
var stream = tcpClient.GetStream();
stream.Read(bytes, 0, bytes.Length);
socketHelper.ProcessMessage(tcpClient, stream, bytes);
}
}
}
class SocketHelper
{
private static int counter = 0;
public void ProcessMessage(TcpClient tcpClient, NetworkStream stream, byte[] bytesReceived)
{
// handle message received and send response to client
var msg = Encoding.ASCII.GetString(bytesReceived);
string response = string.Empty;
if (msg.Substring(0, 10) == "GET / HTTP")
{
response = "";// html page
}
byte[] bytesToSend = Encoding.ASCII.GetBytes(response);
stream.Write(bytesToSend, 0, bytesToSend.Length);
}
The browser appears to connect to it, but it never seems to display the html - what's wrong? I'm eventually wanting to be able to serve up JSON data via a REST interface. In addition, is there a much easier solution to (I assume) this common problem.
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've read a couple of posts on SignalR and thought for a fun test project that I could create a web application to poll my onkyo receiver for status and display the results in a browser. For an initial test, I was successfully able to send the current time on the server back to the client by using this code in Application_Start:
ThreadPool.QueueUserWorkItem(_ =>
{
dynamic clients = Hub.GetClients<KudzuHub>();
while (true)
{
clients.addMessage(DateTime.Now.ToString());
Thread.Sleep(1000);
}
});
In the client javascript, i have the following code:
// Proxy created on the fly
var kHub = $.connection.kudzuHub;
// Declare a function on the hub so that the server can invoke it
kHub.addMessage = function (message) {
console.log('message added');
$('#messages').append('<li>' + message + '</li>');
};
// start the connection
$.connection.hub.start();
So all of that works fine. Every second, I get a new list item containing the current server date and time.
Now when I add this code to read data from the Onkyo receiver, it breaks: (still in Application_Start)
ThreadPool.QueueUserWorkItem(_ =>
{
dynamic clients = Hub.GetClients<KudzuHub>();
try
{
while (true)
{
string host = ConfigurationManager.AppSettings["receiverIP"].ToString();
int port = Convert.ToInt32(ConfigurationManager.AppSettings["receiverPort"]);
TcpClient tcpClient = new TcpClient(host, port);
NetworkStream clientSockStream = tcpClient.GetStream();
byte[] bytes = new byte[tcpClient.ReceiveBufferSize];
clientSockStream.Read(bytes, 0, (int)tcpClient.ReceiveBufferSize);
tcpClient.Close();
clients.addMessage(System.Text.Encoding.ASCII.GetString(bytes));
Thread.Sleep(50);
}
}
catch (SocketException ex)
{
// do something to handle the error
}
});
I set a break point and stepped through the code. It gets to this line and then returns.
clientSockStream.Read(bytes, 0, (int)tcpClient.ReceiveBufferSize);
It never finishes the rest of the code to send the message to the client. What am I doing wrong?
Thanks.
I would make some structural changes to your loop to allow the receiver time to respond, remove the overhead of retrieving the configuration every 50 milliseconds, and cleanup the open network stream:
ThreadPool.QueueUserWorkItem(_ =>
{
dynamic clients = Hub.GetClients<KudzuHub>();
TcpClient tcpClient = null;
NetworkStream clientSockStream = null;
try
{
string host = ConfigurationManager.AppSettings["receiverIP"].ToString();
int port = Convert.ToInt32(ConfigurationManager.AppSettings["receiverPort"]);
while (true)
{
if (tcpClient == null) {
tcpClient = new TcpClient(host, port);
clientSockStream = tcpClient.GetStream();
}
if (clientSockStream.CanRead) {
byte[] bytes = new byte[tcpClient.ReceiveBufferSize];
try {
clientSockStream.Read(bytes, 0, (int)tcpClient.ReceiveBufferSize);
} catch (Exception ex) {
// Add some debug code here to examine the exception that is thrown
}
tcpClient.Close();
// Closing the client does not automatically close the stream
clientSockStream.Close();
tcpClient = null;
clientSockStream = null;
clients.addMessage(System.Text.Encoding.ASCII.GetString(bytes));
}
Thread.Sleep(50);
}
}
catch (SocketException ex)
{
// do something to handle the error
} finally {
if (tcpClient != null) {
tcpClient.Close();
clientSockStream.Close();
}
}
});