Named Pipe: First data transfer after starting the app is very slow - c#

I have a client and a server application and want to send serialized small objects from the client to the server via a Named Pipe. It works very well, apart from the very first transfer: It takes up to two seconds every time after i started the applications. Following transfers are almost instant.
Here is my Server Code:
class PipeServer
{
public static string PipeName = #"OrderPipe";
public static async Task<Order> Listen()
{
using (NamedPipeServerStream pipeServer = new NamedPipeServerStream(PipeName, PipeDirection.In, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous))
{
await Task.Factory.FromAsync(pipeServer.BeginWaitForConnection, pipeServer.EndWaitForConnection, null);
using (StreamReader reader = new StreamReader(pipeServer))
{
string text = await reader.ReadToEndAsync();
var order = JsonConvert.DeserializeObject<Order>(text);
Console.WriteLine(DateTime.Now + ": Order recieved from Client: " + order.Zertifikat.Wkn + " with price " + order.PriceItem.Price + " with time " + order.PriceItem.Time);
return order;
}
}
}
}
And here is the client:
class PipeClient
{
public static string PipeName = #"OrderPipe";
private static async Task SendAwait(Order order, int timeOut = 10)
{
using (NamedPipeClientStream pipeStream = new NamedPipeClientStream(".", PipeName, PipeDirection.Out, PipeOptions.Asynchronous))
{
pipeStream.Connect(timeOut);
Console.WriteLine(DateTime.Now + ": Pipe connection to Trader established.");
using (StreamWriter sw = new StreamWriter(pipeStream))
{
string orderSerialized = JsonConvert.SerializeObject(order);
await sw.WriteAsync(orderSerialized);
Console.WriteLine(DateTime.Now + ": Order sent.");
// flush
await pipeStream.FlushAsync();
}
}
}
public static async void SendOrder(Order order)
{
try
{
await SendAwait(order);
}
catch (TimeoutException)
{
Console.WriteLine("Order was not sent because Server could not be reached.");
}
catch (IOException e)
{
Console.WriteLine("Order was not sent because an Exception occured: " + e.Message);
}
}
}
The data being transfered is kind of a stock exchange order which is also highly time sensitive, so for me it is crucial that also the very first order works without delay.
Is there any other way to make also the first usage of the named pipe as fast as the other ones? Some sort of precompiling?
I really want to avoid additional threads checking if the connection can be established and sending dummy data every x seconds just to "warm up" the respective objects which cause the delay.
(BTW: Code is not from me, I got it from here!)

Related

C# Console application pause working until right click on Console

I'm building a c# console application which read messages from MSMQ(Microsoft Message Queuing), I expected it to run forever but after a day running it stop reading message from MSMQ until I right click on its Console, my problem seems to be alittle bit similar to this: "Console Application "pausing" c#". Bellow is the function that I'm using:
private static void downloadHandler(object args)
{
while (true)
{
while (CURRENT_ACTIVE_THREAD < MAX_THREAD)
{
DownloadController.WriteLog("Current active Thread = " + CURRENT_ACTIVE_THREAD);
Console.WriteLine("Current active Thread = " + CURRENT_ACTIVE_THREAD);
Thread.Sleep(1000);
MessageQueue messageQueue;
if (MessageQueue.Exists(messageQueuePath))
{
messageQueue = new MessageQueue(messageQueuePath);
Message requestMessage = messageQueue.Receive();
try
{
requestMessage.Formatter = new BinaryMessageFormatter();
string msg = requestMessage.Body.ToString();
if (!string.IsNullOrEmpty(msg))
{
DownloadController.WriteLog("received message with message = " + msg);
CURRENT_ACTIVE_THREAD += 1;
RequestDownload request = new RequestDownload();
request = JsonConvert.DeserializeObject<RequestDownload>(msg);
DownloadController.WriteLog("received message with contentId = " + request.contentId + "from message queue | title= " + request.contentTitle + " | url = " + request.baseURL);
DownloadController downloader = new DownloadController();
Thread t = new Thread(new ParameterizedThreadStart(downloader.findURLandDownload));
object[] objs = new object[2];
objs[0] = request;
objs[1] = "1";
t.Start(objs);
Console.WriteLine("received message with contentId = " + request.contentId);
}
}
catch (Exception ex)
{
CURRENT_ACTIVE_THREAD -= 1;
Console.WriteLine("Exception: " + ex.Message);
DownloadController.WriteLog("There is exception while trying to read message from message queue, Exception = " + ex.Message);
}
}
}
}
}
So,could anyone please tell me what the problem is? Why this happening?
It might be you're while loop. I had while loops freeze or break my applications before. Might i suggest using timers instead ? I have some links you could use for reference:
c# wait for a while without blocking
https://msdn.microsoft.com/en-us/library/system.timers.timer(v=vs.110).aspx
I do hope this fixes the problem you're having !
greatings,
Ramon.

Would like code improvement on C# TCP listener to SQL Server database app

I have built a C# console app that accepts TCP connections from GPS reporting devices I have. I built this app to collect that data and dump it into a SQL Server table.
Currently, I have the application working, but it has a bug I can't seem to figure out. As the GPS devices make connections, one out of random 1-10 successful connections give me an index out of range exception.
When I dump the raw data it does not look like something the device is sending me. Would any of you happen to know what is causing this? Also, once I get this application working correctly, it could be receiving up to 3-5k connections a minute, do you think this code could handle this?
This is the error I receive every so often, with the dump of misc data:
Image of error
This is my code:
namespace GPS2DB
{
class Program
{
static void Main(string[] args)
{
try
{
IPAddress ipAddress = IPAddress.Parse("10.71.150.253");
Console.WriteLine("Waiting for Tracker Connections...");
TcpListener listener = new TcpListener(ipAddress, 10000);
listener.Start();
while (true)
{
Socket client = listener.AcceptSocket();
Console.WriteLine("Connection accepted.");
var childSocketThread = new Thread(() =>
{
byte[] data = new byte[1024];
int size = client.Receive(data);
string gpsData = "";
for (int i = 0; i < size; i++)
{
Console.Write(Convert.ToChar(data[i]));
gpsData = gpsData + Convert.ToChar(data[i]);
}
string txt = gpsData;
string txt2 = (txt.Trim(new Char[] { '$', '#' }));
String[] values = txt2.Split(',');
//Console.WriteLine(txt2);
/*
Console.WriteLine("Unit ID: " + values[0]);
Console.WriteLine("Event Code: " + values[1]);
Console.WriteLine("UTC Date: " + values[2]);
Console.WriteLine("UTC Time: " + values[3]);
Console.WriteLine("Lat: " + values[4]);
Console.WriteLine("Long: " + values[5]);
Console.WriteLine("Speed: " + values[7]);
Console.WriteLine("Heading: " + values[11]);
Console.WriteLine("V+: " + values[16]);
Console.WriteLine("Cell Strength: " + values[17]);
Console.WriteLine("GPS Status: " + values[18]);
Console.WriteLine("Fuel Level: " + values[20]);
*/
//dump 2 database
string connectionString = "Data Source=DVT501;Initial Catalog=VehicleTracking;Persist Security Info=True;User ID=TABLE;Password=PASS";
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand cmd = new SqlCommand("INSERT INTO Data_Dump (uid, eventCode, utcDate, utcTime, lat, long, speed, heading, voltage, cellStrength, gpsStatus, fuelLevel) VALUES (#uid, #eventCode, #utcDate, #utcTime, #lat, #long, #speed, #heading, #voltage, #cellStrength, #gpsStatus, #fuelLevel)");
cmd.CommandType = System.Data.CommandType.Text;
cmd.Connection = connection;
try
{
cmd.Parameters.AddWithValue("#uid", values[0]);
cmd.Parameters.AddWithValue("#eventCode", values[1]);
cmd.Parameters.AddWithValue("#utcDate", values[2]);
cmd.Parameters.AddWithValue("#utcTime", values[3]);
cmd.Parameters.AddWithValue("#lat", values[4]);
cmd.Parameters.AddWithValue("#long", values[5]);
cmd.Parameters.AddWithValue("#speed", values[7]);
cmd.Parameters.AddWithValue("#heading", values[11]);
cmd.Parameters.AddWithValue("#voltage", values[16]);
cmd.Parameters.AddWithValue("#cellStrength", values[17]);
cmd.Parameters.AddWithValue("#gpsStatus", values[18]);
cmd.Parameters.AddWithValue("#fuelLevel", values[20]);
connection.Open();
cmd.ExecuteNonQuery();
}
catch (System.IndexOutOfRangeException e)
{
Console.WriteLine("IndexOutOfRangeException caught" + e);
Console.WriteLine(txt);
}
}
//end dump
Console.WriteLine();
client.Close();
});
childSocketThread.Start();
}
listener.Stop();
}
catch (Exception e)
{
Console.WriteLine("Error: " + e.StackTrace);
Console.ReadLine();
}
}
}
}
The error is with the incoming data, it's either a gps device that's configured to send data differently or some random tcp event. Check the port number you're using in a google search and make sure it's not reserved for something else.
This code will definitely not handle that many connections, you iterate through a byte array and convert one character at a time (use System.Text.Encoding.ASCII.GetString(byte[]) instead), you open and close a connection to the sql server within the receive block and so on. In order to handle that kind of activity you need to just read the data and put it in a bus or temp storage to be bulk processed.
You are assuming that you will read one message at a time. TCP provides a boundaryless stream of bytes. You can very well read a partial message or multiple messages.
How to deal with that depends on the format of the stream. If it is line based StreamReader.ReadLine() is a great solution.

C# Programming Unisource 4100 GPIB DMM

I am trying to read voltage measurements from my Unisource 4100 GPIB DMM. I know I can connect to the device because I get appropriate responses with the commands '*RST' and '*IDN?', however I cannot get any responses with other commands such as 'SYST:ERR?' or 'CONF:VOLT:DC 1000, 0.001'. I have tested out the code I am trying with on the Agilent 34410A and managed to get the responses I want, but not with the Unisource 4100. I am using the NI GPIB-USB-HS controller to interface with. I have included the code below. Should the SCPI commands not work for all GPIB interfaces? What changes would I have to make to elicit a response from the Unisource 4100?
I have included some code for reference:
using System;
using System.Collections.Generic;
using System.Threading;
using System.Text;
using Ivi.Visa.Interop;
namespace CsharpExample
{
class VoltageExample
{
static void Main(string[] args)
{
VoltageExample DmmClass = new VoltageExample(); //Create an instance of this class so we can call functions from Main
Ivi.Visa.Interop.ResourceManager rm = new Ivi.Visa.Interop.ResourceManager(); //Open up a new resource manager
Ivi.Visa.Interop.FormattedIO488 myDmm = new Ivi.Visa.Interop.FormattedIO488(); //Open a new Formatted IO 488 session
try
{
string DutAddr = "GPIB0::12::INSTR"; //String for GPIB
myDmm.IO = (IMessage)rm.Open(DutAddr, AccessMode.NO_LOCK, 10000, ""); //Open up a handle to the DMM with a 2 second timeout
//myDmm.IO.Timeout = 20000;
myDmm.IO.Clear(); //Send a device clear first
myDmm.WriteString("*RST", true); //Reset the device
myDmm.WriteString("*IDN?", true); //Get the IDN string
string IDN = myDmm.ReadString();
Console.WriteLine(IDN); //report the DMM's identity
myDmm.WriteString("*TST?", true); //Get the IDN string
Thread.Sleep(5000);
string TST = myDmm.ReadString();
Console.WriteLine(TST); //report the DMM's identity
myDmm.WriteString("SYST:ERR?", true); //Get the IDN string
string ERR = myDmm.ReadString();
Console.WriteLine(ERR); //report the DMM's identity
myDmm.WriteString("CONF:VOLT:DC 1000, 0.001", true);
DateTime time = DateTime.Now; //Timer to measure the time difference to get all the readings
TimeSpan diff;
Console.WriteLine("Measurement in Volts");
for(int i = 0; i<10; i++){
//Configure for DCV 100V range, 100uV resolution
myDmm.WriteString("READ?", true);
String DCVResult = myDmm.ReadString();
Console.WriteLine("DCV Reading = " + DCVResult); //report the DCV reading
DmmClass.CheckDMMError(myDmm); //Check if the DMM has any errors
Thread.Sleep(1000);
diff = DateTime.Now.Subtract(time);
//diff = DateTime.Now.Subtract(time.AddSeconds(1).AddMilliseconds(20));
Console.WriteLine("\t\t\t" + diff);
}
myDmm.WriteString("CONF:RES 100, MAX", true);
Console.WriteLine("Measurement in Ohms");
for (int i = 0; i < 10; i++)
{
//Configure for res 1000 Ohm range, 100uV resolution
myDmm.WriteString("READ?", true);
String OHMResult = myDmm.ReadString();
Console.WriteLine("Resistance Measurement = " + OHMResult); //report the DCV reading
DmmClass.CheckDMMError(myDmm); //Check if the DMM has any errors
Thread.Sleep(500);
}
}
catch (Exception e)
{
Console.WriteLine("Error occured: " + e.Message);
}
finally
{
//Close out your resources
try { myDmm.IO.Close(); }
catch{}
try{ System.Runtime.InteropServices.Marshal.ReleaseComObject(myDmm);}
catch {}
try{
System.Runtime.InteropServices.Marshal.ReleaseComObject(rm);
}
catch {}
Console.WriteLine("Press any key to continue...");
Console.ReadKey();
}
}

Append text in exclusively opened file

I am trying to implement locking scenario where same file is accessed by multiple threads at same time or at different time. While testing it seems code is overwriting the existing line instead of appending new line.
namespace SMPPService
{
public static class LogFile
{
public static void WriteErrorLog(Exception ex)
{
byte[] buf = GetBytes(DateTime.Now.ToString() + ": " + ex.Source.ToString().Trim() + "; " + ex.Message.ToString().Trim());
Lock(HttpRuntime.AppDomainAppPath + "\\Exceptions.txt",
(f) =>
{
try
{
f.Write(buf, 0, buf.Length);
}
catch (IOException ioe)
{
// handle IOException
}
}, buf);
}
public static void WriteErrorLog(string Message)
{
byte[] buf = GetBytes(DateTime.Now.ToString() + ": " + Message);
Lock(HttpRuntime.AppDomainAppPath + "\\LogFile.txt",
(f) =>
{
try
{
f.Write(buf, 0, buf.Length);
}
catch (IOException ioe)
{
// handle IOException
}
}, buf);
System.Threading.Thread.Sleep(60000);
}
public static void Lock(string path, Action<FileStream> action,byte [] lines)
{
var autoResetEvent = new AutoResetEvent(false);
while (true)
{
try
{
using (var file = File.Open(path,
FileMode.OpenOrCreate,
FileAccess.ReadWrite,
FileShare.Write))
{
action(file);
break;
}
}
catch (IOException)
{
var fileSystemWatcher =
new FileSystemWatcher(Path.GetDirectoryName(path))
{
EnableRaisingEvents = true
};
fileSystemWatcher.Changed +=
(o, e) =>
{
if (Path.GetFullPath(e.FullPath) == Path.GetFullPath(path))
{
autoResetEvent.Set();
}
};
autoResetEvent.WaitOne();
}
}
}
static byte[] GetBytes(string str)
{
byte[] bytes = new byte[str.Length * sizeof(char)];
System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
return bytes;
}
}
}
Usage
LogFile.WriteErrorLog("Requesting SMPP Client from WMAS..." + " " + "Date:" + DateTime.Now + " " + "Source Address:" + msisdn);
FileShare.Write
From MSDN:
Allows subsequent opening of the file for writing.
This is exactly the flag you do not want to use. With files the easiest way to do locking is to let the file system do it for you, use FileShare.Read (so someone can look at the log) and retry if the open fails do to a sharing violation.
Implementing your own locking like that is only going to be re-creating when the file system already does, but badly.
Also, rather than messing handling encoding yourself (getting the edge cases right is not easy):
Open as a text file with a specified encoding (UTF-8 would be my choice).
Open the file for append, so new content will always be written at the end.
There is an overload of StreanWriter's constructor that does this.
EDIT: A quick check of the reference source: this does use FileShare.Read.
You should use File.AppendAllLines instead your lock method. File.AppendAllLines is not Thread safe and you have to lock it.
private object lockObject = new object();
private string fileName = Path.Combine(HttpRuntime.AppDomainAppPath, "LogFile.txt");
public static void WriteErrorLog(string Message)
{
lock(lockObject)
{
File.AppendAllLines(fileName, new string[] { Message + "\n" });
}
}
note that File.AppendAllLines was introduced in .Net 4 and you have to use File.AppendAllText in older framework

Need help sending textbox text to the console application

Hey I'm new to coding C# and I'm trying to code a C# IRC Bot and I want to make a GUI for it so I can send chat from the GUI but I'm having problems doing so.
First off I'm opening two things, the Console app and a winform.
This code is executed within another class:
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
Here is the main code (I did not code it all):
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.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;
namespace IRCBot
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
}
class IrcBot
{
// Irc server to connect
public static string SERVER = File.ReadAllText("server.txt");
// Irc server's port (6667 is default port)
private static int PORT = 6667;
// User information defined in RFC 2812 (Internet Relay Chat: Client Protocol) is sent to irc server
private static string USER = "USER LeeSharp Bot v1 * :I'm a C# IRC bot made by LeeIzaZombie";
// Bot's nickname
private static string NICK = File.ReadAllText("nickname.txt");
// Channel to join
private static string CHANNEL = File.ReadAllText("channel.txt");
// StreamWriter is declared here so that PingSender can access it
public static StreamWriter writer;
static void Main(string[] args)
{
NetworkStream stream;
TcpClient irc;
string inputLine;
StreamReader reader;
string nickname;
try
{
irc = new TcpClient(SERVER, PORT);
stream = irc.GetStream();
reader = new StreamReader(stream);
writer = new StreamWriter(stream);
// Start PingSender thread
PingSender ping = new PingSender();
ping.Start();
Console.WriteLine("Connecting to " + SERVER);
Console.WriteLine("Port: " + PORT);
writer.WriteLine(USER);
writer.Flush();
Console.WriteLine("Nickname: " + NICK + ".");
writer.WriteLine("NICK " + NICK);
writer.Flush();
Console.WriteLine("Now joining " + CHANNEL);
writer.WriteLine("JOIN " + CHANNEL);
writer.Flush();
while (true)
{
while ((inputLine = reader.ReadLine()) != null)
{
if (inputLine.EndsWith("JOIN :" + CHANNEL))
{
nickname = inputLine.Substring(1, inputLine.IndexOf("!") - 1);
writer.WriteLine("PRIVMSG " + CHANNEL + " :" + "Hi " + nickname +
" and welcome to " + CHANNEL + " !");
writer.Flush();
// Sleep to prevent flooding :P
Thread.Sleep(2000);
}
if (inputLine.Contains(" is no longer AFK"))
{
writer.WriteLine("PRIVMSG " + CHANNEL + " :Welcome back! :D");
writer.Flush();
// Sleep to prevent excess flood
Thread.Sleep(2000);
}
if (inputLine.Contains("leebot go away"))
{
nickname = inputLine.Substring(1, inputLine.IndexOf("!") - 1);
if (nickname == "LeeIzaZombie")
{
writer.WriteLine("QUIT");
writer.Flush();
}
// Sleep to prevent excess flood
Thread.Sleep(2000);
}
/* if (inputLine.EndsWith(" joined the game."))
{
nickname = inputLine.Substring(1, inputLine.IndexOf(" joined") - 1);
nickname2 = nickname.Substring(1, nickname.IndexOf("PRIVMSG") - 1);
writer.WriteLine("PRIVMSG " + CHANNEL + " :Hey, " + nickname2 + " welcome to $server!");
writer.Flush();
// Sleep to prevent excess flood
Thread.Sleep(2000);
}*/
if (inputLine.Contains("Hey LeeBot"))
{
writer.WriteLine("PRIVMSG " + CHANNEL + " :Hey, what up?");
writer.Flush();
// Sleep to prevent excess flood
Thread.Sleep(2000);
}
Thread.Sleep(5);
if (inputLine.EndsWith("JOIN :" + CHANNEL))
{
nickname = inputLine.Substring(1, inputLine.IndexOf("!") - 1);
inputLine = nickname + " joined " + CHANNEL;
}
Console.WriteLine(inputLine);
}
// Close all streams
writer.Close();
reader.Close();
irc.Close();
}
}
catch (Exception e)
{
// Show the exception, sleep for a while and try to establish a new connection to irc server
Console.WriteLine(e.ToString());
Thread.Sleep(5000);
string[] argv = { };
Main(argv);
}
}
}
}
What I've tried to do was make a button in the Form and a Textbox and I wanted to make the button add the text into the writer in the IrcBot class like:
writer.WriteLine("PRIVMSG " + CHANNEL + " :" + textbox.Text);
writer.Flush();
But I can't get the variable "CHANNEL" from the Form, but I manualy changed it to test the writer and the writer did not work.
Basicaly I want the Form to use the console's writer, and I have no idea how to do it.
You can't access it because it's private. Change it to public and you should be able to access it from your Form1 class.
As CHANNEL is static you should access it with the class name, like this:
IrcBot.writer.WriteLine("PRIVMSG " + IrcBot.CHANNEL + " :" + textbox.Text);
IrcBot.writer.Flush();

Categories

Resources