I have a StreamReader listening to an IP port and running in a thread / loop, this is working correctly (C#, Visual Studio) -
ns = tc.GetStream();
sr = new System.IO.StreamReader(ns);
private void ReceiveData()
{
while (true)
{
messageId = sr.ReadLine();
bool flag = messageId.Length <= 31;
if (!flag)
{
messageId = messageId.Substring(20, 12);
m_search.m_queue.add(messageId);
}
System.Threading.Thread.Sleep(250);
flag = true;
}
}
I wish to send back some characters and so I create a StreamWriter (in a separate .cs and so I have to reference the underlying stream variable in the first .cs)
var xs = Socketclient.ns;
using (System.IO.StreamWriter sw = new System.IO.StreamWriter(xs))
{
sw.Write("TH1\r\n");
sw.Flush();
//Wait 3 secs then deactivate relay
System.Threading.Thread.Sleep(3000);
sw.Write("TH0\r\n");
sw.Flush();
}
}
Which works until it 'returns' (after the last sw.Flush();) and reports Unable to read data from the transport connection here -
messageId = sr.ReadLine();
I assume I need to run my StreamWriter in a different thread or I need some way of suspending / restarting StreamReader whilst StreamWriter runs.
According to various sites StreamWriter should not affect StreamReader but it does and seems to close the underlying stream (ns) when finished.
Thoughts appreciated.
Regards
Related
After several attempts I can't get StreamWriter to build / work corectly so I am doing something fundamentally wrong (C#, Visual Studio)
I have an exisitng TCP Client which connects and acts as a reader, this is working without fault -
private System.Net.Sockets.NetworkStream ns;
private System.IO.StreamReader sr;
private string strIP;
private string strPort;
public System.Net.Sockets.TcpClient tc;
public Socketclient(Reader.Search objSearch)
{
m_search = objSearch;
}
public void EthernetConnection()
{
try
{
bool flag = !System.IO.File.Exists(System.Windows.Forms.Application.StartupPath + "\\IPAddress.txt");
if (!flag)
{
System.IO.TextReader textReader = System.IO.File.OpenText(System.Windows.Forms.Application.StartupPath + "\\IPAddress.txt");
string s = textReader.ReadLine();
textReader.Close();
char[] chArr = new char[] { ';' };
string[] sArr = s.Split(chArr);
strPort = sArr[0];
strIP = sArr[1];
flag = strIP == System.String.Empty || strPort == System.String.Empty;
if (!flag)
{
int i = System.Convert.ToInt16(strPort);
tc = new System.Net.Sockets.TcpClient(strIP, i);
flag = !tc.Connected;
if (!flag)
{
ns = tc.GetStream();
sr = new System.IO.StreamReader(ns);
m_search.threadClient = new System.Threading.Thread(new System.Threading.ThreadStart(ReceiveData));
m_search.threadClient.Priority = System.Threading.ThreadPriority.Lowest;
m_search.threadClient.Name = "Ethernet Thread";
}
I then want to add (in another .cs which is part of the same application) a StreamWriter thread to write back some characters to the same port and then close the StreamWriter thread (leaving the reader running) -
private System.IO.StreamWriter sw;
string line = "TH1/r/n";
using (StreamWriter sw = new StreamWriter(ns));
sw.WriteLine(line);
sw.Flush();
sw.Close();
Which, somehow (I think) needs to refer back to
ns = tc.GetStream();
Any thougts appreciated
Regards
Active
this sort of question has been asked many times already.
Receving and sending data in C#
brief cut and past from example above showing sending of data
using(TcpClient tcpClient = new TcpClient("ADDRESS"))
{
NetworkStream networkStream = tcpClient.GetStream();
using(StreamWriter streamWriter = new StreamWriter(networkStream))
{
streamWriter.WriteLine(data);
}
}
The issue was the using block around StreamWriter, removing it allowed the underlying stream to continue.
I'm using a C# NetworkStream to read/write to an IP address (not a DNS address).
My program is replacing a very old assembly language program that was on a mainframe. Now it's on Windows.
I'm writing/reading less than 200 bytes. The strings end with a LineFeed character so I'm using a StreamReader.Readline() to read a response, after my Stream.Write(). On the IBM a write/read cycle took 300ms.
Now about after every 2nd or 3 read, it takes 15 seconds for the read. When I read the log of the sender it is sending the data in less than a second. For some reason I get these 15 second delays.
I'm clueless on what's happening.
p.s.
One weird thing I noticed if I set the stream read timeout to 4 seconds, it times out around 4 seconds. If I set the timeout to 10 seconds or no timeout, it times out after 15 seconds.
TcpClient tcpc = null;
NetworkStream stream = null;
StreamReader sr = null;
tcpc = new TcpClient();
tcpc.NoDelay = true;
tcpc.ExclusiveAddressUse = false;
tcpc.Connect("172.18.10.100", 4004);
stream = tcpc.GetStream();
sr = new StreamReader(stream, Encoding.ASCII);
sr.Peek();
string Message = null;
Message = "IX3543543" + '\r';
stream.Write(Encoding.ASCII.GetBytes(Message), 0, Message.Length);
string readmsg = null;
for (int i = 0; i < 4; i++)
readmsg = sr.ReadLine();
Your connection stays open as your code never free your IDisposable resources.
I think that your code should run faster if you add the using constructure.
Also you can merge declaration and assignment, like this (this is only a style comment, the main concern is `IDisposable usage)
And you can ReadToEnd your message in return, and examine it by youself after releasing the resources.
So your code could look something like this:
string response = null;
using(var tcpc = new TcpClient())
{
tcpc.NoDelay = true;
tcpc.ExclusiveAddressUse = false;
tcpc.Connect("172.18.10.100", 4004);
using (var stream = tcpc.GetStream())
using (var sr = new StreamReader(stream, Encoding.ASCII))
{
sr.Peek();
var Message = "IX3543543" + '\r';
stream.Write(Encoding.ASCII.GetBytes(Message), 0, Message.Length);
response = sr.ReadToEnd();
}
}
// examine message here
var lines = response.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
I am trying to create a "virtual printer" application in C# that receives print jobs over the network, parses the raw print data for certain information, and then saves the document into a database. A modified version of the following class is working for postscript print jobs (it saves the incoming data to a valid .prn file, just as though the printer was set to print to the "FILE:" port.) When I try to capture .XPS documents from Microsoft XPS Document Writer, though, the documents cannot be opened. Valid XPS files should also be valid ZIP files if the extension is renamed, and this doesn't work either. When I print the same document to the FILE: port and then to my application, and I compare the results in Notepad++, there is a 5-character difference in the length of the data, but it looks identical (it is not plaintext so it's difficult to look at, but the first few characters and last few characters appear to be the same). The file saved the "normal" way works fine, but the file generated by my code does not.
More generally speaking, I'm trying to receive arbitrary data through a TCP port and write it to a file. My solution is "close" but not working. I don't know what kind of encoding XPS uses, but I am using ASCII for postscript and I have tried ASCII and UTF8 for this XPS version.
Any help is greatly appreciated! Here is the relevant part of my code:
class XPSListener
{
private TcpListener tcpListener;
private Thread listenThread;
private string instanceName = "";
private string fileShare = (Settings.Default.SharedPath.Substring(Settings.Default.SharedPath.Length - 1) == #"\") ? Settings.Default.SharedPath : Settings.Default.SharedPath + #"\"; // use SharedPath setting value - append backslash if it isn't already there.
public XPSListener(string initInstanceName, Int32 initPort)
{
this.instanceName = initInstanceName;
this.tcpListener = new TcpListener(IPAddress.Any, initPort);
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.Start();
}
private void ListenForClients()
{
try
{
this.tcpListener.Start();
}
catch (Exception e)
{
MessageBox.Show("Socket Error 1 - " + e.StackTrace);
}
while (true)
{
//blocks until a client has connected to the server
TcpClient client = this.tcpListener.AcceptTcpClient();
//create a thread to handle communication with connected client
Thread clientThread = new Thread(new ParameterizedThreadStart(AcceptXPSData));
clientThread.Start(client);
}
}
private void AcceptXPSData(object client)
{
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
string tempFilePath = fileShare + "XPStemp_" + instanceName + ".oxps";
byte[] message = new byte[65536];
int bytesRead;
string input;
while (true)
{
bytesRead = 0;
try
{
//blocks until a client sends a message
bytesRead = clientStream.Read(message, 0, 65536);
Debug.WriteLine("Bytes read: " + bytesRead.ToString());
}
catch
{
//a socket error has occured
break;
}
if (bytesRead == 0)
{
//the client has disconnected from the server
break;
}
//message has successfully been received
if (instanceName != "DontPrint")
{
Debug.WriteLine(instanceName + " Receiving Data");
//ASCIIEncoding encoder = new ASCIIEncoding();
UTF8Encoding encoder = new UTF8Encoding();
using (FileStream fs = new FileStream(tempFilePath, FileMode.Append, FileAccess.Write))
{
using (StreamWriter sw = new StreamWriter(fs))
{
input = encoder.GetString(message, 0, bytesRead);
sw.Write(input);
// first capture this input and write it to an xps file. This file can be converted to PDF at a later time by Ghostscript
// but we will still have access to the temp file for parsing purposes.
}
}
}
}
tcpClient.Close();
// processXPS();
}
You have at least two problems in your code, one of them almost certainly the reason the file you write is incorrect:
You keep reopening the file you're writing to, rather than just opening it once.
You are interpreting the bytes you receive as text and then re-encoding them.
The first issue is more of an efficiency/file-locking issue than a correctness problem. But the second is a big problem.
As you seem to be aware, an XPS file is basically a .zip file. That means that while the underlying data is XML (i.e. UTF8), the file itself is a compressed binary file. You can't interpret that as text in any meaningful way.
You should simply write the bytes you read straight to the file. A better version of your code would look like this:
private void AcceptXPSData(object client)
{
string tempFilePath = fileShare + "XPStemp_" + instanceName + ".oxps";
using (TcpClient tcpClient = (TcpClient)client)
using (NetworkStream clientStream = tcpClient.GetStream())
using (FileStream fs = new FileStream(tempFilePath, FileMode.Create, FileAccess.Write))
{
clientStream.CopyTo(fs);
}
// processXPS();
}
If you actually want to monitor the I/O as it occurs, you can deal with it explicitly, but still much more simply than your code was:
private void AcceptXPSData(object client)
{
string tempFilePath = fileShare + "XPStemp_" + instanceName + ".oxps";
using (TcpClient tcpClient = (TcpClient)client)
using (NetworkStream clientStream = tcpClient.GetStream())
using (FileStream fs = new FileStream(tempFilePath, FileMode.Create, FileAccess.Write))
{
byte[] message = new byte[65536];
int bytesRead;
while ((bytesRead = clientStream.Read(message, 0, message.Length)) > 0)
{
fs.Write(message, 0, bytesRead);
// Add logging or whatever here
}
}
// processXPS();
}
Note that if you want to handle exceptions, you need to handle only those you specifically expect might happen, and for which you have a reasonable way to deal with. Bare catch clauses, or broad catch (Exception) should be avoided in code like this.
I've written a very small application to get a feeling for TCP latencies on our local network. That's where I encountered a very strange delay for certain package sizes that I could up to now not relate to a bug of mine.
Using the code below, I get sub-millisecond ping/pong times for all DataLengths up to 100 kiB, with one strange exception: if DataLength is between about 1010 and 2400 bytes, there seems to be a fixed 400ms delay added to that for no reason I can see.
Where does this long delay come from?
Client code
using (var client = new TcpClient())
{
client.Connect(Server); // Server is set somewhere else
var stream = client.GetStream();
var writer = new StreamWriter(stream, Encoding.UTF8) { AutoFlush = true };
var reader = new StreamReader(stream, Encoding.UTF8);
Stopwatch stopwatch = new Stopwatch();
string data = "".PadLeft(DataLength, 'T');
for (int i = 0; i < NumberOfPings; i++)
{
stopwatch.Restart();
writer.WriteLine(data);
reader.ReadLine();
// record elapsed time
}
}
Server code
while (true)
{
var client = tcpListener.AcceptTcpClient();
var stream = client.GetStream();
var reader = new StreamReader(stream, Encoding.UTF8);
var writer = new StreamWriter(stream, Encoding.UTF8) { AutoFlush = true };
while (client.Connected)
{
var request = reader.ReadLine();
if (request == null)
break;
writer.WriteLine(request);
}
}
This delay seems to be coming from something like Nagle's Algorithm which is used to collect multiple small packages before sending.
The problem I experienced is described in this knowledgebase article.
TcpClient has a NoDelay property that, when set to true, avoids this behaviour.
I have a system where in one end I have a device communicating with a module via RS-232.
The module is connected to a PC via TCP, and translates TCP messages to RS-232 and vice versa.
This is how I do it:
I read out every byte on the stream
build a string
compare the latter part of the string to a delimiter
then I stop reading the stream (and fire an event, though not shown here).
My current code for handling this is
string delimiter = "\r\n";
byte[] reply = new byte[1];
string replyString = string.Empty;
bool readOk = true;
int dl = delimiter.Length;
bool delimiterReached = false;
do
{
try
{
stream.Read(reply, 0, 1);
}
catch (Exception e)
{
readOk = false;
break;
}
replyString += Encoding.ASCII.GetString(reply, 0, reply.Length);
int rl = replyString.Length;
if (rl > dl)
{
string endString = replyString.Substring(rl-dl, dl);
if (endString.Equals(delimiter))
delimiterReached = true;
}
} while (!delimiterReached);
where stream is the TcpClient.GetStream()
I don't much care for the constant string building, so I was wondering if there is a better way of doing this?
Once the TCP connection is established, wrap the TcpClient stream in a StreamReader:
var reader = new StreamReader( stream, Encoding.ASCII );
Since your delimiter is \r\n, StreamReader.ReadLine will read a complete message:
var reply = reader.ReadLine();
Be careful to create the StreamReader once per TCP connection; it may read and buffer additional data from the underlying TCP stream for efficiency.