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.
Related
I am working with a heat cell with which i can only communicate through Ethernet. When trying to connect to it using sockets, I am stuck on waiting for the Receive() method to end.
I've checked the connection using PuTTY in raw mode and it worked just fine, I was able to send and receive messages.
This led me to believe that I needed to use some kind of raw communication as well, hence why I tried to use SharpPCap and the like. Using this, I am able to read from the cell (although I am faced with a few issues that aren't related to this post).
However, since I'm not very experienced with networking, I was wondering if there was a way to obtain the same results as when I used PuTTY's raw mode but using only Sockets ?
I've come accross this question that was left unanswered, apart from the fact that the author was advised not to use SocketType.Raw.
Below is the example from MSDN documentation that I adapted for my tests. It is supposed to send a request and then listen for the answer.
static void Main(string[] args)
{
System.Net.IPAddress host = System.Net.IPAddress.Parse("10.0.0.3");
int port = 2049;
Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
socket.Connect(host, port);
if (socket.Connected)
{
string request = "99997¶1¶1\\r";
var byteSent = Encoding.Default.GetBytes(request);
var byteReceived = new byte[256];
socket.Send(byteSent, byteSent.Length, 0);
int bytes = 0;
do
{
bytes = socket.Receive(byteReceived, byteReceived.Length, 0); // this is the line I'm being stuck on
} while (bytes > 0);
Console.WriteLine($"Result : {Encoding.Default.GetString(byteReceived)}");
Console.ReadLine();
}
else
{
Console.WriteLine("Connection Failed");
Console.ReadLine();
}
}
UPDATE
I used WireShark to take a look at what was being sent from my application. Turns out the 'CR' and 'LF' werent sent correctly. But correcting this didn't solve my problem.
I can see the server's answer to my request on WireShark, but still I can't read anything using socket.Receive(). Could it be possible that the server is faster to answer than my machine is to start listening ? I tried setting up the socket.ReceiveTimeout property and put my send/receive instructions in a loop, but still nothing returning from the Receive() statement.
The socket is in blocking mode by default (cf Socket.Blocking). That mean that, for your case, blocking until 256 byte has been read (Without timeout by default Socket.ReceiveTimeout).
You may want to set the Blocking mode to false, or set a Receive timeout in order to not block indefinitly.
Alternatively, you may want also to use async method to avoid blocking the main thread.
I am creating very simple TCP/IP communication program between Client and Server. Aim is just to exchange some string between them.
The Client Server side needs to send and receive some simple string to Server.
The problem is that it works perfectly when I send data to Sever using StreamWriter. However, when I enable the StreamReader, the while loop just hanging forever. The "Console.Write("> ");" line is only executed once at the beginning but never prompted again in the second time.
Here is the code below.
Note "_client" is already connected socket for TcpClient declared as TcpClient _client in the another part of code.
_sReader = new StreamReader(_client.GetStream(), Encoding.ASCII);
_sWriter = new StreamWriter(_client.GetStream(), Encoding.ASCII);
_isConnected = true;
String sData = null;
while (_isConnected)
{
Console.Write("> ");
sData = Console.ReadLine();
_sWriter.WriteLine(sData);
_sWriter.Flush();
//If I commnet out these two lines of code below, then there is no problem. Program works fine.
String sDataIncomming = _sReader.ReadLine();
Console.WriteLine(sDataIncomming);
//While loop just hanging after this line.
//It does not even break the while loop.
//Either while loop goes back to the top of the line.
//Just stuck here. Why ?
}
If I comment out the two lines of code for StreamReader, the program works perfect again.
How can I fix this problem ? Sharing your knowledge will be really appreciated.
Kind regards.
I think I have found a partial answer to this problem.
I think if the socket does not receive anything from Server, it seems that this code line stuck forever.
String sDataIncomming = _sReader.ReadLine();
So new question is that how can I check if some string is coming from server or not ?
If no string is coming from server, then just stop listening from the socket.
I am new to both C# and to client-server programming. Right now, for class, I'm attempting to create an FTP client without using any pre-established FTP libraries. I feel like I have the project down for the most part, however I'm running into a problem when I make more than one call that requires use of the data port (list, retr, etc.) Here is a sample of the code that is breaking:
writer.WriteLine(portcmd);
writer.Flush();
GetServerMessage(stream);
writer.WriteLine("list ");
writer.Flush();
tmpserver = new TcpListener(IPAddress.Any, 3128);
tmpserver.Start();
tmpclient = tmpserver.AcceptTcpClient();
Console.WriteLine("gothere");
if (!tmpclient.Connected)
{
tmpserver.Start();
}
StreamReader tmpreader = new StreamReader(tmpclient.GetStream());
GetServerMessage(stream);
while (tmpreader.Peek() != -1)
{
Console.WriteLine(tmpreader.ReadLine());
}
tmpclient.Close();
tmpserver.Stop();
GetServerMessage(stream);
Getservermessage is a method that takes a network stream and prints out everything available within a .5 second timeout, stream is the NetworkStream for the current connection to the FTP server, and writer is that same network stream wrapped in a StreamReader for ease of writing ASCII characters to the server. In case you are wondering why I use a stream reader to read from the data connection, it is because the server closes the connection after it transmits the data so I could easily get an eof notification. My GetServerMessage method was for some reason breaking when I used the closed network stream.
This code is sending the port command to the FTP server to inform it that I will be requiring a data connection (first 2 lines) Then sending the list command, establishing the data connection to the server, getting the desired information, and then terminating the data connection (the rest of the code).
This code will execute without flaw the first time I run it but if I try it again, it hangs on the 'tmpclient = tmpserver.AcceptTcpClient();' line. It never reaches the "gothere" print statement. I believe this is because I am receiving the client from the same machine on the same port but I'm not sure. I tried adding a Boolean value to make sure the AcceptTcpClient() only ran once but then I got a runtime error and visual studio informed me that I may have 'released resources before I was done with them' I predicted this would be a problem but how can I tell if the server reestablishes the connection after it has closed it once?
At the end of the given code I stop tmpserver and close tmpclient. I originally did this because I knew the FTP server would close the connection when it was finished transmitting and thought it was the proper thing to do. I find if I comment out these lines, the code will execute more than once but the streams appear to be empty... I'm not sure if this information is helpful but I figured I'd mention it.
I apologize if I am unclear at all but my lack of knowledge with the subject makes it difficult to articulate my problem. If there is any confusion over what the problem is I'd be happy to attempt to clear it up.
To be able to accept another client you should execute tmpclient = tmpserver.AcceptTcpClient(); and waiting for the first client to finish its works(before accepting second client) may not be a good idea
Here is a sample server code that waits for the connections and echoes strings sent from each client. You can test it with telnet localhost 3128
Thread t = new Thread(Server);
t.IsBackground = true;
t.Start();
-
void Server()
{
TcpListener listener = new TcpListener(IPAddress.Any, 3128);
listener.Start();
while (true)
{
var client = listener.AcceptTcpClient();
new Thread(() =>
{
using (client)
{
var reader = new StreamReader(client.GetStream());
var writer = new StreamWriter(client.GetStream());
while (true)
{
string line = reader.ReadLine();
if (line == "QUIT") break;
writer.WriteLine("From Thread[" + Thread.CurrentThread.ManagedThreadId + "] > " + line);
writer.Flush();
}
}
}).Start();
}
}
OK, it's like this. To do a server in a simple manner, you need to thread off the code that handles the client socket. When the accept returns, create and start a thread, passing it the 'tmpclient' and then loop around to the accept call again so that any new client can connnct up. In the newly-spawned server<> client thread, read and write to the passed socket in a loop to communicate with the client.
Once you close your tcp client stream, you can no longer read from the stream you pulled from it.
var stream = tcpClient.GetStream();
...
tcpclient.Close();
...
stream.Read .. fail
The client would have to request another connection,
OR
You should keep your tcp client sockets open.
More complex servers will keep some metadata (state) cached about the client so when sockets unexpectedly close - and the client quickly tries to reconnect, the server can continue processing the smoothly.
I have been sending binary data between applications lots of times over TCP sockets but never before using strings. Bumbed into an issue intending to do so. Here is what I got:
TcpClient tcpClient = new TcpClient("localhost", port);
//Connects fine
NetworkStream ns = tcpClient.GetStream();
StreamWriter sw = new StreamWriter(ns);
//The code moves on but nothing seems to be sent unless I do
//a sw.Close() after this line. That would however close the
//ns and prevent me from reading the response further down
sw.Write("hello");
//I am using a stream reader with ReadToEnd() on the tcpListener
//which never receives the string from this piece of code
//Since the above never actually send I get stuck here
string response = new StreamReader(ns).ReadToEnd();
sw.Close();
tcpClient.Close();
How do I send the string without closing the network stream? ns.Flush() is what I would be looking for really.
You have an sw.Flush() , that ought to work. A WriteLine() might have done it too.
But when the other side does a ReadLine() then you have to make sure you end with newline. Try WriteLine() instead of Write().
And be careful about closing a StreamReader/Writer, they also close their underlying streams.
There's a StreamWriter.Flush(). When you get done with sending you message, just do sw.Flush(). However, since buffer sizes are fairly large (upto a couple KB), the correct way is to only Flush() just before you wait for a response. That way several calls to .Write() can be bundled into a single packet and sent down the wire at the same time.
You just need to set the AutoFlush property on the StreamWriter to true.
Can anyone point out the flaw in this code? I'm retrieving some HTML with TcpClient. NetworkStream.Read() never seems to finish when talking to an IIS server. If I go use the Fiddler proxy instead, it works fine, but when talking directly to the target server the .read() loop won't exit until the connection exceptions out with an error like "the remote server has closed the connection".
internal TcpClient Client { get; set; }
/// bunch of other code here...
try
{
NetworkStream ns = Client.GetStream();
StreamWriter sw = new StreamWriter(ns);
sw.Write(request);
sw.Flush();
byte[] buffer = new byte[1024];
int read=0;
try
{
while ((read = ns.Read(buffer, 0, buffer.Length)) > 0)
{
response.AppendFormat("{0}", Encoding.ASCII.GetString(buffer, 0, read));
}
}
catch //(SocketException se)
{
}
finally
{
Close();
}
Update
In the debugger, I can see the entire response coming through immediately and being appended to my StringBuilder (response). It just appears that the connection isn't being closed when the server is done sending the response, or my code isn't detecting it.
Conclusion
As has been said here, it's best to take advantage of the offerings of the protocol (in the case of HTTP, the Content-Length header) to determine when a transaction is complete. However, I've found that not all pages have content-length set. So, I'm now using a hybrid solution:
For ALL transactions, set the request's Connection header to "close", so that the server is discouraged from keeping the socket open. This improves the chances that the server will close the connection when it is through responding to your request.
If Content-Length is set, use it to determine when a request is complete.
Else, set the NetworkStream's RequestTimeout property to a large, but reasonable, value like 1 second. Then, loop on NetworkStream.Read() until either a) the timeout occurs, or b) you read fewer bytes than you asked for.
Thanks to everyone for their excellent and detailed responses.
Contrary to what the documentation for NetworkStream.Read implies, the stream obtained from a TcpClient does not simply return 0 for the number of bytes read when there is no data available - it blocks.
If you look at the documentation for TcpClient, you will see this line:
The TcpClient class provides simple methods for connecting, sending, and receiving stream data over a network in synchronous blocking mode.
Now my guess is that if your Read call is blocking, it's because the server has decided not to send any data back. This is probably because the initial request is not getting through properly.
My first suggestion would be to eliminate the StreamWriter as a possible cause (i.e. buffering/encoding nuances), and write directly to the stream using the NetworkStream.Write method. If that works, make sure that you're using the correct parameters for the StreamWriter.
My second suggestion would be not to depend on the result of a Read call to break the loop. The NetworkStream class has a DataAvailable property that is designed for this. The correct way to write a receive loop is:
NetworkStream netStream = client.GetStream();
int read = 0;
byte[] buffer = new byte[1024];
StringBuilder response = new StringBuilder();
do
{
read = netStream.Read(buffer, 0, buffer.Length);
response.Append(Encoding.ASCII.GetString(buffer, 0, read));
}
while (netStream.DataAvailable);
Read the response until you reach a double CRLF. What you now have is the Response headers.
Parse the headers to read the Content-Length header which will be the count of bytes left in the response.
Here is a regular expression that can catch the Content-Length header.
David's Updated Regex
Content-Length: (?<1>\d+)\r\n
Content-Length
Note
If the server does not properly set this header I would not use it.
Not sure if this is helpful or not but with HTTP 1.1 the underlying connection to the server might not be closed so maybe the stream doesn't get closed either? The idea being that you can reuse the connection to send a new request. I think you have to use the content-length. Alternatively use the WebClient or WebRequest classes instead.
I may be wrong, but it looks like your call to Write is writing (under the hood) to the stream ns (via StreamWriter). Later, you're reading from the same stream (ns). I don't quite understand why are you doing this?
Anyway, you may need to use Seek on the stream, to move to the location where you want to start reading. I'd guess that it seeks to the end after writing. But as I said, I'm not really sure if this is a useful answer!
Two Suggestions...
Have you tried using the DataAvailable property of NetworkStream? It should return true if there is data to be read from the stream.
while (ns.DataAvailable)
{
//Do stuff here
}
Another option would be to change the ReadTimeOut to a low value so you don't end up blocking for a long time. It can be done like this:
ns.ReadTimeOut=100;