SSH.NET Verbose Mode - c#

I am trying to print more logs on the console while running my SSH.NET app, I know for OpenSSH client you can simply add ssh -vvv to get all traces
Is there anything similar to SSH.NET client as well?

Here is a custom ShellStream wrapper that has provision for logging. It also has other custom features for my main use, which is a CLI wrapper for network switch configuration.
public static class SshClientExt {
public static ExtShellStream CreateExtShellStream(this SshClient sc, string termName, uint cols, uint rows, uint width, uint height, int bufSize) =>
new ExtShellStream(sc.CreateShellStream(termName, cols, rows, width, height, bufSize));
}
public class ExtShellStream : IDisposable {
static Regex reEscVT100 = new Regex("\x1B\\[[^A-Z]+[A-Z]", RegexOptions.Compiled);
static TimeSpan ReadTimeout = new TimeSpan(0, 0, 10);
public bool Debug = false;
ShellStream ssh;
StreamReader sr;
StreamWriter sw;
public ExtShellStream(ShellStream anSSH) {
ssh = anSSH;
sr = new StreamReader(ssh);
sw = new StreamWriter(ssh);
}
public List<string> ReadLinesUpTo(string prompt, TimeSpan? timeout = null) {
if (Debug) {
Console.WriteLine($"{DateTime.Now:HH:mm:ss.ff}: >>>ReadLinesUpTo(\"{prompt}\", {timeout:%s})");
Console.WriteLine($"{DateTime.Now:HH:mm:ss.ff}: " + new String('v', 60));
}
var ans = new List<string>();
var now = DateTime.Now;
do {
var line = sr.ReadLine();
if (line != null) {
line = line.Remove(reEscVT100).TrimEnd();
if (Debug)
Console.WriteLine($#"<""{line}""");
if (line.EndsWith(prompt)) {
if (Debug)
Console.WriteLine($"{DateTime.Now:HH:mm:ss.ff}: Found prompt, done reading");
break;
}
ans.Add(line);
if (ssh.Length < 240) { // wait for more lines to come in
Thread.Sleep(50);
}
now = DateTime.Now; // reset timeout while data is available
}
else
Thread.Sleep(250); // if no prompt, wait for more data until timeout
} while (!timeout.HasValue || DateTime.Now - now <= timeout);
if (Debug) {
Console.WriteLine($"{DateTime.Now:HH:mm:ss.ff}: " + new String('^', 60));
Console.WriteLine($"{DateTime.Now:HH:mm:ss.ff}: <<<ReadLinesUpTo(\"{prompt}\")");
}
return ans;
}
static TimeSpan DumpTimeout = TimeSpan.FromSeconds(0.1);
public void DumpLines() => ReadLinesUpTo("#", DumpTimeout);
public void Send(string toSend, bool dumpLines = false) {
if (Debug)
Console.WriteLine($"Send(\"{toSend}\", {dumpLines})");
sw.Write(toSend);
sw.Flush();
if (dumpLines)
DumpLines();
}
public IEnumerable<string> DoCommand(string cmd, TimeSpan? timeout, string prompt) {
sr.DiscardBufferedData();
if (Debug)
Console.WriteLine($"Write>\"{cmd}\\r\"");
sw.Write(cmd);
Send("\r");
while (!ssh.DataAvailable)
Thread.Sleep(250);
return ReadLinesUpTo(prompt, timeout).Select(l => l.StartsWith(cmd) ? l.Substring(cmd.Length) : l);
}
#region IDisposable Support
private bool disposedValue = false; // To detect redundant calls
protected virtual void Dispose(bool disposing) {
if (!disposedValue) {
if (disposing) {
// prevent double dispose
// don't dispose of sr or sw: their only resource is ssh
ssh.Dispose();
}
disposedValue = true;
}
}
// This code added to correctly implement the disposable pattern.
public void Dispose() {
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
Dispose(true);
}
#endregion
}
Here is how I create it in the program:
SSHStream = SSHClient.CreateExtShellStream("dumb", 240, 120, 512, 0, 65536);

Related

ThreadPool.RegisterWaitForSingleObject, HttpWebRequest, Proxy c# (.NET) Memory Leak

I have troubles with my .NET web scraping software for http://mydataprovider.com/ service due to Memory Leak.
How my app works: it checks 10000 proxy servers for LIVE status.
Many proxies are broken so I have to filter them and to leave only active proxies (timeout response for live proxy is 3 seconds).
And I have to do it quickly (1 process starts ~80 threads).
I used WebClient class Firstly, but Timeout property does not effect right when I set it. I used HttpWebRequest Timeout, but it also did not help me with timeout.
I discovered at SO that I could use ThreadPool.RegisterWaitForSingleObject class for right Timeout processing (find below class HttpWebRequest_BeginGetResponse what I developed ) but it has troubles with memory leak and I did not find way how to fix it,
I tested in with .net 4.0 & 4.6.2 - behaviours are the same....
If any idea, help me, please.
Here is Code of class that is responsible for proxy activities:
using System;
using System.Net;
using System.IO;
using System.Text;
using System.Threading;
using System.Collections.Generic;
namespace ECommercePriceWebTaskManager
{
//read this http://stackoverflow.com/questions/1783031/c-sharp-asynchronous-operation
/*
BeginInvoke You tell the program what you need to be done (the delegate), what to call when it's done (callback), and what to do it with (state). You get back an IAsyncResult, which is the object that you need to give it back in order to receive your result. You can then do other stuff, or use the WaitHandle in the IAsyncResult to block until the operation's done.
Callback: When the asynchronous operation finishes, it will call this method, giving you the same IAsyncResult as before. At this point, you can retrieve your state object from it, or pass the IAsyncResult to EndInvoke.
EndInvoke: This function takes the IAsyncResult and finds the result of the operation. If it hasn't finished yet, it'll block until it does, which is why you usually call it inside the callback.
This is a pattern that's often used all over the framework, not just on function delegates. Things like database connections, sockets, etc. all often have Begin/End pairs.
*/
public class HttpWebRequest_BeginGetResponse_RequestState
{
public ManualResetEvent allDone = new ManualResetEvent(false);
public byte[] BufferRead;
public HttpWebRequest request;
public HttpWebResponse response;
public Stream responseStream;
public string Html;
public IAsyncResult ResponseIAsyncResult = null;
public IAsyncResult ReadIAsyncResult = null;
public List<Exception> Exceptions = new List<Exception>();
}
public class HttpWebRequest_BeginGetResponse
{
const int BUFFER_SIZE = 10240;
const int DefaultTimeout = 5 * 1000;
List<byte> _bytes = new List<byte>();
Encoding _encoding = Encoding.UTF8;
HttpWebRequest_BeginGetResponse_RequestState _requestState = new HttpWebRequest_BeginGetResponse_RequestState();
RegisteredWaitHandle RWH_GetResponse = null;
RegisteredWaitHandle RWH_Read = null;
public string Load(string url, WebProxy wp, Encoding en)
{
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
httpWebRequest.Proxy = wp;
string respUrl;
return Load(httpWebRequest, en, out respUrl);
}
public string Load(HttpWebRequest httpWebRequest, Encoding en, out string respUrl)
{
respUrl = "";
_encoding = en;
try
{
_requestState.request = httpWebRequest;
_requestState.ResponseIAsyncResult = (IAsyncResult)httpWebRequest.BeginGetResponse(new AsyncCallback(GetResponse), _requestState);
RWH_GetResponse = ThreadPool.RegisterWaitForSingleObject(_requestState.ResponseIAsyncResult.AsyncWaitHandle, new WaitOrTimerCallback(GetResponseTimeout), _requestState, DefaultTimeout, true);
_requestState.allDone.WaitOne();
if (_requestState.response != null)
{
if (_requestState.response.ResponseUri != null)
{
respUrl = _requestState.response.ResponseUri.AbsolutePath;
}
}
}
catch (Exception e)
{
AddException(e);
}
AbortAll();
if (_requestState.Exceptions.Count > 0)
{
throw new Exception("BeginGetResponse .... ");
//throw new AggregateException(_requestState.Exceptions);
}
return _requestState.Html;
}
private void GetResponseTimeout(object state, bool timedOut)
{
lock (this)
{
if (timedOut)
{
AbortAll();
AddException(new Exception("BeginGetResponse timeout (Internal)"));
_requestState.allDone.Set();
}
}
}
private void GetResponse(IAsyncResult asynchronousResult)
{
lock (this)
{
try
{
_requestState.response = (HttpWebResponse)_requestState.request.EndGetResponse(asynchronousResult);
if (_requestState.allDone.WaitOne(0, false))
{
AbortAll();
return;
}
_requestState.responseStream = _requestState.response.GetResponseStream();
_requestState.BufferRead = new byte[BUFFER_SIZE];
_requestState.ReadIAsyncResult = _requestState.responseStream.BeginRead(_requestState.BufferRead, 0, BUFFER_SIZE, new AsyncCallback(Read), _requestState);
RWH_Read = ThreadPool.RegisterWaitForSingleObject(_requestState.ReadIAsyncResult.AsyncWaitHandle, new WaitOrTimerCallback(ReadTimeout), _requestState, 1000, true);
return;
}
catch (Exception e)
{
AddException(e);
}
AbortAll();
_requestState.allDone.Set();
}
}
private void ReadTimeout(object state, bool timedOut)
{
lock (this)
{
if (timedOut)
{
AbortAll();
AddException(new Exception("ReadTimeoutCallback timeout (Internal)"));
_requestState.allDone.Set();
}
}
}
private void AbortAll()
{
try
{
if (_requestState.responseStream != null)
{
_requestState.responseStream.Close();
}
}
catch { }
try
{
if (_requestState.response != null)
{
_requestState.response.Close();
}
}
catch { }
try
{
if (_requestState.request != null)
{
_requestState.request.Abort();
}
}
catch { }
if (RWH_GetResponse != null)
RWH_GetResponse.Unregister(_requestState.ResponseIAsyncResult.AsyncWaitHandle);
if (RWH_Read != null)
RWH_Read.Unregister(_requestState.ReadIAsyncResult.AsyncWaitHandle);
}
void AddException(Exception ex)
{
_requestState.Exceptions.Add(ex);
}
private void Read(IAsyncResult asyncResult)
{
lock (this)
{
try
{
int read = _requestState.responseStream.EndRead(asyncResult);
if (_requestState.allDone.WaitOne(0, false))
{
AbortAll();
return;
}
if (read > 0)
{
for (var i = 0; i < read; i++)
{
_bytes.Add(_requestState.BufferRead[i]);
}
if (RWH_Read != null)
{
RWH_Read.Unregister(_requestState.ReadIAsyncResult.AsyncWaitHandle);
}
_requestState.ReadIAsyncResult = _requestState.responseStream.BeginRead(_requestState.BufferRead, 0, BUFFER_SIZE, new AsyncCallback(Read), _requestState);
RWH_Read = ThreadPool.RegisterWaitForSingleObject(_requestState.ReadIAsyncResult.AsyncWaitHandle, new WaitOrTimerCallback(ReadTimeout), _requestState, 1000, true);
return;
}
else
{
_requestState.Html = _encoding.GetString(_bytes.ToArray());
}
}
catch (Exception e)
{
AddException(e);
}
AbortAll();
_requestState.allDone.Set();
}
}
}
}
Sometimes I can get a strange exception, look at the next image, please:
How I use HttpWebRequest_BeginGetResponse class :
var hb = new HttpWebRequest_BeginGetResponse ();
hb.Load("http://your_url_here.com");
That code was called from ~80 threads in 1 process.

(Pause) Stop download without dropping connection

I want to be able to pause a download. I can stop them by dropping the existing connections.
What I'm referring to is almost similar to what's described here: https://superuser.com/questions/170509/whats-the-difference-in-using-pause-stop-in-%C2%B5torrent
My download class:
public class Download
{
public event EventHandler<DownloadStatusChangedEventArgs> DownloadStatusChanged;
public event EventHandler<DownloadProgressChangedEventArgs> DownloadProgressChanged;
public event EventHandler DownloadCompleted;
public bool stop = true; // by default stop is true
public void DownloadFile(string DownloadLink, string Path)
{
stop = false; // always set this bool to false, everytime this method is called
long ExistingLength = 0;
FileStream saveFileStream;
if (File.Exists(Path))
{
FileInfo fileInfo = new FileInfo(Path);
ExistingLength = fileInfo.Length;
}
if (ExistingLength > 0)
saveFileStream = new FileStream(Path, FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
else
saveFileStream = new FileStream(Path, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
var request = (HttpWebRequest)HttpWebRequest.Create(DownloadLink);
request.Proxy = null;
request.AddRange(ExistingLength);
try
{
using (var response = (HttpWebResponse)request.GetResponse())
{
long FileSize = ExistingLength + response.ContentLength; //response.ContentLength gives me the size that is remaining to be downloaded
bool downloadResumable; // need it for sending empty progress
if ((int)response.StatusCode == 206)
{
Console.WriteLine("Resumable");
var downloadStatusArgs = new DownloadStatusChangedEventArgs();
downloadResumable = true;
downloadStatusArgs.ResumeSupported = downloadResumable;
OnDownloadStatusChanged(downloadStatusArgs);
}
else // sometimes a server that supports partial content will lose its ability to send partial content(weird behavior) and thus the download will lose its resumability
{
Console.WriteLine("Resume Not Supported");
ExistingLength = 0;
var downloadStatusArgs = new DownloadStatusChangedEventArgs();
downloadResumable = false;
downloadStatusArgs.ResumeSupported = downloadResumable;
OnDownloadStatusChanged(downloadStatusArgs);
// restart downloading the file from the beginning because it isn't resumable
// if this isn't done, the method downloads the file from the beginning and starts writing it after the previously half downloaded file, thus increasing the filesize and corrupting the downloaded file
saveFileStream.Dispose(); // dispose object to free it for the next operation
File.WriteAllText(Path, string.Empty); // clear the contents of the half downloaded file that can't be resumed
saveFileStream = saveFileStream = new FileStream(Path, FileMode.Append, FileAccess.Write, FileShare.ReadWrite); // reopen it for writing
}
using (var stream = response.GetResponseStream())
{
byte[] downBuffer = new byte[4096];
int byteSize = 0;
long totalReceived = byteSize + ExistingLength;
var sw = new Stopwatch();
sw.Start();
while ((byteSize = stream.Read(downBuffer, 0, downBuffer.Length)) > 0)
{
saveFileStream.Write(downBuffer, 0, byteSize);
totalReceived += byteSize;
var args = new DownloadProgressChangedEventArgs();
args.BytesReceived = totalReceived;
args.TotalBytesToReceive = FileSize;
float currentSpeed = totalReceived / (float)sw.Elapsed.TotalSeconds;
args.CurrentSpeed = currentSpeed;
if (downloadResumable == true)
{
args.ProgressPercentage = ((float)totalReceived / (float)FileSize) * 100;
long bytesRemainingtoBeReceived = FileSize - totalReceived;
args.TimeLeft = (long)(bytesRemainingtoBeReceived / currentSpeed);
}
else
{
//args.ProgressPercentage = Unknown;
//args.TimeLeft = Unknown;
}
OnDownloadProgressChanged(args);
if (stop == true)
return;
}
sw.Stop();
}
}
var completedArgs = new EventArgs();
OnDownloadCompleted(completedArgs);
saveFileStream.Dispose();
}
catch (WebException e)
{
string filename = System.IO.Path.GetFileName(Path);
Console.WriteLine(e.Message);
saveFileStream.Dispose();
return; //not needed because this is the last line of the method, but let's keep it here
}
}
public void StopDownload()
{
stop = true;
}
protected virtual void OnDownloadStatusChanged(DownloadStatusChangedEventArgs e)
{
EventHandler<DownloadStatusChangedEventArgs> handler = DownloadStatusChanged;
if (handler != null)
{
handler(this, e);
}
}
protected virtual void OnDownloadProgressChanged(DownloadProgressChangedEventArgs e)
{
EventHandler<DownloadProgressChangedEventArgs> handler = DownloadProgressChanged;
if (handler != null)
{
handler(this, e);
}
}
protected virtual void OnDownloadCompleted(EventArgs e)
{
EventHandler handler = DownloadCompleted;
if (handler != null)
{
handler(this, e);
}
}
}
public class DownloadStatusChangedEventArgs : EventArgs
{
public bool ResumeSupported { get; set; }
}
public class DownloadProgressChangedEventArgs : EventArgs
{
public long BytesReceived { get; set; }
public long TotalBytesToReceive { get; set; }
public float ProgressPercentage { get; set; }
public float CurrentSpeed { get; set; } // in bytes
public long TimeLeft { get; set; } // in seconds
}
Can anybody help me with this?
Note: I can already resume downloads, that's not what I want, if you were wondering.
In your code (you should copy it into your question, by the way), you have a loop that reads bytes from a stream. You have a flag that will stop the loop.
You do the exact same thing except for pausing instead of stopping. It could be another flag, but you will also need to know when to resume, so you need something for the loop to wait on. One fairly neat way to do this would be with a lock (mutex).
I don't know C# so I can't give you working code, but here is pseudocode for it. With your pointer to the reference docs, it looks like SemaphoreSlim is the simplest thing suitable for this purpose.
bool stop = false
bool paused = false
SemaphoreSlim pauseLock = new SemaphoreSlim(1)
method download():
while (stuff to read):
read from stream
write to file
if stop:
break
// This will do nothing if not paused, or will block if paused
pauseLock.Wait()
pauseLock.Release()
method stop():
stop = true
self.unpause() // stop waiting on lock if needed
method pause()
if not paused:
paused = true
// Note this cannot block for more than a moment
// since the download thread doesn't keep the lock held
pauseLock.Wait()
method unpause()
if paused:
paused = false
pauseLock.Release()
Of course, doing this may cause the server to drop your connection eventually (at which point you need to resume anyway, and you'll only notice this after unpausing).

While loop keeps running after break

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)

How to Communicate with two c# processes with Named Pipes for Network Interprocess

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);
}
}
}

Why does C# thread die?

This is my 1st C# project so I may be doing something obviously improper in the code below.
I am using .NET, WinForms (I think), and this is a desktop application until I get the bugs out.
UpdateGui() uses Invoke((MethodInvoker)delegate to update various GUI controls based on received serial data and
sends a GetStatus() command out the serial port 4 times a second.
Thread Read() reads the response from serial port whenever it arrives which should be near immediate.
SerialPortFixer is a SerialPort IOException Workaround in C# I found at
http://zachsaw.blogspot.com/2010/07/serialport-ioexception-workaround-in-c.html.
After one or both threads die I'll see something like
The thread 0x1288 has exited with code 0 (0x0).
in the debug code output.
Why do UpdateGui() and/or Read() eventually die?
public partial class UpdateStatus : Form
{
private readonly byte[] Command = new byte[32];
private readonly byte[] Status = new byte[32];
readonly Thread readThread;
private static readonly Mutex commandMutex = new Mutex();
private static readonly Mutex statusMutex = new Mutex();
...
public UpdateStatus()
{
InitializeComponent();
SerialPortFixer.Execute("COM2");
if (serialPort1.IsOpen)
{
serialPort1.Close();
}
try
{
serialPort1.Open();
}
catch (Exception e)
{
labelWarning.Text = LOST_COMMUNICATIONS + e;
labelStatus.Text = LOST_COMMUNICATIONS + e;
labelWarning.Visible = true;
}
readThread = new Thread(Read);
readThread.Start();
new Timer(UpdateGui, null, 0, 250);
}
static void ProcessStatus(byte[] status)
{
Status.State = (State) status[4];
Status.Speed = status[6]; // MSB
Status.Speed *= 256;
Status.Speed += status[5];
var Speed = Status.Speed/GEAR_RATIO;
Status.Speed = (int) Speed;
...
}
public void Read()
{
while (serialPort1 != null)
{
try
{
serialPort1.Read(Status, 0, 1);
if (Status[0] != StartCharacter[0]) continue;
serialPort1.Read(Status, 1, 1);
if (Status[1] != StartCharacter[1]) continue;
serialPort1.Read(Status, 2, 1);
if (Status[2] != (int)Command.GetStatus) continue;
serialPort1.Read(Status, 3, 1);
...
statusMutex.WaitOne();
ProcessStatus(Status);
Status.update = true;
statusMutex.ReleaseMutex();
}
catch (Exception e)
{
Console.WriteLine(#"ERROR! Read() " + e);
}
}
}
public void GetStatus()
{
const int parameterLength = 0; // For GetStatus
statusMutex.WaitOne();
Status.update = false;
statusMutex.ReleaseMutex();
commandMutex.WaitOne();
if (!SendCommand(Command.GetStatus, parameterLength))
{
Console.WriteLine(#"ERROR! SendCommand(GetStatus)");
}
commandMutex.ReleaseMutex();
}
private void UpdateGui(object x)
{
try
{
Invoke((MethodInvoker)delegate
{
Text = DateTime.Now.ToLongTimeString();
statusMutex.WaitOne();
if (Status.update)
{
if (Status.Speed > progressBarSpeed.Maximum)
{
Status.Speed = progressBarSpeed.Maximum;
}
progressBarSpeed.Value = Status.Speed;
labelSpeed.Text = Status.Speed + RPM;
...
}
else
{
labelWarning.Text = LOST_COMMUNICATIONS;
labelStatus.Text = LOST_COMMUNICATIONS;
labelWarning.Visible = true;
}
statusMutex.ReleaseMutex();
GetStatus();
});
}
catch (Exception e)
{
Console.WriteLine(#"ERROR! UpdateGui() " + e);
}
}
}
A thread will terminate when there's no more code to execute, or more specifically when the method you specify when you create thread returns.
Maybe serialport1 becomes null?
As for the update timer, there is a special purpose windows forms timer that runs periodically that doesn't require you to use Invoke. It's the right tool for the job

Categories

Resources