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
Related
I'm attempting to learn ZeroMq for project at work although my background is in C#, and in the most simplest of tests I seem to have an issue where the socket.recv(...) call will block for the first received message, but after this throws an exception because the amount of data received is -1.
Currently my 'server' is:
zmq::context_t context(1);
zmq::socket_t socket(context, ZMQ_REP);
socket.bind("tcp://127.0.0.1:5555");
while (true)
{
zmq::message_t message;
if (socket.recv(&message))
{
auto str = std::string(static_cast<char*>(message.data()), message.size());
printf("Receieved: %s\n", str.c_str());
}
}
This is basically from following the first example server within the ZeroMq documentation.
I'm pushing 1 bit of data from a C# 'client' using this code:
using (var context = new ZContext())
using (var requester = new ZSocket(context, ZSocketType.REQ))
{
requester.Connect(#"tcp://127.0.0.1:5555");
requester.Send(new ZFrame(#"hello"));
requester.Disconnect(#"tcp://127.0.0.1:5555");
}
Now I start the server, then start the client. I correctly receive the first message and I am correctly able to print this.
But now when I hit socket.recv(&message) again the code won't block but will instead throw an exception because the underlying zmq_msg_recv(...) returns a value of -1.
I'm unsure why this is occurring, I cannot see why it is expecting another message as I know that there is nothing else on this port. The only thing I came across is calling zmq_msg_close(...) but this should be called as part of the message_t destructor, which I have confirmed.
Is there anything I'm doing wrong in terms of the socket setup or how I'm using it for the recv(...) call to stop blocking?
Your problem is that you cannot receive 2 requests in a row with the REQ-REP pattern.
In the Request-Reply Pattern each request demands a reply. Your client needs to block until it receives a reply to its first request. Also, your server needs to reply to the requests before it services a new request.
Here is a quote referring to your exact issue from the guide.
The REQ-REP socket pair is in lockstep. The client issues zmq_send()
and then zmq_recv(), in a loop (or once if that's all it needs). Doing
any other sequence (e.g., sending two messages in a row) will result
in a return code of -1 from the send or recv call. Similarly, the
service issues zmq_recv() and then zmq_send() in that order, as often
as it needs to.
First, I don't know if Stackoverflow is the best site to post this kind of message, but I don't know another sites like this.
In oder to understand properly tcp programmation in C#, I decided to do all possible ways from scratch. Here is what I want to know (not in the right order:
- Simple One Thread Socket Server (this article)
- Simple Multiple Threads Socket Server (I don't know how, cause threads are complicated)
- Simple Thread Socket Server (put the client management in another thread)
- Multiple Threads Socket Server
- Using tcpListener
- Using async / Await
- Using tasks
The ultimate objective is to know how to do the best tcp server, without just copy/paste some parts of come, but understand properly all things.
So, this is my first part : a single thread tcp server.
There is my code, but I don't think anybody will correct something, because it's quite a copy from MSDN : http://msdn.microsoft.com/en-us/library/6y0e13d3(v=vs.110).aspx
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace SimpleOneThreadSocket
{
public class ServerSocket
{
private int _iPport = -1;
private static int BUFFER_SIZE = 1024;
private Socket _listener = null;
public ServerSocket(int iPort)
{
// Create a TCP/IP socket.
this._listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// Save the port
this._iPport = iPort;
}
public void Start()
{
byte[] buffer = null;
String sDatasReceived = null;
// Bind the socket to loopback address
try
{
this._listener.Bind(new System.Net.IPEndPoint(System.Net.IPAddress.Loopback, _iPport));
this._listener.Listen(2);
}
catch (Exception e)
{
System.Console.WriteLine(e.ToString());
}
// Listening
try
{
Console.WriteLine("Server listening on 127.0.0.1:" + _iPport);
while (true)
{
Socket client = this._listener.Accept();
Console.WriteLine("Incoming connection from : " + IPAddress.Parse(((IPEndPoint)client.RemoteEndPoint).Address.ToString()) + ":" + ((IPEndPoint)client.RemoteEndPoint).Port.ToString());
// An incoming connection needs to be processed.
while (true)
{
buffer = new byte[BUFFER_SIZE];
int bytesRec = client.Receive(buffer);
sDatasReceived += Encoding.ASCII.GetString(buffer, 0, bytesRec);
if (sDatasReceived.IndexOf("<EOF>") > -1)
{
// Show the data on the console.
Console.WriteLine("Text received : {0}", sDatasReceived);
// Echo the data back to the client.
byte[] msg = Encoding.ASCII.GetBytes(sDatasReceived);
client.Send(msg);
sDatasReceived = "";
buffer = null;
}
else if (sDatasReceived.IndexOf("exit") > -1)
{
client.Shutdown(SocketShutdown.Both);
client.Close();
sDatasReceived = "";
buffer = null;
break;
}
}
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
}
But I have some questions about that :
Listen Method from Socket have a parameter : backlog. According to MSDN, backlog is the number of available connection. I don't know why, when I put 0, I can connect to my server with multiple Telnet sessions. EDIT : 0 & 1 both allow 2 connections (1 current, 1 pending), 2 allow 3 connections (1 current, 2 pending), etc... So I didn't understand well the meaning of MSDN.
Can you confirm that Accept Method will take each connection one after one, that's why I see text from differents Telnet session in my server ?
Can you confirm (my server is a C# library) I can't kill my server (with this kind of code) without killing the process ? It could be possible with threads but it will come later.
If something is wrong in my code, please help me :)
I will come back soon with a simple multiple thread socket server, but I don't know how (I think one step is available before using threads or async/await).
First off, do your best not to even learn this. If you can possibly use a SignalR server, then do so. There is no such thing as a "simple" socket server at the TCP/IP level.
If you insist on the painful route (i.e., learning proper TCP/IP server design), then there's a lot to learn. First, the MSDN examples are notoriously bad starting points; they barely work and tend to not handle any kind of error conditions, which is absolutely necessary in the real world when working at the TCP/IP level. Think of them as examples of how to call the methods, not examples of socket clients or servers.
I have a TCP/IP FAQ that may help you, including a description of the backlog parameter. This is how many connections the OS will accept on your behalf before your code gets around to accepting them, and it's only a hint anyway.
To answer your other questions: A single call to Accept will accept a single new socket connection. The code as-written has an infinite loop, so it will work like any other infinite loop; it will continue executing until it encounters an exception or its thread is aborted (which happens on process shutdown).
If something is wrong in my code, please help me
Oh, yes. There are lots of things wrong with this code. It's an MSDN socket example, after all. :) Off the top of my head:
The buffer size is an arbitrary value, rather low. I would start at 8K myself, so it's possible to get a full Ethernet packet in a single read.
The Bind explicitly uses the loopback address. OK for playing around, I guess, but remember to set this to IPAddress.Any in the real world.
backlog parameter is OK for testing, but should be int.MaxValue on a true server to enable the dynamic backlog in modern server OSes.
Code will fall through the first catch and attempt to Accept after a Bind/Listen failed.
If any exception occurs (e.g., from Listen or Receive), then the entire server shuts down. Note that a client socket being terminated will result in an exception that should be logged/ignored, but it would stop this server.
The read buffer is re-allocated on each time through the loop, even though the old buffer is never used again.
ASCII is a lossy encoding.
If a client cleanly shuts down without sending <EOF>, then the server enters an infinite busy loop.
Received data is not properly separated into messages; it is possible that the echoed message contains all of one message and part of another. In this particular example it doesn't matter (since it's just an echo server and it's using ASCII instead of a real encoding), but this example hides the fact that you need to handle message framing properly in any real-world application.
The decoding should be done after the message framing. This isn't necessary for ASCII (a lossy encoding), but it's required for any real encodings like UTF8.
Since the server is only either receiving or sending at any time (and never both), it cannot detect or recover from a half-open socket situation. A half-open socket will cause this server to hang.
The server is only capable of a single connection at a time.
That was just after a brief readthrough. There could easily be more.
This is not a question about how to do this, but a question about whether it's wrong what I'm doing. I've read that it's not possible to detect if a socket is closed unexpectedly (like killing the server/client process, pulling the network cable) while waiting for data (BeginReceive), without use of timers or regular sent messages, etc. But for quite a while I've been using the following setup to do this, and so far it has always worked perfectly.
public void OnReceive(IAsyncResult result)
{
try
{
var bytesReceived = this.Socket.EndReceive(result);
if (bytesReceived <= 0)
{
// normal disconnect
return;
}
// ...
this.Socket.BeginReceive...;
}
catch // SocketException
{
// abnormal disconnect
}
}
Now, since I've read it's not easily possible, I'm wondering if there's something wrong with my method. Is there? Or is there a difference between killing processes and pulling cables and similar?
It's perfectly possible and OK to do this. The general idea is:
If EndReceive returns anything other than zero, you have incoming data to process.
If EndReceive returns zero, the remote host has closed its end of the connection. That means it can still receive data you send if it's programmed to do so, but cannot send any more of its own under any circumstances. Usually when this happens you will also close your end the connection thus completing an orderly shutdown, but that's not mandatory.
If EndReceive throws, there has been an abnormal termination of the connection (process killed, network cable cut, power lost, etc).
A couple of points you have to pay attention to:
EndReceive can never return less than zero (the test in your code is misleading).
If it throws it can throw other types of exception in addition to SocketException.
If it returns zero you must be careful to stop calling BeginReceive; otherwise you will begin an infinite and meaningless ping-pong game between BeginReceive and EndReceive (it will show in your CPU usage). Your code already does this, so no need to change anything.
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 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().