I have an application using which I execute IMAP commands using:
TcpClient to connect to the IMAP server
SslStream to write and read commands
Problem:
Cannot read the complete ouput content from the stream
while loop on the SslStream.Read seems not to work
StreamReader.ReadLine, ReadToEnd, Read methods do not work
Sample code:
while ((l = reader.ReadLine()) != null)
{
output.AppendLine(l);
}
This code snippet would read 1 to 2 lines and hang in reader.Readline().
Workaround I tried with setting the ReadTimeout property:
try
{
_output=new byte[_tcpclient.ReceiveBufferSize];
_sslstream.Read(_output, 0, _output.Length);
textBox1.Text = Encoding.ASCII.GetString(_output);
}
catch (IOException ex)
{
textBox1.Text ="ERROR !! " + ex.Message;
}
Help:
How can I read the complete output of a command from the stream?
Note: I do not want to use any third party libraries.
The TCP stream cannot know whether the current response has finished. All it knows is whether it has just received data on the wire; it cannot know whether the next packet is going to come right now (a multi-packet response) or whether it will come much later (if the response is finished).
Instead, you need to predict when you'll get more data; you should keep reading until you receive a tagged completion response, as documented in the IMAP protocol.
However, IMAP seems to be intended to be read continuously on a background thread, since the server can send you information at any time. Therefore, you probably ought to have a separate thread which is always in ReadLine().
Related
I've tried checking the server:port with telnet and I'm getting the expected results. So either writer.Write() or reader.ReadLine() isn't working cause I get nothing from the server.
TcpClient socket = new TcpClient(hostname, port);
if (!socket.Connected) {
Console.WriteLine("Failed to connect!");
return;
}
TextReader reader = new StreamReader(socket.GetStream());
TextWriter writer = new StreamWriter(socket.GetStream());
writer.Write("PING");
writer.Flush();
String line = null;
while ((line = reader.ReadLine()) != null) {
Console.WriteLine(line);
}
Console.WriteLine("done");
EDIT: I might have found the issue. This code was based off examples I found on the web. I tried another irc server: open.ircnet.net:6669 and I got a response:
:openirc.snt.utwente.nl 020 * :Please wait while we process your connection.
It seems as if I probably need to run the reader in a Thread so it can just constantly wait for a response. However it does seem weird that the program got caught on the while loop without ever printing done to the console.
I think you need to provide further details. I'm just going to assume that because you can easily telnet to the server using the same port your problem lies in the evaluation of the Connected property...
if (!socket.Connected) {
Console.WriteLine("Failed to connect!");
return;
}
this is wrong because Microsoft clearly specifies in the documentation that the Connected property is not reliable
Because the Connected property only reflects the state of the connection as of the most recent operation, you should attempt to send or receive a message to determine the current state. After the message send fails, this property no longer returns true. Note that this behavior is by design. You cannot reliably test the state of the connection because, in the time between the test and a send/receive, the connection could have been lost. Your code should assume the socket is connected, and gracefully handle failed transmissions.
That said, you should not use this property to determine the state of the connection. Needless to say that using this property to control the flow of your console app will result in unexpected results.
Suggestion
Remove the evaluation of the Connected property
Wrap your GetStream and Write method calls in a try/catch block to handle network communication errors
reader.ReadLine() will just wait for any data to arrive. If no data arrive, it seems to hang. That's a feature of tcp (I don't like it either). You need to find out how the end of the message is defined and stop based on that end criterion. Be careful, the end of message identifier may be split into two or more lines...
RFC for ping says that the server may not respond to it & such connections has to be closed after a time. Please check the RFC: https://www.rfc-editor.org/rfc/rfc1459#section-4.6.2
I am making a .NET application which is supposed to communicate with a Java application over the sockets.
Here is the .NET code:
string str = " MSG1234";
TcpClient client = new TcpClient();
client.Connect("127.0.0.1", 8080);
byte[] msg = Encoding.UTF8.GetBytes(str);
client.Client.Send(msg);
StreamWriter sw = new StreamWriter(client.GetStream());
StreamReader sr = new StreamReader(client.GetStream());
while (true)
{
Console.WriteLine(sr.Read());
}
The problem is that the Java application wouldn't send the answer. The application is a 3rd party piece of software and I can't change it, however I have downloaded a decompiler and found the relevant piece of code in the Java class:
try {
while (this.is.available() <= 0);
body = new byte[this.is.available()];
this.is.readFully(body);
System.out.println("Message received");
} catch (Exception e) {
System.out.println("Error: " + body);
}
"is" in this case is a DataInputStream. Here is what happens:
1. I create a socket and send the message
2. I wait for response, nothing happens
3. I close the app manually - it causes the socket to expire
4. Suddenly the whole message appears in the Java application's log. That means the exception happened and there actually is something in the body.
Can you perhaps point me out where the error could be? I believe the this.is.readFully(body) line shouldn't be there, but I'm not sure. Perhaps I should send an EOF from the C# code manually, but I wasn't able to find out how.
Another, minor problem with that code is, that the first two characters of the message are stripped away, that's why I have included the two space in front of the actual message.
Thank you in advance.
EDIT
So I have tried to fill the socket with some random data and I've finally got the answer:
for (int i = 0; i < 600; i++)
{
sw.Write("some long random string");
sw.Flush();
}
This not a good solution though, because the message I send has to be exact.
Then I have tried to close the socket after relevant data has been sent by soc.Disconnect(false); which causes the Java application's log to fill with proper debug information.
Is there any way to send EOL to the socket so the Java app would stop listening and would start sending the data?
Thank you.
EDIT 2
I have tried to create a Java client to connect to the server, the same thing has happened.
Then I have created a dummy server to listen on the same port as the Java app I'm connecting too, it has also behaved the way as the Java app should and it was working.
Now I feel that my only chance is to send EOT or EOF command to the stream, but I have no idea how to do it on .NET and I wasn't able to find the answer on the internet either.
If the Java application is from a third party, chances are that you're doing something wrong. The DataInputStream.readFully(byte[]) function block the application until it has read the number of bytes that the byte array can hold, so the snippet of code you have is from the read operation.
I also see that you use the Socket.Send(byte[]) function to communicate with the Java application, I recommend you to use something higher level like StreamWriter or BinaryWriter, more less like this:
StreamWriter = new BinaryWriter(client.GetStream());
StreamWriter.Write(msg);
StreamWriter.Flush();
Can you try to flush both the StreamWriter (so it writes its buffer to the stream object) and the actual NetworkStream you got from client.GetStream() (so it sends a packet, despite the packet not being "full" yet)?
NetworkStream ns = client.GetStream();
StreamWriter sw = new StreamWriter(ns);
StreamReader sr = new StreamReader(ns);
// ...
sw.Flush();
ns.Flush();
Most likely, you are not flushing all that you need to flush. Have you tried looking at the network communication with e.g. wireshark - is the data actually going out? If not, the problem is in your .NET code.
To start I am coding in C#. I am writing data of varying sizes to a device through a socket. After writing the data I want to read from the socket because the device will write back an error code/completion message once it has finished processing all of the data. Currently I have something like this:
byte[] resultErrorCode = new byte[1];
resultErrorCode[0] = 255;
while (resultErrorCode[0] == 255)
{
try
{
ReadFromSocket(ref resultErrorCode);
}
catch (Exception)
{
}
}
Console.WriteLine(ErrorList[resultErrorCode[0] - 48]);
I use ReadFromSocket in other places, so I know that it is working correctly. What ends up happening is that the port I am connecting from (on my machine) changes to random ports. I think that this causes the firmware on the other side to have a bad connection. So when I write data on the other side, it tries to write data to the original port that I connected through, but after trying to read several times, the connection port changes on my side.
How can I read from the socket continuously until I receive a completion command? If I know that something is wrong with the loop because for my smallest test file it takes 1 min and 13 seconds pretty consistently. I have tested the code by removing the loop and putting the code to sleep for 1 min and 15 seconds. When it resumes, it successfully reads the completion command that I am expecting. Does anyone have any advice?
What you should have is a separate thread which will act like a driver of your external hardware. This thread will receive all data, parse it and transmit the appropriate messages to the rest of your application. This portion of code will give you an idea of how receive and parse data from your hardware.
public void ContinuousReceive(){
byte[] buffer = new byte[1024];
bool terminationCodeReceived = false;
while(!terminationCodeReceived){
try{
if(server.Receive(buffer)>0){
// We got something
// Parse the received data and check if the termination code
// is received or not
}
}catch (SocketException e){
Console.WriteLine("Oops! Something bad happened:" + e.Message);
}
}
}
Notes:
If you want to open a specific port on your machine (some external hardware are configured to talk to a predefined port) then you should specify that when you create your socket
Never close your socket until you want to stop your application or the external hardware API requires that. Keeping your socket open will resolve the random port change
using Thread.Sleep when dealing with external hardware is not a good idea. When possible, you should either use events (in case of RS232 connections) or blocking calls on separate threads as it is the case in the code above.
I'm trying to create a chat with file transfer application using TCPSocket and here is my code..
SENDER:
public void sendData(string message)
{
StreamWriter streamWriter = new StreamWriter(netStream); // netStream is
// connected
streamWriter.WriteLine(message);
streamWriter.WriteLine(message);
logs.Add(string.Format("Message Sent! :{0}", message));
//netStream.Flush();
streamWriter.Flush();
}
RECEIVER:
private void ReceiveData()
{
StreamReader streamReader = new StreamReader(ChatNetStream);
StringBuilder dataAppends = new StringBuilder();
bool doneTransfer = false;
string data;
while (!doneTransfer)
{
while ((data = streamReader.ReadLine()) != null)
{
dataAppends.Append(data);
}
doneTransfer = true;
//ChatNetStream.Close();
//streamReader
}
//do whatever i want with dataAppends.ToString() here..
ReceiveData()
}
the problem is i always turn into infinite loop inside this statement
while ((data = streamReader.ReadLine()) != null)
{
dataAppends.Append(data);
}
even if i put streamWriter.Flush() on my sender..
do i need to close/dispose the netStream/NetworkStream?
anyway, can i use only 1 socket or connection to send a File and send a chat at the same time..? or do i need to use a new socket connection everytime i send a file..
You get an infinite loop because StreamReader.ReadLine will only return null when the end of the stream is reached. For a network stream, "end of stream" means "the other side has closed its half of the connection". Since the other side is your client, and it keeps the connection open while waiting for the user to type in more data, you will end up with an infinite loop.
What you want to do instead is fire off an operation that only completes if there is more data to read. There are two ways to go about this: either use a blocking read operation (on a dedicated thread, so that you don't block your application's other processing while waiting for messages), or use an async (event- or callback-based) approach.
For the synchronous (blocking) approach, see the documentation on NetworkStream.Read which includes example code that shows how to check if there is incoming data and how you can read it. The one point you absolutely need to know here is that when Read returns zero, it means that all data has been read and the connection has been closed from the other side (so you should close your end as well and not loop; the client has disconnected).
For low-level async network reads, the relevant operation is NetworkStream.BeginRead, which comes with its own example.
Both approaches are lower-level than what you currently have and will require you to manually assemble data inside a buffer and decide when "enough data" (i.e. a full line) has accumulated for you to process. You will then have to carefully pull that data out of the buffer and continue.
For a higher-level approach that still allows you some degree of orchestrating things, look into using client sockets (and in particular the two sync and async options there). This functionality is introduced by the TcpClient (and server-side the corresponding TcpListener) classes.
Finally, as jValdron's comment says, you will either need a separate connection for transferring file data or engineer some custom protocol that allows you to interleave multiple kinds of data over the same network stream. The second solution is has generally more technical merit, but it will also be harder for you to implement correctly.
Checkout the BasicSend example in networkComms.net which demonstrates a simple chat application using an open source library.
I am sending and receiving bytes between a server and a client. The server regularly sends some message in the form of bytes and client receives them.
Message format is below:
{Key:Value,Key:Value,Key:Value}
Now at the client side instead of receiving this message, I am receiving multiple copies of this message which is not suitable for this.
The client is receiving like this:
{Key:Value,Key:Value,Key:Value}
{Key:Value,Key:Value,Key:Value}
{Key:Value,Key:Value,Key:Value}
{Key:Value,Key:Value,Key:Value}
{Key:Value,Key:Value,Key:Value}
{Key:Value,Key:Value,Key:Value}
{Key:Value,Key:Value,
Can someone help me figure out the problem?
Updated
This code is sending instructions.
var client = (param as System.Net.Sockets.Socket);
while (true)
{
try
{
var instructions = "{";
instructions += "Window:" + window + ",";
instructions += "Time:" + System.DateTime.Now.ToShortTimeString() + ",";
instructions += "Message:" + msgToSend + "";
instructions += "}";
var bytes = System.Text.Encoding.Default.GetBytes(instructions);
client.Send(bytes, 0, bytes.Length, System.Net.Sockets.SocketFlags.None);
}
catch (Exception ex)
{
continue;
}
}
This code is receiving at client side.
while (true)
{
try
{
var data = new byte[tcpClient.ReceiveBufferSize];
stream.Read(data, 0, tcpClient.ReceiveBufferSize);
instructions = System.Text.Encoding.Default.GetString(data.ToArray());
}
catch (Exception ex)
{
continue;
}
}
Okay, a few problems with this code:
You're using Encoding.Default, which is almost certainly not what you want to do
You're always decoding the whole string, rather than just the amount you've actually managed to read - you're ignoring the return value of stream.Read
You're just continuing after an exception, with no logging, error handling or anything
As Dean says, you're repeatedly sending the same data
Ideally, it would be useful for your messages to have a prefix saying how long each one is, in bytes. Then in the receiving side you can read that length, then loop to repeatedly read into a buffer until you've read all the data you need. Then perform the decoding.
If you can't change the protocol, you'll still need to loop round, but checking for the end delimiter ("}" presumably) explicitly - and noting that you may receive data from the next message which you'll have to store until you next want to read.
You've got:
while (true)
In the sender: it's just going to keep sending the same thing over and over...
Also, if you get an exception trying to send or receive the data, you can't just try again and expect it to work. Depending on the exact error, you might need to reestablish the connection, or it might be that the network has gone away completely. In any case, simply retrying again is almost always going to be the wrong thing to do.
Problem has figured out like Dean Harding said.
But beside you should be more clearly about "client" or "server".
Basicaly:
Only server side should wait (by a loop) for msgs. Client (sender) sends msgs when needed or in condition.
You can sending msg in loop but should control and regulate it by a "Sleep" or "Timer". In this way, you can spare resource and give more time for receiver can process msg completely.
Your are sending your data through TCP. TCP is a stream-oriented protocol, so you know the client will receive the same stream of bytes in the same order, but you loose the packet boundaries. Your protocol seems to be packet-oriented instead. Then you have the choice:
switch to a packet-oriented protocol (UDP) or
delimit the packets yourself at the receiving side (as Jon Skeet said, by looking for the delimiters).
Keep in mind that TCP has some reliability features not found in UDP. If reliability is not a concern, switch to UDP. Otherwise, finding the delimiters at the client side should be easier than implementing your own reliability layer.