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);
Related
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
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'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 an application that download files from a Unix FTP server. It works fine, just have this performance problem: Files which size is <= 1K takes in average between 2084 and 2400 milliseconds to download, while applications like Filezilla download the same files in less than 1 second (per each file).
Maybe this time its OK for some average users, but is not acceptable for my application, since I need to download THOUSANDS of files.
I optimize the code as much as I could:
- The cache and buffer to read the content are created 1 time in the constructor of the class.
- I create 1 time the network credentials, and re-use on every file download. I know this is working, since for the first file it takes like 7s to download, and all subsequent downloads are on the range of 2s.
- I change the size of the buffer from 2K until 32K. I dont know if this will help or not, since the files Im downloading are less than 1K, so in theory the buffer will be fill with all the information in 1 round from network.
Maybe is not related to the network, but to the way Im writing and/or windows handles the write of the file??
Can someone please give me some tips on how to reduce the time to something similar to filezilla??
I need to reduce the time, otherwise my ftp will be running for 3 days 24 hours a day to finish its task :(
Many thanks in advance.
The code here: Its not complete, it just show the download part.
//Create this on the constructor of my class
downloadCache = new MemoryStream(2097152);
downloadBuffer = new byte[32768];
public bool downloadFile(string pRemote, string pLocal, out long donwloadTime)
{
FtpWebResponse response = null;
Stream responseStream = null;
try
{
Stopwatch fileDownloadTime = new Stopwatch();
donwloadTime = 0;
fileDownloadTime.Start();
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(pRemote);
request.Method = WebRequestMethods.Ftp.DownloadFile;
request.UseBinary = false;
request.AuthenticationLevel = AuthenticationLevel.None;
request.EnableSsl = false;
request.Proxy = null;
//I created the credentials 1 time and re-use for every file I need to download
request.Credentials = this.manager.ftpCredentials;
response = (FtpWebResponse)request.GetResponse();
responseStream = response.GetResponseStream();
downloadCache.Seek(0, SeekOrigin.Begin);
int bytesSize = 0;
int cachedSize = 0;
//create always empty file. Need this because WriteCacheToFile just append the file
using (FileStream fileStream = new FileStream(pLocal, FileMode.Create)) { };
// Download the file until the download is completed.
while (true)
{
bytesSize = responseStream.Read(downloadBuffer, 0, downloadBuffer.Length);
if (bytesSize == 0 || 2097152 < cachedSize + bytesSize)
{
WriteCacheToFile(pLocal, cachedSize);
if (bytesSize == 0)
{
break;
}
downloadCache.Seek(0, SeekOrigin.Begin);
cachedSize = 0;
}
downloadCache.Write(downloadBuffer, 0, bytesSize);
cachedSize += bytesSize;
}
fileDownloadTime.Stop();
donwloadTime = fileDownloadTime.ElapsedMilliseconds;
//file downloaded OK
return true;
}
catch (Exception ex)
{
return false;
}
finally
{
if (response != null)
{
response.Close();
}
if (responseStream != null)
{
responseStream.Close();
}
}
}
private void WriteCacheToFile(string downloadPath, int cachedSize)
{
using (FileStream fileStream = new FileStream(downloadPath, FileMode.Append))
{
byte[] cacheContent = new byte[cachedSize];
downloadCache.Seek(0, SeekOrigin.Begin);
downloadCache.Read(cacheContent, 0, cachedSize);
fileStream.Write(cacheContent, 0, cachedSize);
}
}
Sounds to me your problem is related to Nagels algorithm used in the TCP client.
You can try turning the Nagel's algorithm off and also set SendChunked to false.
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.