Print preview performance - c#

My question is pretty straightforward. I need to display a print preview dialog in a multi-user ERP environment. It speaks for itself that printing should be as fast as possible.
However, if I use the code below, it takes about 10! seconds before the preview is displayed and is fully generated. This is without database access or any other CPU intensive operations.
Is there any way or method to improve this performance? I'm also able to use WPF, should that be necessary.
I've noticed that if you generate the preview, close it, and then quickly generate it again, it responds much faster, about a second or two. If you then wait another 5 seconds or so, generate it again, it takes about 10 seconds again.
I'm guessing some type of caching is going on, but don't have a clue what's actually happening.
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Printing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace PrintPerformanceTests
{
public class PrintPreviewTest
{
private string printerName;
private PrintPreviewDialog printPreviewDialog1;
private PrintDocument printDocument1 = new PrintDocument();
private Random random = new Random();
public string PrinterName
{
get { return printerName; }
set { printerName = value; }
}
public PrintPreviewDialog PrintPreviewDialog
{
get { return printPreviewDialog1; }
set { printPreviewDialog1 = value; }
}
public PrintPreviewTest(string printerName, PrintPreviewDialog printPreviewDialog)
{
this.PrinterName = printerName;
this.PrintPreviewDialog = printPreviewDialog;
printDocument1.PrintPage += new PrintPageEventHandler(printDocument1_PrintPage);
}
public void GenerateRandomPrintPreview()
{
Cursor.Current = Cursors.WaitCursor;
try
{
PrintPreviewDialog.Document = printDocument1;
PrintPreviewDialog.ShowDialog();
}
catch (Exception exc)
{
Cursor.Current = Cursors.Default;
MessageBox.Show(exc.ToString());
}
finally
{
Cursor.Current = Cursors.Default;
}
}
void printDocument1_PrintPage(object sender, PrintPageEventArgs e)
{
e.Graphics.PageUnit = GraphicsUnit.Millimeter;
using(Font f = new Font("Arial", 10f))
{
for (int i = 0; i < 20; i++)
{
string txt = "Random string " + i.ToString();
e.Graphics.DrawString(txt, f, Brushes.Black, new PointF(random.Next(10, 200), random.Next(10,280)));
}
}
e.HasMorePages = false;
}
}
}
usage:
PrintPreviewTest pt = new PrintPreviewTest(tbPrinter.Text, printPreviewDialog);
pt.GenerateRandomPrintPreview();

In my experience this startup delay is related to initialization of printer parameters. When you set printer name (especially network printer name) and create print preview dialog, it first connects to the specified printer and checks it's settings (paper size etc.). It takes a lot of time. The only way (IMHO) to overcome this issue is to create your own print preview dialog that initializes printer settings in separate thread.

Related

OpenCvSharp VideoWriter writes an empty video

I am trying to read a vide file, resize the frames and write them to an output file:
using System;
using System.Drawing;
using System.Windows.Forms;
using OpenCvSharp;
using OpenCvSharp.Extensions;
namespace VideoProcessing
{
public class Player
{
private VideoCapture capture;
private VideoWriter writer;
private Mat matInternal;
public Bitmap bmInternal;
private bool bIsPlaying = false;
public Timer MyTimer = new Timer();
const string outname = "output.avi";
OpenCvSharp.Size dsize = new OpenCvSharp.Size(640, 480);
public void InitPlayer(string videoName)
{
capture = new VideoCapture(videoName);
writer = new VideoWriter(outname, FourCC.MJPG, capture.Fps, dsize);
matInternal = Mat.Zeros(dsize, MatType.CV_8UC3);
bmInternal = matInternal.ToBitmap();
var delay = 1000 / (int)capture.Fps;
MyTimer.Interval = delay;
MyTimer.Tick += new EventHandler(mk_onTick());
MyTimer.Start();
}
private Action<object, EventArgs>
mk_onTick()
{
return (object sender, EventArgs e) =>
{
capture.Read(matInternal);
if (matInternal.Empty())
{
Console.WriteLine("Empty frame!");
}
else
{
matInternal.Resize(dsize);
bmInternal = matInternal.ToBitmap();
writer.Write(matInternal);
}
};
}
public void Dispose()
{
capture.Dispose();
writer.Dispose();
}
}
}
This is executed in my main function as follows:
using System;
using System.Drawing;
using OpenCvSharp;
using OpenCvSharp.Extensions;
namespace VideoProcessing
{
internal class Program
{
private static void Main(string[] args)
{
var videoName = "input.mp4";
var pl = new Player();
pl.InitPlayer(videoName);
// Some other code that executes in the meantime
pl.Dispose();
}
}
}
The writer can get disposed before the video finishes, which is fine because this will later be adapted for live camera video streams. However, the VideoWriter here produces an apparently empty, 0 second long video file. The codec setting does not produce any errors, and the video is only at 24 FPS so it should not be running into any speed issues. What could be causing this?
I think you have to delay your main thread.
By adding Thread.Sleep(2000) for instance.
I try your code with camera and it works well.

Launching application from server creates Open File for lifetime of application

I launch a program located on one of my file servers. After launching the program it shows as an Open file in Computer Management.
Is there a way I can close this open file while my program runs so it doesn't show up in Computer Management?
My code is below. I'd be happy to take suggestions on improving my program, but I'm really just looking for a solution to stop all these Open Files from appearing.
Program.cs -- starts the program, handles logic to launch my application
using System;
using System.Windows.Forms;
using System.Diagnostics;
namespace IT_TaskbarApp
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
string programName = "TEG System Helper";
//Process[] proc = Process.GetProcessesByName(programName);
if (Process.GetProcessesByName(programName).Length == 1)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Primary());
}
else
{
foreach (Process p in Process.GetProcessesByName(programName))
{
if (Process.GetCurrentProcess().Id != p.Id)
{
p.CloseMainWindow();
p.Close();
p.Kill();
p.Dispose();
}
}
Main();
}
}
}
}
Primary.cs -- creates an icon in the system icons which I can use to send notifications and easily access utilities within our organization
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Threading;
using System.Windows.Forms;
namespace IT_TaskbarApp
{
public partial class Primary : Form
{
private NotifyIcon notifyIcon;
private ContextMenu contextMenu;
private MenuItem[] menuItem = new MenuItem[8];
private IContainer components;
//private Boolean SendNotices = true;
private DateTime startTime = DateTime.Now;
private DateTime currentTime;
private Icon tegroupIcon = new Icon(Assembly.GetExecutingAssembly().GetManifestResourceStream("IT_TaskbarApp.Src.tegroup.ico"));
private string prevNotification = "";
private bool isRunning = true;
private BackgroundWorker bgNotify = new BackgroundWorker();
private const string programName = "TEG System Helper";
public Primary()
{
this.FormClosing += Primary_FormClosing; //remove ghost icon in taskbar
ForeColor = Color.Blue;
BackColor = Color.Green;
components = new Container();
contextMenu = new ContextMenu();
for (int i = 0; i < menuItem.Length; i++)
{
menuItem[i] = new MenuItem();
menuItem[i].Index = i;
menuItem[i].Click += new EventHandler(LoadProcess);
}
menuItem[0].Text = programName;
menuItem[1].Text = "Knowledge Base";
menuItem[2].Text = "Policies";
menuItem[3].Text = "Feedback";
menuItem[4].Text = "Global Shop Search";
menuItem[5].Text = "-";
menuItem[6].Text = "Submit Ticket";
menuItem[7].Text = "Send Email";
//initialize contextMenu
contextMenu.MenuItems.AddRange(menuItem);
// Create the NotifyIcon.
notifyIcon = new NotifyIcon(components)
{
Icon = tegroupIcon,
BalloonTipIcon = new ToolTipIcon(),
ContextMenu = contextMenu, //the menu when right clicked
Text = programName,
Visible = true,
BalloonTipTitle = programName,
};
notifyIcon.DoubleClick += new EventHandler(Icon_DoubleClick);
InitializeComponent();
bgNotify.WorkerSupportsCancellation = true;
bgNotify.WorkerReportsProgress = true;
bgNotify.DoWork += NotifyUser;
bgNotify.ProgressChanged += SendNotice;
//bgNotify.RunWorkerCompleted += BgNotify_RunWorkerCompleted; //enable this to perform an action when the thread dies
bgNotify.RunWorkerAsync();
//Thread tNotify = new Thread();
}
#region SupportedFunctions
private void NotifyUser(object Sender, EventArgs e)
{
Console.WriteLine("enter");
while (isRunning)
{
currentTime = DateTime.Now;
#region DisplayCurrentTime
if (currentTime.Hour < 10 || currentTime.Minute < 10)
{
if (currentTime.Hour < 10)
{
if (currentTime.Minute < 10)
{
Console.WriteLine("0{0}:0{1}", currentTime.Hour, currentTime.Minute);
}
else
{
Console.WriteLine("0{0}:{1}", currentTime.Hour, currentTime.Minute);
}
}
else
{
if (currentTime.Minute < 10)
{
Console.WriteLine("{0}:0{1}", currentTime.Hour, currentTime.Minute);
}
}
}
else
{
Console.WriteLine("{0}:{1}", currentTime.Hour, currentTime.Minute);
}
#endregion
FileStream fs = new FileStream("\\\\te-admin\\public\\TaskbarNotices.txt", FileMode.Open);
StreamReader sr = new StreamReader(fs);
string noticeText = sr.ReadToEnd();
sr.Close();
fs.Close();
if (noticeText != "" && noticeText != prevNotification)
{
prevNotification = noticeText;
bgNotify.ReportProgress(1);
}
else
{
bgNotify.ReportProgress(2);
}
Console.WriteLine("Inner Text: {0} TOF: {1}", noticeText, noticeText != "");
Thread.Sleep(10000);
}
}
private void SendNotice(object Sender, ProgressChangedEventArgs e)
{
if (e.ProgressPercentage == 1)
{
Console.WriteLine("notification sent");
this.notifyIcon.BalloonTipText = prevNotification;
this.notifyIcon.ShowBalloonTip(1500);
}
}
private void LoadProcess(object Sender, EventArgs e)
{
if (Sender is MenuItem)
{
MenuItem tempMenu = Sender as MenuItem;
string ProgramTag = "http://";
switch (tempMenu.Index)
{
case 0: //home page
ProgramTag += "teg";
break;
case 1: //docviewer
ProgramTag += "teg/docViewer";
break;
case 2: //policies
ProgramTag += "teg/Policies";
break;
case 3: //feedback
ProgramTag += "teg/Feedback";
break;
case 4: //inventory search
ProgramTag = "http://searchglobalshop/inventory/index.aspx";
break;
case 6: //submit ticket
ProgramTag = "https://timberlandgroup.on.spiceworks.com/portal/tickets";
break;
case 7: //send email
string sendto = "admin#tewinch.com";
string emailSubject = "Assistance Request";
string emailBody = "";
string mailto = string.Format("mailto:{0}?Subject={1}&Body={2}", sendto, emailSubject, emailBody);
ProgramTag = Uri.EscapeUriString(mailto);
break;
}
/*
Try to launch the choice the user made with the default processing method.
Should the default method fail we try to control how the process is run.
We open internet explorer and then we show them what to do otherwise.
*/
#region LaunchSelectedProcess
try
{
if (ProgramTag != "" && ProgramTag != "http://")
Process.Start(ProgramTag);
}
catch (System.ComponentModel.Win32Exception)
{
try
{
if (ProgramTag.StartsWith("http://") || ProgramTag.StartsWith("https://"))
Process.Start("iexplore.exe", ProgramTag);
}
catch (System.ComponentModel.Win32Exception)
{
Process.Start("control.exe", "/name Microsoft.DefaultPrograms");
string message = "";
if (tempMenu.Index <= 6)
{
message = "You must have a default browser set\n\tClick [Set Default Program]\n";
if (Environment.OSVersion.ToString().Contains("NT 10.")) //windows 10
{
message += "\tUnder [Web Browser] Edge is currently set as default\n\tClick on Microsoft Edge\n\tSelect the browser you use";
}
else //windows 7 -- "NT 6.1")
{
message += "Select the browser you use\n\tClick [Set this program as default]";
}
}
else
{
if (Environment.OSVersion.ToString().Contains("NT 10.")) //windows 10
{
message += "Please setup a default email application";
}
}
message += "\n\nIf this issue persists please contact your Administrator.\nPhone: 519-537-6262\nEmail: admin#tewinch.com";
MessageBox.Show(message, "Application Warning", MessageBoxButtons.OK, MessageBoxIcon.Information);
//if ( == DialogResult.OK)
}
}
#endregion
}
}
private void Icon_DoubleClick(object Sender, EventArgs e)
{
Process.Start("http://teg");
}
#endregion
#region BuiltFunctions
private void Primary_FormClosing(object sender, FormClosingEventArgs e)
{
notifyIcon.Icon = null;
notifyIcon.Dispose();
isRunning = false;
Dispose(true);
}
private void InitializeComponent()
{
this.SuspendLayout();
//
// Primary
//
this.Icon = tegroupIcon;
this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
this.CausesValidation = false;
this.ClientSize = new System.Drawing.Size(120, 23);
this.ControlBox = false;
this.Enabled = false;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "Primary";
this.Opacity = 0D;
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.WindowState = System.Windows.Forms.FormWindowState.Minimized;
this.ResumeLayout(false);
}
protected override void Dispose(bool disposing)
{
// Clean up any components being used.
if (disposing)
if (components != null)
components.Dispose();
base.Dispose(disposing);
}
#endregion
}
}
Instead of cancelling the program on start up, I kill the other running instances of the program. The idea is that if any issues arise with the program I just launch another instance and resolve the issues. Right now not much can go wrong but we will be developing this program to complete many more tasks in the future.
The only area I can see which would keep a file open is when I pull an Embedded Resource tegroup.ico I was looking to see if I missed something while opening this, but I couldn't see a way to close the ManifestResourceStream after reading it in.
Any tips/suggestions would be wonderful but again, I really just want to know if there's a way I can close these Open Files
Example below
Open File after app launch
I might be trying to solve something which is a known result of using Application.Run() if this is the case then please suggest alternatives I can use. My other ideas would be loading the program into memory and launching it locally, using the .exe on the server as a starting point for this method though.
I believe that Windows doesn't load an entire executable into ram. It isn't just about files from the resource section of a PE file. Portions of the exe are only loaded when referenced and even after loading everything there is to load, Windows will maintain an open file handle until the process closes. Trying to close that handle yourself is a bad idea.
c/c++ allow a "SWAPFILE" flag to be specified that tells windows to put the whole thing into the page file but I don't know how you would do that with c# and I don't know if that would even stop windows from keeping the handle open anyways (I doubt it).
If this is truly important, iffin' I were your exe... I would:
Check a mutex for an existing running instance, exit if exist
Check where I was running from.
If running from temp, set a mutex that I am running and just run.
If not running from temp, copy myself to %temp%, start that copy, and exit.
Good luck.

How to convert jpg byte array to image and display in picturebox?

I am a newbie to mono C# programming in raspbian os (pi3 b). I have taken a sample code for fingerprint scanner application in C# mono from this github link, Now I am running the same application in Raspbian os under the pi3 b board.
Now after scanning the user finger image, I want to display into my winform PictureBox.
once the application scans each finger then it will send the byte[] to the UI using the below callback method.
private void FingerPrintlib_OnEnrollImageResult(byte[] enrollImage, int count)
{
//lblinstruction.Invoke((MethodInvoker)delegate
//{
// lblinstruction.Visible = false;
//});
if (count == 0)
{
pictureBox4.Invoke((MethodInvoker)delegate
{
//pictureBox4.Image = byteArrayToImage(enrollImage);
pictureBox4.SizeMode = PictureBoxSizeMode.StretchImage;
});
}
else
{
pictureBox5.Invoke((MethodInvoker)delegate
{
//pictureBox5.Image = byteArrayToImage(enrollImage);
pictureBox5.SizeMode = PictureBoxSizeMode.StretchImage;
});
}
}
I am a newbie to mono C# programming in raspbian os (pi3 b). I have written a fingerprint scanner application in C# and using mono, I am running the same application in Raspbian os under the pi3 board.
Now after scanning the user finger image, I want to display into my PictureBox.
once the lib scans each finger then it will send the byte[] to the UI using the below callback method.
private void FingerPrintlib_OnEnrollImageResult(byte[] enrollImage, int count)
{
//lblinstruction.Invoke((MethodInvoker)delegate
//{
// lblinstruction.Visible = false;
//});
if (count == 0)
{
pictureBox4.Invoke((MethodInvoker)delegate
{
//pictureBox4.Image = byteArrayToImage(enrollImage);
pictureBox4.SizeMode = PictureBoxSizeMode.StretchImage;
});
}
else
{
pictureBox5.Invoke((MethodInvoker)delegate
{
//pictureBox5.Image = byteArrayToImage(enrollImage);
pictureBox5.SizeMode = PictureBoxSizeMode.StretchImage;
});
}
}
Image byteArrayToImage(byte[] byteArrayIn)
{
try { MemoryStream ms = new MemoryStream(byteArrayIn);
Image returnImage = Image.FromStream(ms);
return returnImage;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
return null;
}
when I execute the above code I am getting an exception like
A null reference or invalid value was found [GDI+ status:
InvalidParameter]
so how can I solve this issue and display the image file into my application?
Thanks
The code below works just fine:
using System;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
namespace ImageLoad
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
byte[] data = File.ReadAllBytes("test.jpg");
this.pictureBox1.Image = GetImage(data);
}
private static Image GetImage(byte[] data)
{
using (MemoryStream ms = new MemoryStream(data))
{
return (Image.FromStream(ms));
}
}
}
}
New Windows form project, add a picture box to form, copy test.jpg file to Debug directory and use code above. No problem. Image was loaded.

Form doesn't load in while loop

I have a class defined to get live capture from a camera, and a form button "END CAPTURE" that should halt the capture; and an typical Application.Exit() button.
However, for some reason the while loop as shown below doesn't load the form even when the condition is met. To debug this, I commented out the while loop to see if it snaps at least 1 image; and it does (as shown in fig). What makes the while loop not to load the form and show the output continuously ?
while (!terminated)
{
// CAMERA ACQUISITION CODE
}
Figure of single while loop run:
Full program for reference:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
using mv.impact.acquire;
using mv.impact.acquire.examples.helper;
namespace mv_BlueFoxControl
{
public partial class Form1 : Form
{
private bool button1WasClicked = false;
public Bitmap SnappedBitmap = null;
public static Image PersistentImage = null;
public Form1()
{
InitializeComponent();
mv.impact.acquire.LibraryPath.init(); // this will add the folders containing unmanaged libraries to the PATH variable.
Device pDev = DeviceManager.getDevice(0);// Get a pointer to the first device found
if (pDev == null)
{
Console.WriteLine("Unable to continue! No device found! Press any key to end the program.");
//Console.Read();
Environment.Exit(1);
}
Console.WriteLine("Initialising the device. This might take some time...");
try
{
pDev.open();//start the sensor
Console.WriteLine("Device opened successfully...");
}
catch (ImpactAcquireException e)
{
// throw error code if the same device is already opened in another process...
Console.WriteLine("An error occurred while opening the device " + pDev.serial +
"(error code: " + e.Message + "). Press any key to end the application...");
//Console.ReadLine();
Environment.Exit(1);
}
bool terminated = false;// Bool terminated was here.
Console.WriteLine("Press CAPTURE to end the application");
// create thread for live capture
Thread thread = new Thread(delegate()//Start live acquisition
{
DeviceAccess.manuallyStartAcquisitionIfNeeded(pDev, fi);
Request pRequest = null;
// we always have to keep at least 2 images as the display module might want to repaint the image, thus we
// can free it unless we have a assigned the display to a new buffer.
Request pPreviousRequest = null;
int timeout_ms = 500;
int cnt = 0;
int requestNr = Device.INVALID_ID;
Console.WriteLine(terminated);
while (!terminated)
{
// CAMERA ACQUISITON CODE
}
DeviceAccess.manuallyStopAcquisitionIfNeeded(pDev, fi);
// free the last potential locked request
if (pRequest != null)
{
pRequest.unlock();
}
// clear the request queue
fi.imageRequestReset(0, 0);
// extract and unlock all requests that are now returned as 'aborted'
requestNr = Device.INVALID_ID;
while ((requestNr = fi.imageRequestWaitFor(0)) >= 0)
{
pRequest = fi.getRequest(requestNr);
Console.WriteLine("Request {0} did return with status {1}", requestNr, pRequest.requestResult.readS());
pRequest.unlock();
}
});//End of thread
Console.WriteLine(" End Thread");
thread.Start();
if (button1WasClicked)
{
terminated = true;
}
Console.WriteLine("Program termination");
Console.WriteLine(terminated);
thread.Join();
}
private void button2_Click(object sender, EventArgs e)
{
Application.Exit();
}
private void button1_Click(object sender, EventArgs e)
{
button1WasClicked = true;
}
}
}
Because of thread.Join(); The application will wait that the thread ends (which will not end until you press the button) and so the constructor is never finished.
You have to initialize a Thread field and only close it when you press the button.
Try this:
public partial class Form1 : Form
{
//...
private Thread _cameraThread;
public Form1()
{
//... the previous code
_cameraThread = new Thread(delegate()//Start live acquisition
{
// thread logic
});
_cameraThread.Start();
}
private void button2_Click(object sender, EventArgs e)
{
Application.Exit();
}
private void button1_Click(object sender, EventArgs e)
{
button1WasClicked = true;
//set the flag and wait for the thread to finish
_cameraThread.Join();
Console.WriteLine("Program termination");
}
}

C# TcpClient not sending or reading 100% of data?

Hey all. I'm writing a simple client/server application (just for the experience, networking is fairly new to me) where the client sends the server data and the server outputs it to a textbox. It all works fine, except for one small detail... It seems sometimes a connection is made, but the data isn't being sent or read (can't work out which) and thus nothing is being outputted in the textbox. Every time a connection is made a counter is incremented, same thing when a data block is received. When you compare the two, the number of connections is correct but the data counter is usually lower, sometimes by as much as half. Anyway, if anyone can give me some advice or point me in the right direction, it would be greatly appreciated!
Here's the code if you require it:
(SERVER_CODE)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace Server
{
public partial class Form1 : Form
{
public int Connections = 0;
public int blocks = 0;
public int threads = 0;
public Thread MasterThread;
public TcpListener Master;
public volatile bool Run;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
public void StartMaster()
{
Master = new TcpListener(IPAddress.Any, 1986);
Master.Start();
MasterThread = new Thread(new ThreadStart(RunMaster));
MasterThread.Start();
}
public void RunMaster()
{
threads++;
label6.Text = String.Format("{0}", threads);
while (Run)
{
TcpClient client = Master.AcceptTcpClient();
Connections++;
label4.Text = String.Format("{0}", Connections);
Thread ClientThread = new Thread(new ParameterizedThreadStart(RunClient));
ClientThread.Start(client);
}
Master.Stop();
threads--;
label6.Text = String.Format("{0}", threads);
}
public void RunClient(object tcpClient)
{
TcpClient client = (TcpClient)tcpClient;
byte[] buffer = new byte[4096];
int byteCount = 0;
NetworkStream stream = client.GetStream();
threads++;
label6.Text = String.Format("{0}", threads);
while (Run)
{
try
{
byteCount = stream.Read(buffer, 0, 4096);
}
catch
{
//Connections--;
break;
}
if (byteCount == 0)
{
//Connections--;
break;
}
blocks++;
label5.Text = String.Format("{0}", blocks);
textBox1.AppendText(Encoding.ASCII.GetString(buffer, 0, byteCount) + "\r\n");
}
client.Close();
threads--;
label6.Text = String.Format("{0}", threads);
}
private void button1_Click(object sender, EventArgs e)
{
Run = true;
StartMaster();
}
private void button2_Click(object sender, EventArgs e)
{
Run = false;
}
}
}
(CLIENT_CODE)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace Client
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1986);
TcpClient client = new TcpClient();
try
{
client.Connect(endPoint);
}
catch
{
MessageBox.Show("Connect Error");
}
NetworkStream stream = client.GetStream();
byte[] data = Encoding.ASCII.GetBytes(textBox1.Text);
stream.Write(data, 0, data.Length);
stream.Flush();
client.Close();
}
}
}
Thank-you,
Tristan!.
Well, to start with you're crippling your own diagnostics with this:
catch
{
//Connections--;
break;
}
Why are you swallowing exceptions without any logging etc? Maybe an exception is being thrown, and you have no way of knowing. Ideally you should catch specific exceptions, and when you do catch an exception at least log what's going on.
At the other end of the spectrum, Wireshark should help you to work out whether the data is being sent or not.
I haven't had a thorough look at your code yet, but after a quick glance, you access variables from multiple threads without proper locking. A statement like x++; has to read the value of x, increment it, and write it back. Now if you have two threads doing this, you might run into this situation:
x = 0
Thread 1 Thread 2
------------------------
Read (0)
Read (0)
Increment (1)
Increment (1)
Write (1)
Write (1)
=> x = 1 instead of 2
If you need to access variables from multiple threads, ALWAYS synchronize unless you know exactly what you're doing. For example, create and use a synchronization object like this:
int threads = 0;
object threadSync = new object();
...
lock (threadSync) {
threads++;
}
Then only one thread may access the variable at a time and values are incremented correctly.
Edit: Another problem is that you access visible controls from a different thread than the one that created them. Early .NET versions allowed this, but the newer don't. If you need to update status messages, you need to look at the control's InvokeRequired property and if set to true, use Control.Invoke(...) to call a method that sets the property.

Categories