Hi I'm new to programming and new to even more newer at C#.
I wanted to create a second file to make everything look a bit cleaner but it doesn't work out.
It's an UWP background project for a RP3 running Windows 10 IoT core.
I want to make a webserver that can be accessed by an app but I haven't made that code yet, obviously.
Now I'm trying to figure out the connection between the Arduino and the RP. It works perfectly for the most part.
But I wanted to make it look better so I wanted to put all the sensor stuff in a different file but I can't access or change any variable.
For example, I want to change clState to true/false, I can't do that.
Another problem I have is that when the arduino sends a single string through serial, the RP receives it and it works perfectly but if I send multiple strings (for example multiple Serial.write) it receives it but my code that checks if it's correct only works for on of the strings... I suspect it has something to do with the asynchronous stuff but I don't know how to fix it. But that is less important.
rcvdText = dataReaderObject.ReadString(bytesRead);
Debug.WriteLine("Debug: Succesvol gelezen van Arduino");
Debug.WriteLine(rcvdText);
char startMarker = '<';
char endMarker = '>';
if (rcvdText.Contains(startMarker) == true && rcvdText.Contains(endMarker) == true)
{
int startIndex = rcvdText.IndexOf(startMarker) + 1;
int endIndex = rcvdText.IndexOf(endMarker) - 1;
receivedChars = rcvdText.Substring(startIndex, endIndex);
Debug.WriteLine(receivedChars);
CheckNewData();
}
All help is very much appreciated! :)
Sorry the indentation failed when copying... And I think I didn't follow the naming convention...
This is the main file.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Http;
using Windows.ApplicationModel.Background;
using Windows.Devices.Enumeration;
using Windows.Devices.SerialCommunication;
using System.Diagnostics;
using System.Threading.Tasks;
using Windows.Networking.Sockets;
using Windows.ApplicationModel.AppService;
using Windows.Storage.Streams;
using System.Runtime.InteropServices.WindowsRuntime;
namespace ArduinoData
{
public sealed class StartupTask : IBackgroundTask
{
//public bool clState;
public ArduinoConnect test2 = new ArduinoConnect();
BackgroundTaskDeferral serviceDeferral;
public void Run(IBackgroundTaskInstance taskInstance)
{
serviceDeferral = taskInstance.GetDeferral();
BackgroundTaskDeferral arduinoDeferral = taskInstance.GetDeferral();
//ArduinoConnect test = new ArduinoConnect();
test2.WatchDevice();
Test();
test2.clState = false;
}
}
}
And this is ArduinoConnect.cs
using System;
using System.Linq;
using Windows.Devices.Enumeration;
using Windows.Devices.SerialCommunication;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.Storage.Streams;
namespace ArduinoData
{
public sealed class ArduinoConnect
{
DataReader dataReaderObject = null;
private SerialDevice serialPort = null;
private CancellationTokenSource ReadCancellationTokenSource;
private string rcvdText;
private string receivedChars;
//variabelen voor status
private bool clState;
private bool phPlusState;
private bool phMinState;
private bool pompState;
private bool lampenState;
private bool warmteState;
private bool vulState;
private bool waterState;
private byte dekState;
public void WatchDevice()
{
UInt16 vid = 0x2341;
UInt16 pid = 0x0001;
string aqs = SerialDevice.GetDeviceSelectorFromUsbVidPid(vid, pid);
var Watcher = DeviceInformation.CreateWatcher(aqs);
Watcher.Added += new TypedEventHandler<DeviceWatcher, DeviceInformation>(DeviceAdded);
Watcher.Removed += new TypedEventHandler<DeviceWatcher, DeviceInformationUpdate>(OnDeviceRemoved);
Watcher.Start();
}
private async void DeviceAdded(DeviceWatcher watcher, DeviceInformation device)
{
Debug.WriteLine("Debug: Apparaat gevonden! :)");
try
{
serialPort = await SerialDevice.FromIdAsync(device.Id);
Debug.WriteLine("Debug: " + device.Name + " verbonden!!! :D");
serialPort.WriteTimeout = TimeSpan.FromMilliseconds(1000);
serialPort.ReadTimeout = TimeSpan.FromMilliseconds(1000);
serialPort.BaudRate = 9600;
serialPort.Parity = SerialParity.None;
serialPort.StopBits = SerialStopBitCount.One;
serialPort.DataBits = 8;
serialPort.Handshake = SerialHandshake.None;
Debug.WriteLine("Debug: Seriële poort succesvol geconfigureerd! :D");
ReadCancellationTokenSource = new CancellationTokenSource();
}
catch
{
Debug.WriteLine("Debug: Fout bij Seriële poort configureren. :(");
}
Listen();
}
private async void Listen()
{
try
{
Debug.WriteLine("Debug: Listen() function");
if (serialPort != null)
{
dataReaderObject = new DataReader(serialPort.InputStream);
// keep reading the serial input
while (true)
{
await ReadAsync(ReadCancellationTokenSource.Token);
}
}
}
catch (TaskCanceledException)
{
Debug.WriteLine("Reading task was cancelled, closing device and cleaning up");
CloseDevice();
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
finally
{
// Cleanup once complete
if (dataReaderObject != null)
{
dataReaderObject.DetachStream();
dataReaderObject = null;
}
}
}
private async Task ReadAsync(CancellationToken cancellationToken)
{
Task<UInt32> loadAsyncTask;
uint ReadBufferLength = 1024;
// If task cancellation was requested, comply
cancellationToken.ThrowIfCancellationRequested();
// Set InputStreamOptions to complete the asynchronous read operation when one or more bytes is available
dataReaderObject.InputStreamOptions = InputStreamOptions.Partial;
using (var childCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken))
{
// Create a task object to wait for data on the serialPort.InputStream
loadAsyncTask = dataReaderObject.LoadAsync(ReadBufferLength).AsTask(childCancellationTokenSource.Token);
// Launch the task and wait
UInt32 bytesRead = await loadAsyncTask;
if (bytesRead > 0)
{
rcvdText = dataReaderObject.ReadString(bytesRead);
Debug.WriteLine("Debug: Succesvol gelezen van Arduino");
Debug.WriteLine(rcvdText);
char startMarker = '<';
char endMarker = '>';
if (rcvdText.Contains(startMarker) == true && rcvdText.Contains(endMarker) == true)
{
int startIndex = rcvdText.IndexOf(startMarker) + 1;
int endIndex = rcvdText.IndexOf(endMarker) - 1;
receivedChars = rcvdText.Substring(startIndex, endIndex);
Debug.WriteLine(receivedChars);
CheckNewData();
}
}
}
}
private void CheckNewData()
{
switch (receivedChars)
{
case "CL_STATE=0" :
clState = false;
break;
case "CL_STATE=1" :
clState = true;
break;
case "PHPLUS_STATE=0" :
phPlusState = false;
break;
case "PHPLUS_STATE=1" :
phPlusState = true;
break;
case "POMP_STATE=0" :
pompState = false;
break;
case "POMP_STATE=1" :
pompState = false;
break;
case "LAMPEN_STATE=0" :
lampenState = false;
break;
case "LAMPEN_STATE=1" :
lampenState = true;
break;
case "VUL_STATE=0" :
vulState = false;
break;
case "VUL_STATE=1" :
vulState = true;
break;
case "WATER_STATE=0" :
waterState = false;
break;
case "WATER_STATE=1" :
waterState = true;
break;
case "DEK_STATE=0" :
dekState = 0;
break;
case "DEK_STATE=1" :
dekState = 1;
break;
case "DEK_STATE=2" :
dekState = 2;
break;
case "REFRESH=1" :
Debug.WriteLine("Debug: Refresh uitgevoerd!");
break;
default:
Debug.WriteLine("Debug: Fout commando!");
break;
}
}
private void OnDeviceRemoved(DeviceWatcher sender, DeviceInformationUpdate device)
{
Debug.WriteLine("Debug: Apparaat losgekoppeld.");
try
{
CancelReadTask();
CloseDevice();
}
catch(Exception ex)
{
Debug.WriteLine("Debug: " + ex.Message);
}
}
private void CancelReadTask()
{
if (ReadCancellationTokenSource != null)
{
if (!ReadCancellationTokenSource.IsCancellationRequested)
{
ReadCancellationTokenSource.Cancel();
}
}
}
private void CloseDevice()
{
if (serialPort != null)
{
serialPort.Dispose();
}
serialPort = null;
rcvdText = "";
}
}
}
EDIT
I have a new problem with this code I had the same problem sometimes with my old code above...
Error
Exception thrown: 'System.ArgumentOutOfRangeException' in System.Private.CoreLib.ni.dll
Index and length must refer to a location within the string.
Parameter name: length
I can't paste it correctly, it's annoying...
if (bytesRead > 0)
{
rcvdText = dataReaderObject.ReadString(bytesRead);
Debug.WriteLine("Debug: Succesvol gelezen van Arduino");
Debug.WriteLine(rcvdText);
//char startMarker = '<';
//char endMarker = '>';
int i = 0;
foreach (var ch in rcvdText)
{
//if (ch != '\u+003C') continue;
if (ch == '\u003C')
{
StartIndex = i + 1;
Debug.WriteLine(StartIndex);
}
if (ch == '\u003E')
{
EndIndex = i - 1;
Debug.WriteLine(EndIndex);
receivedChars = rcvdText.Substring(StartIndex, EndIndex);
Debug.WriteLine(receivedChars);
StartIndex = 0;
EndIndex = 0;
}
i++;
Debug.WriteLine("test");
}
Debug.WriteLine("finished");
}
And the Debug output:
Debug: Succesvol gelezen van Arduino
<WATER_STATE=1>
<WATER_STATE=0>
1
test
test
test
test
test
test
test
test
test
test
test
test
test
test
13
WATER_STATE=1
test
test
test
18
test
test
test
test
test
test
test
test
test
test
test
test
test
test
30
Exception thrown: 'System.ArgumentOutOfRangeException' in System.Private.CoreLib.ni.dll
test2
Index and length must refer to a location within the string.
Parameter name: length
test2
The program '[2888] backgroundTaskHost.exe' has exited with code -1 (0xffffffff).
EDIT2 I figured it out, I'm an idiot...
But I wanted to make it look better so I wanted to put all the sensor
stuff in a different file but I can't access or change any variable.
For example, I want to change clState to true/false, I can't do that.
You can using auto-implementing properties like this:
public bool clState { get; set; }
More information you can reference here.
Related
I try to implement the HoloLens2 - PC TCP Socket.
For the Unity project, which is built into HoloLens2, I have selected the InternetClient, InternetClientServer, and PrivateNetworkClientServer options.
And I also closed the SSL connection required option for HoloLens2.
The result is that HoloLens2 can create a socket successfully, but I run the code on a PC to connect the HoloLens2 socket server always shows timeout.
The code is below.
How can I solve...?
HoloLens 2: TCP Server
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
#if !UNITY_EDITOR
using Windows.Networking;
using Windows.Networking.Sockets;
using Windows.Storage.Streams;
#endif
//Able to act as a reciever
public class UniversalSampleTutorial : MonoBehaviour
{
public String _input = "Waiting";
public bool _listening = false;
public bool _connect = false;
#if !UNITY_EDITOR
StreamSocket socket;
StreamSocketListener listener;
String port;
String message;
#endif
// Use this for initialization
void Start()
{
#if !UNITY_EDITOR
listener = new StreamSocketListener();
port = "9090";
listener.ConnectionReceived += Listener_ConnectionReceived;
listener.Control.KeepAlive = true;
Listener_Start();
#endif
}
#if !UNITY_EDITOR
private async void Listener_Start()
{
Debug.Log("Listener started");
try
{
await listener.BindServiceNameAsync(port);
}
catch (Exception e)
{
Debug.Log("Error: " + e.Message);
}
Debug.Log("Listening");
_listening = true;
}
private async void Listener_ConnectionReceived(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args)
{
Debug.Log("Connection received");
_connect = true;
try
{
while (true) {
using (var dw = new DataWriter(args.Socket.OutputStream))
{
dw.WriteString("Hello There");
await dw.StoreAsync();
dw.DetachStream();
}
using (var dr = new DataReader(args.Socket.InputStream))
{
dr.InputStreamOptions = InputStreamOptions.Partial;
await dr.LoadAsync(12);
var input = dr.ReadString(12);
Debug.Log("received: " + input);
_input = input;
}
}
}
catch (Exception e)
{
Debug.Log("disconnected!!!!!!!! " + e);
}
}
#endif
void Update()
{
if (_listening == false && _connect == false)
this.GetComponent<TextMesh>().text = _input;
else if (_listening == true && _connect == false)
this.GetComponent<TextMesh>().text = "Listening";
else if (_listening == true && _connect == true)
this.GetComponent<TextMesh>().text = "Connect";
}
}
PC: TCP Client
import asyncio
#THIS CODE WORKS SENDING STRING MESSAGE TO HOLOLENS
async def tcp_echo_client(message, loop):
reader, writer = await asyncio.open_connection('192.168.0.102', 9090, loop=loop)
print('Send: %r' % message)
writer.write(message.encode())
data = await reader.read(100)
print('Received: %r' % data.decode())
print('Close the socket')
writer.close()
message = 'hello there frend'
loop = asyncio.get_event_loop()
loop.run_until_complete(tcp_echo_client(message, loop))
loop.close()
I need to download a file and use it to connect to a server. If the connection fails, it restarts the loop. Somehow the while loop keeps running and downloading the file constantly. I think that something weird happens with the boolean Globals.sockRetry but I can't find what's really happening.
public class Globals
{
public static string serverIp;
public static int serverPort;
public static int sockConn = 0;
public static bool sockRetry = false;
public static TcpClient client;
public static NetworkStream nwStream;
public static StreamReader reader;
public static StreamWriter writer;
}
static void connect(Globals g)
{
Globals.sockConn = 1;
try
{
Globals.client = new TcpClient(Globals.serverIp, Globals.serverPort);
Globals.nwStream = Globals.client.GetStream();
Globals.reader = new StreamReader(Globals.nwStream);
Globals.writer = new StreamWriter(Globals.nwStream);
Globals.sockConn = 2;
string inputLine;
while ((inputLine = Globals.reader.ReadLine()) != null)
{
// ParseMessage(Globals.writer, inputLine, g);
}
}
catch
{
Globals.sockRetry = true;
Globals.sockConn = 0;
return;
}
}
static void getInfo()
{
while (true)
{
try
{
WebRequest request = WebRequest.Create(INFO_HOST + INFO_PATH);
WebResponse response = request.GetResponse();
string content;
using (var sr = new StreamReader(response.GetResponseStream()))
{
content = sr.ReadToEnd();
}
string[] contentArray = content.Split(':');
string serverIp = contentArray[0];
string serverPortStr = contentArray[1];
int serverPort = 5000;
Int32.TryParse(serverPortStr, out serverPort);
Globals g = new Globals();
Globals.serverIp = serverIp;
Globals.serverPort = serverPort;
while (Globals.sockConn == 0)
{
if (Globals.sockRetry == false)
{
connect(g);
}
else
{
// error connecting
// wait and retry
Globals.sockRetry = false;
Thread.Sleep(60000);
break;
}
}
continue;
}
catch
{
// error downloading file
// wait and retry
Thread.Sleep(60000);
continue;
}
}
}
The only place there you terminate the loop is here:
if (Globals.sockRetry == false)
{
connect(g);
}
else
{
...
break;
}
So it happens only if Globals.sockRetry == true. Globals.sockRetry is assigned true only if an exception is thrown. If no exception is thrown, the loop never ends.
Change it like this:
if (Globals.sockRetry == false)
{
connect(g);
break;
}
Otherwise after you connect you will connect again, and then again till an exception is thrown (hopefully).
continue continues to the next iteration in the loop.
break stops the loop. So, the loop never ends.
You set sockRetry to false when you want to stop the loop, so you could do this: while (sockRetry)
I have two Clients (Client-PC1 + Client-PC2) on my Network.
On each of that Clients I like to run a small c# Forms/Console Application and I like to communicate between that Applications.
I like to trigger the Application on Client-PC2 from Client-PC1. (in Code-Part: menuItem1_Click)
I already did some research and found this article on TechNet: How to: Use Named Pipes for Network Interprocess Communication
But I have one mistake or misunderstanding:
On the server side there is a specific number of threads that can be handled (at the moment: numThreads = 4)
So if I trigger from Client-PC1 more then 4 times then the Server side (Client-PC2) is closing the whole application...
How can I change this code to accept more than just 4 requests/triggers?
In total there are only 1-2 Computers that will connect to the server but sending multiple requests.
I think that I make something wrong on the client side after sending the request/trigger?
Any ideas?
Client Code:
using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.IO.Pipes;
using System.Collections.Generic;
using System.Linq;
using System.Security.Principal;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace NamedPipe_Client
{
class Program
{
private static int numClients = 4;
private static bool isConnected = false;
private System.Windows.Forms.NotifyIcon notifyIcon1;
private System.Windows.Forms.ContextMenu contextMenu1;
private System.Windows.Forms.MenuItem menuItem1;
private System.ComponentModel.IContainer components;
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
static void Main(string[] args)
{
Program pg = new Program();
//pg.CreateNotifyicon();
Application.Run();
Console.ReadLine();
}
Program()
{
CreateNotifyicon();
// hide application
System.IntPtr HWnd = FindWindow(null, Application.ExecutablePath);
if (HWnd != null)
{
bool result = ShowWindow(HWnd, 0);
}
}
private void CreateNotifyicon()
{
this.components = new System.ComponentModel.Container();
this.contextMenu1 = new System.Windows.Forms.ContextMenu();
this.menuItem1 = new System.Windows.Forms.MenuItem();
// Initialize menuItem1
this.menuItem1.Index = 0;
this.menuItem1.Text = "E&xit";
this.menuItem1.Click += new System.EventHandler(this.menuItem1_Click);
// Initialize contextMenu1
this.contextMenu1.MenuItems.AddRange(
new System.Windows.Forms.MenuItem[] { this.menuItem1 });
// Create the NotifyIcon.
this.notifyIcon1 = new System.Windows.Forms.NotifyIcon(this.components);
// The Icon property sets the icon that will appear
// in the systray for this application.
notifyIcon1.Icon = new Icon("app_icon.ico");
// The ContextMenu property sets the menu that will
// appear when the systray icon is right clicked.
notifyIcon1.ContextMenu = this.contextMenu1;
// The Text property sets the text that will be displayed,
// in a tooltip, when the mouse hovers over the systray icon.
notifyIcon1.Text = "Console App (Console example)";
notifyIcon1.Visible = true;
// Handle the DoubleClick event to activate the form.
notifyIcon1.DoubleClick += new System.EventHandler(this.notifyIcon1_DoubleClick);
notifyIcon1.Click += new System.EventHandler(this.notifyIcon1_Click);
}
private void notifyIcon1_Click(object Sender, EventArgs e)
{
MessageBox.Show("clicked");
}
private void notifyIcon1_DoubleClick(object Sender, EventArgs e)
{
MessageBox.Show("Double clicked");
}
private void menuItem1_Click(object Sender, EventArgs e)//on menu click exit.
{
//Show application again
//System.IntPtr HWnd = FindWindow(null, Application.ExecutablePath);
//if (HWnd != null)
//{
// bool result = ShowWindow(HWnd, 1);
//}
NamedPipeClientStream pipeClient =
new NamedPipeClientStream(".", "testpipe",
PipeDirection.InOut, PipeOptions.None,
TokenImpersonationLevel.Impersonation);
Console.WriteLine("Connecting to server...\n");
pipeClient.Connect();
StreamString ss = new StreamString(pipeClient);
// Validate the server's signature string
if (ss.ReadString() == "I am the one true server!")
{
// The client security token is sent with the first write.
// Send the name of the file whose contents are returned
// by the server.
//ss.WriteString(#"C:\Test\textfile.txt");
ss.WriteString("Test");
// Print the file to the screen.
Console.Write(ss.ReadString());
}
else
{
Console.WriteLine("Server could not be verified.");
}
pipeClient.Close();
}
// Helper function to create pipe client processes
private static void StartClients()
{
int i;
string currentProcessName = Environment.CommandLine;
Process[] plist = new Process[numClients];
Console.WriteLine("Spawning client processes...\n");
if (currentProcessName.Contains(Environment.CurrentDirectory))
{
currentProcessName = currentProcessName.Replace(Environment.CurrentDirectory, String.Empty);
}
// Remove extra characters when launched from Visual Studio
currentProcessName = currentProcessName.Replace("\\", String.Empty);
currentProcessName = currentProcessName.Replace("\"", String.Empty);
for (i = 0; i < numClients; i++)
{
// Start 'this' program but spawn a named pipe client.
plist[i] = Process.Start(currentProcessName, "spawnclient");
}
while (i > 0)
{
for (int j = 0; j < numClients; j++)
{
if (plist[j] != null)
{
if (plist[j].HasExited)
{
Console.WriteLine("Client process[{0}] has exited.",
plist[j].Id);
plist[j] = null;
i--; // decrement the process watch count
}
else
{
Thread.Sleep(250);
}
}
}
}
Console.WriteLine("\nClient processes finished, exiting.");
}
}
// Defines the data protocol for reading and writing strings on our stream
public class StreamString
{
private Stream ioStream;
private UnicodeEncoding streamEncoding;
public StreamString(Stream ioStream)
{
this.ioStream = ioStream;
streamEncoding = new UnicodeEncoding();
}
public string ReadString()
{
int len;
len = ioStream.ReadByte() * 256;
len += ioStream.ReadByte();
byte[] inBuffer = new byte[len];
ioStream.Read(inBuffer, 0, len);
return streamEncoding.GetString(inBuffer);
}
public int WriteString(string outString)
{
byte[] outBuffer = streamEncoding.GetBytes(outString);
int len = outBuffer.Length;
if (len > UInt16.MaxValue)
{
len = (int)UInt16.MaxValue;
}
ioStream.WriteByte((byte)(len / 256));
ioStream.WriteByte((byte)(len & 255));
ioStream.Write(outBuffer, 0, len);
ioStream.Flush();
return outBuffer.Length + 2;
}
}
}
Server Code:
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Pipes;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace NamedPipe_Server
{
class Program
{
private static int numThreads = 4;
static void Main(string[] args)
{
int i;
Thread[] servers = new Thread[numThreads];
Console.WriteLine("\n*** Named pipe server stream with impersonation example ***\n");
Console.WriteLine("Waiting for client connect...\n");
for (i = 0; i < numThreads; i++)
{
servers[i] = new Thread(ServerThread);
servers[i].Start();
}
Thread.Sleep(250);
while (i > 0)
{
for (int j = 0; j < numThreads; j++)
{
if (servers[j] != null)
{
if (servers[j].Join(250))
{
Console.WriteLine("Server thread[{0}] finished.", servers[j].ManagedThreadId);
servers[j] = null;
i--; // decrement the thread watch count
}
}
}
}
Console.WriteLine("\nServer threads exhausted, exiting.");
}
private static void ServerThread(object data)
{
NamedPipeServerStream pipeServer =
new NamedPipeServerStream("testpipe", PipeDirection.InOut, numThreads);
int threadId = Thread.CurrentThread.ManagedThreadId;
// Wait for a client to connect
pipeServer.WaitForConnection();
Console.WriteLine("Client connected on thread[{0}].", threadId);
try
{
// Read the request from the client. Once the client has
// written to the pipe its security token will be available.
StreamString ss = new StreamString(pipeServer);
// Verify our identity to the connected client using a
// string that the client anticipates.
ss.WriteString("I am the one true server!");
string filename = ss.ReadString();
if (filename.ToString() == "Test")
{
Console.WriteLine("yes");
ss.WriteString("Done");
}
// Read in the contents of the file while impersonating the client.
//ReadFileToStream fileReader = new ReadFileToStream(ss, filename);
// Display the name of the user we are impersonating.
//Console.WriteLine("Reading file: {0} on thread[{1}] as user: {2}.",
// filename, threadId, pipeServer.GetImpersonationUserName());
//pipeServer.RunAsClient(fileReader.Start);
}
// Catch the IOException that is raised if the pipe is broken
// or disconnected.
catch (IOException e)
{
Console.WriteLine("ERROR: {0}", e.Message);
}
pipeServer.Close();
}
}
// Defines the data protocol for reading and writing strings on our stream
public class StreamString
{
private Stream ioStream;
private UnicodeEncoding streamEncoding;
public StreamString(Stream ioStream)
{
this.ioStream = ioStream;
streamEncoding = new UnicodeEncoding();
}
public string ReadString()
{
int len = 0;
len = ioStream.ReadByte() * 256;
len += ioStream.ReadByte();
byte[] inBuffer = new byte[len];
ioStream.Read(inBuffer, 0, len);
return streamEncoding.GetString(inBuffer);
}
public int WriteString(string outString)
{
byte[] outBuffer = streamEncoding.GetBytes(outString);
int len = outBuffer.Length;
if (len > UInt16.MaxValue)
{
len = (int)UInt16.MaxValue;
}
ioStream.WriteByte((byte)(len / 256));
ioStream.WriteByte((byte)(len & 255));
ioStream.Write(outBuffer, 0, len);
ioStream.Flush();
return outBuffer.Length + 2;
}
}
// Contains the method executed in the context of the impersonated user
public class ReadFileToStream
{
private string fn;
private StreamString ss;
public ReadFileToStream(StreamString str, string filename)
{
fn = filename;
ss = str;
}
public void Start()
{
string contents = File.ReadAllText(fn);
ss.WriteString(contents);
}
}
}
I'm trying to write a remote control application to Windows Phone 7.
All goes OK, but i can not make IP scan over net.
Connected param in Socket class works badly. To use it i need to connect to any IP, then send anymessage - it's Ok. But timeout is too long - about 10 secs(for turned off Pcs).
I need to scan about 256 IPs, and 2560 seconds - is too long.
I tried to write timeout by my self. It works, but after some time application stops.
I can not understand why. No exceptions. Phone just stops attempts to connect and visual studio crashes sometimes.
If there is overflow - where can it be?
Here is some code:
(TryHost is runnung in FOR cycle. Only one start at a time, Searcher.AddHost() runs next iteration of TryHost)
AsynchronousClient:
public void TryHost(string host)
{
SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
DnsEndPoint hostEntry = new DnsEndPoint(host, _port);
// Create a socket and connect to the server
Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(SocketEventArg_Completed1);
socketEventArg.RemoteEndPoint = hostEntry;
sock.NoDelay = true;
socketEventArg.UserToken = sock;
try
{
sock.ConnectAsync(socketEventArg);
}
catch (SocketException ex)
{}
}
void SocketEventArg_Completed1(object sender, SocketAsyncEventArgs e)
{
switch (e.LastOperation)
{
case SocketAsyncOperation.Connect:
ProcessConnect1(e);
break;
case SocketAsyncOperation.SendTo:
connected = false;
ProcessSend1(e);
break;
case SocketAsyncOperation.Receive:
sended = false;
ProcessReceive1(e);
break;
default:
throw new Exception("Problems");
}
}
private void ProcessReceive1(SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
// Received data from server
string dataFromServer = Encoding.UTF8.GetString(e.Buffer, 0, e.BytesTransferred);
if (dataFromServer.IndexOf("<EOF>") > -1)
{
Searcher.AddHost(dataFromServer);
}
}
else
{
Searcher.AddHost(null);
}
}
private void ProcessSend1(SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
Socket sock = e.UserToken as Socket;
sended = true;
sock.ReceiveAsync(e);
Thread.Sleep(500);
if (sended)
{
sock.Dispose();
Searcher.AddHost(null);
}
}
else
{
Searcher.AddHost(null);
}
}
private void ProcessConnect1(SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
byte[] buffer = Encoding.UTF8.GetBytes("Knock" + "!" + sessionId + "<EOF>");
e.SetBuffer(buffer, 0, buffer.Length);
sock = e.UserToken as Socket;
connected = true;
sock.SendToAsync(e);
e.ConnectSocket.NoDelay = false;
Thread.Sleep(500);
if (connected)
{
sock.Dispose();
}
}
else
{
sock.Dispose();
Searcher.AddHost(null);
}
}
i'm using static class Searcher. UI button starts search from StartSearch() metod wich prepares class to search, and run methods in AsyncClient variable. When AssyncClient request is timed out or answered by host, AssyncClient runs AddHost() method
and Searcher prepares next IP, then start TryHost() again
static Searcher:
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;
using System.Threading;
namespace PivotApp1 {
class PartedIp
{
public string FirstPart;
public string LastPart;
public PartedIp(string first, string last)
{
FirstPart = first;
LastPart = last;
}
}
public class SearchArgs : EventArgs
{
private List<string> message;
public SearchArgs(List<string> msg)
{
message = msg;
}
public List<string> Message
{
get { return message; }
}
}
public static class Searcher
{
static bool searching = false;
static string phoneIp = "";
static string ipTemplate = "";
static int currentLookingIp;
static int stopIp;
static List<string> answers = new List<string>();
static AsynchronousClient newC;
static int chBound = 255;
static int lwBound = 255;
public static event EventHandler SearchComplete = delegate { };
public static void SayItsOver(List<string> message)
{
SearchComplete(null, new SearchArgs(message));
}
static AsynchronousClient searcher;
static string CheckIp()
{
string phoneIp = null;
try
{
MyIPAddress finder = new MyIPAddress();
finder.Find((address) =>
{
phoneIp = address == null ? "Unknown" : address.ToString();
});
}
catch (Exception e)
{
throw new Exception();
}
if (phoneIp == "Unknown")
{
return null;
}
else
{
return phoneIp;
}
}
static PartedIp PrepareForSearch(string phoneIp)
{
IPAddress ipForTest = new IPAddress(10);
if (IPAddress.TryParse(phoneIp, out ipForTest))
{
string[] splittedIp = phoneIp.Split('.');
PartedIp phonePartedIp = new PartedIp(splittedIp[0] + '.' + splittedIp[1] + '.' + splittedIp[2] + '.', splittedIp[3]);
return phonePartedIp;
}
else return null;
}
public static void StartSearch(AsynchronousClient newC)
{
phoneIp = CheckIp();
if (phoneIp != null)
{
searching = true;
newC = newC1;
PartedIp partedIp = PrepareForSearch(phoneIp);
ipTemplate = partedIp.FirstPart;
stopIp = Int32.Parse(partedIp.LastPart);
currentLookingIp = stopIp - 1;
newC.TryHost(ipTemplate + currentLookingIp);
}
else
Deployment.Current.Dispatcher.BeginInvoke(() => {
MessageBox.Show("Error in Ip detection");
});
}
static void NextHost()
{
if (searching)
{
currentLookingIp--;
if (currentLookingIp == 0)
currentLookingIp = 255;
}
}
static public void AddHost(string answer)
{
if (searching)
{
if (answer != null)
{
answers.Add(answer);
}
NextHost();
if (currentLookingIp == stopIp)
{
SayItsOver(answers);
searching = false;
}
else
{
newC.TryHost(ipTemplate + currentLookingIp);
}
}
}
} }
I debugged this a lot of time. My start ip = 192.168.0.103. My Server Ip = 192.168.0.100.
Search working perfectly, until 192.168.0.19(no PCs here). Even if i start my search from 192.168.0.20 it crashed.
Another dead zone is 192.168.0.1 and next 192.168.0.255.
Also - manual starting of TryHost() works fine. Problems begin when I'm trying to automate search.
What's wrong?
I spent a few days on it and just do not know what to do.
This is one of my first issues. Whenever I exit out the program, tcpClient.Connect() takes forever to close. I've tried a ton of things, and none of them seem to work.
Take a look at the CreateConnection() thread, if the client isn't connected yet... and I close the program, it takes forever to close. If it IS connected, it closes immediately. I know this can be done with some kind of timeout trick, but i've tried a few and none of them worked.
Please provide a code example if you can.
Also, is there any good tutorial out there for C# on reading/writing the actual bytes with a buffer instead of this version that just does masterServer.writeLine() and masterServer.readline() or are they both just as efficient?
If you see anything else to help me improve this... by all means, go ahead. I'm trying to teach myself how to do this and I have no help, so don't let me go on doing something wrong if you see it!!! Thanks guys!
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;
namespace RemoteClient
{
public partial class Form1 : Form
{
private int MyPort = 56789;
private IPAddress myIp = IPAddress.Parse("210.232.115.79");
private IPAddress serverIp = IPAddress.Parse("72.216.18.77"); // Master Server's IP Address
public static TcpClient masterServer = new TcpClient();
private StreamWriter responseWriter;
private StreamReader commandReader;
private Thread connectionThread;
private Thread commandsThread;
private bool RequestExitConnectionThread { get; set; }
private delegate void AddMessageDelegate(string message, int category);
private delegate void ConnectedDelegate();
private bool isConnected { get; set; }
public Form1()
{
InitializeComponent();
isConnected = false;
}
private void LogMessage(string message, int category)
{
if (category == 1)
{
ListViewItem item = new ListViewItem(message);
item.BackColor = Color.LightGreen;
item.UseItemStyleForSubItems = true;
Log.Items.Add(item).SubItems.Add(DateTime.Now.ToString());
}
if (category == 2)
{
ListViewItem item = new ListViewItem(message);
item.BackColor = Color.Orange;
item.UseItemStyleForSubItems = true;
Log.Items.Add(item).SubItems.Add(DateTime.Now.ToString());
}
if (category == 3)
{
ListViewItem item = new ListViewItem(message);
item.BackColor = Color.Yellow;
item.UseItemStyleForSubItems = true;
Log.Items.Add(item).SubItems.Add(DateTime.Now.ToString());
}
if (category == 0)
{
Log.Items.Add(message).SubItems.Add(DateTime.Now.ToString());
}
}
private void Connected()
{
LogMessage("Found and Accepted Master Server's connection. Waiting for reply...",1);
Status.Text = "Connected!";
Status.ForeColor = Color.Green;
commandsThread = new Thread(new ThreadStart(RecieveCommands));
sendClientInfo();
}
private void exitButton_Click(object sender, EventArgs e)
{
Disconnect();
exitButton.Enabled = false;
exitButton.Text = "Closing...";
if (connectionThread != null)
{
while (connectionThread.IsAlive)
{
Application.DoEvents();
}
}
this.Close();
}
private void Form1_Load(object sender, EventArgs e)
{
Connect();
}
private void Disconnect()
{
RequestExitConnectionThread = true;
if (masterServer != null)
masterServer.Close();
if (connectionThread != null)
connectionThread.Abort();
LogMessage("Closing Client. Please wait while Program threads end.", 2);
}
private void Disconnected()
{
Status.Text = "Disconnected";
Status.ForeColor = Color.Red;
Connect();
}
private void Connect()
{
LogMessage("Attempting to connect to Master Server...", 1);
connectionThread = new Thread(new ThreadStart(CreateConnection));
connectionThread.Start();
}
private void CreateConnection()
{
int i = 1;
bool success = false;
while (!success)
{
try
{
using (masterServer = new TcpClient())
{
IAsyncResult result = masterServer.BeginConnect(serverIp, MyPort, null, null);
success = result.AsyncWaitHandle.WaitOne(1000, false);
}
if (success)
{
BeginInvoke(new ConnectedDelegate(this.Connected), new object[] {});
break;
}
else
{
Thread.Sleep(2000);
BeginInvoke(new AddMessageDelegate(LogMessage), new object[] { "Connection Retry # " + i.ToString() + ". Master Server hasn't been started yet.", 3 });
}
}
catch
{
MessageBox.Show("Error!");
}
i++;
}
}
private void RecieveCommands()
{
MessageBox.Show("Hello!");
commandReader = new StreamReader(masterServer.GetStream());
string CommandResponse = commandReader.ReadLine();
string Command = null;
if (CommandResponse != null)
MessageBox.Show("Recieved Command that was NOT null!");
if (CommandResponse != null)
{
MessageBox.Show("Recieved null response!");
BeginInvoke(new AddMessageDelegate(LogMessage), new object[] { "Disconnected From Master Server. Reason: Recieved Null response.", 1 });
Disconnected();
}
else if (CommandResponse.StartsWith("0"))
{
MessageBox.Show("Recieved 0 as a response!");
Command = CommandResponse.Substring(2).Trim();
isConnected = false;
BeginInvoke(new AddMessageDelegate(LogMessage), new object[] { "Disconnected From Master Server. Reason: " + Command, 1 });
}
else if (CommandResponse.StartsWith("1"))
{
MessageBox.Show("Recieved 1 as a response!");
isConnected = true;
BeginInvoke(new AddMessageDelegate(LogMessage), new object[] { "Connected to Master Server Successfully.", 1 });
}
}
//************************** RESPONSE'S BELOW HERE ************************* \\
private void sendClientInfo()
{
responseWriter = new StreamWriter(masterServer.GetStream());
responseWriter.WriteLine(myIp.ToString());
responseWriter.Flush();
}
}
}
Sorry, after testing it: NO, it does not use an async waithandle, it blocks the process :(
I prefer this solution, which also blocks the process but only by the period you specify, in this case 5 seconds:
using (TcpClient tcp = new TcpClient())
{
IAsyncResult ar = tcp.BeginConnect("127.0.0.1", 80, null, null);
System.Threading.WaitHandle wh = ar.AsyncWaitHandle;
try
{
if (!ar.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5), false))
{
tcp.Close();
throw new TimeoutException();
}
tcp.EndConnect(ar);
}
finally
{
wh.Close();
}
}
From: http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/2281199d-cd28-4b5c-95dc-5a888a6da30d
The following example uses both async connection and async timeout control:
var tcp = new TcpClient();
var ar = tcp.BeginConnect(Ip, Port, null, null);
Task.Factory.StartNew(() =>
{
var wh = ar.AsyncWaitHandle;
try
{
if (!ar.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5), false))
{
// The logic to control when the connection timed out
tcp.Close();
throw new TimeoutException();
}
else
{
// The logic to control when the connection succeed.
tcp.EndConnect(ar);
}
}
finally
{
wh.Close();
}
});
connect with timeout of 2000 ms:
AutoResetEvent connectDone = new AutoResetEvent( false );
TcpClient client = new TcpClient();
client.BeginConnect(
"127.0.0.1", 80,
new AsyncCallback(
delegate( IAsyncResult ar ) {
client.EndConnect( ar );
connectDone.Set();
}
), client
);
if( !connectDone.WaitOne( 2000 ) ) {
Console.WriteLine( "network connection failed!" );
Environment.Exit( 0 );
}
Stream stream = client.GetStream();
Adding a check within your connection process to cancel it if the program is exiting should help.
Try adding this in CreateConnection() inside your while(!success) loop but before your try block:
if(RequestExitConnectionThread)
{
break;
}
Here's an example of an asynchronous BeginConnect() call:
myTcpClient.BeginConnect("localhost", 80, OnConnect, null);
OnConnect function:
public static void OnConnect(IAsyncResult ar)
{
// do your work
}