As a client, I have a queue of messages to send to the server. Each one opens a new TcpClient, Write and Read.
If the server has a delay, and the client reaches its timeout, I close the TcpClient and move to the next message.
However, when writing and reading the next one, I mistakenly read the previous response.
Here's a code that illustrates the problem:
using (TcpClient client1 = new TcpClient(ip, port))
using (NetworkStream stream1 = client1.GetStream())
{
byte[] dataToSend = Encoding.ASCII.GetBytes(message1);
await stream1.WriteAsync(dataToSend, 0, dataToSend.Length);
await stream1.FlushAsync();
// The server takes a while to respond. Simulate a timeout in client...
}
using (TcpClient client2 = new TcpClient(ip, port))
using (NetworkStream stream2 = client2.GetStream())
{
byte[] dataToSend = Encoding.ASCII.GetBytes(message2);
await stream2.WriteAsync(dataToSend, 0, dataToSend.Length);
await stream2.FlushAsync();
byte[] dataToRead = new byte[client2.ReceiveBufferSize];
int bytesRead = await stream2.ReadAsync(dataToRead, 0, client2.ReceiveBufferSize);
string messageReceived = Encoding.ASCII.GetString(dataToRead, 0, bytesRead);
}
The 'messageReceived' gets the response of the first Write rather than the second one.
I tried to set SendTimeout/ReceiveTimeout of the client, but it didn't help.
Is there an elegant way to ignore/avoid the response of the previous Write?
This is a problem with the server. Each connection is independent. A new connection will not see data for an old connection, even if the client and server are the same.
If a new connection is getting a response intended for a different connection, then that is a bug in the server. It sounds like the server may be sending responses to "whatever clients are currently connected", which is almost always incorrect behavior. Instead, the server should only send responses to the same connection that sent the request.
Related
I am working on sending data across the network with the traditional server-client model.
Here Server starts the Tcplistener in a particular address and port. In this case, it is the local host.
The client makes use of WebRequest class in .net and takes the request stream and starts writing data into the request stream.
Let me walk through the Server code class:
TcpListener tcpListener = new TcpListener(IPAddress.Parse("127.0.0.1"),9309);
tcpListener.Start()//Start the listener and wait for client to connect.
while(true)
{
TcpClient newclient = tcpListener.AcceptTcpClient();
if(newclient.Connected())
{
break;
}
}
while(true)
{
ReadData(newclient);
}
public void ReadData(TcpClient newclient)
{
byte[] buffer = newbyte[50];
Stream ns = newclient.GetStream();
ns.Read(buffer, 0, buffer.Length);
Console.WriteLine( Encoding.UTF8.GetString(buffer));
}
//End of Server class.
Now let's see the Client Code class:-
WebRequest Request = HttpWebRequest.Create(http://127.0.0.1:9309/DataChannel);
Request.Method = "POST";
//Below method registers to Server's AcceptTcpClient and tcpclient is assigned.
Stream NetworkStream = ModifyCollimationRequest.GetRequestStream();
int DataWritten = 0;
while(true)
{
string Dname = "\r\nPosting server with Data as {0}\r\n";
byte[] dbytes = Encoding.UTF8.GetBytes(string.Format(Dname, ++DataWritten));
ns.WriteAsync(dbytes, 0, dbytes.Length);
ns.FlushAsync();
}
//End of Client code. Once the connection is established, the client keeps writing into the stream till the buffer size of >65000 is reached without issue but the problem is with the Server.
In Server,
Stream ns = newclient.GetStream(); -> This line under ReadData() method of the server executes,
but the the next line the code where Read() is used -> the code does not throw exception nor reaches next line. It just exits while debugging or times out. Someone it feels like, I am not able to fetch the stream or stream is empty. But the client keeps writing without any issue.
Can sometimes try this out and help me with what I am missing. Ultimately, I should be able to read the data available in a stream in any case but not sure why. Please add in your suggestions?
At the end of the client code, we need to call the below method for the data to
start actual streaming
ResponseStream = (HttpWebResponse)Request.GetResponse();
This is because there seems to be a bug in this .NET API where the buffered data is sent only when GetResponse() stream is called. This fixed the issue for me.
Below StackOverflow URL helped me learn more on this problem
HttpWebRequest.GetRequestStream returned stream does not send data immediately in .NET Core
I'm trying to make a simple TCP program. I can get the client to connect to the server, but when my client calls stream.Write, the server does not read the sent data until the client closes the connection.
In addition to this, when my client attempts to read the server's response, the client throws an IOException. ("The connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.")
Server code:
listener.Start();
TcpClient client = listener.AcceptTcpClient();
NetworkStream ns = client.GetStream();
//Wait for message
MemoryStream ms = new MemoryStream();
ns.CopyTo(ms);//server will hang here until connection is closed, then receive correct data
Client code:
client.Connect(endpt);
client.GetStream().Write(encodedMessage, 0, encodedMessage.Length);
NetworkStream ns = client.GetStream();
MemoryStream ms = new MemoryStream();
ns.CopyTo(ms); //client crashes here
No, the server reads the data just fine. It's just that the stream doesn't end until you close the connection - the CopyTo method has no way to know that you want it to stop reading at some point. Remember, TCP doesn't send messages, it maintains a bi-directional stream of bytes. If you need messages, you need to build a messaging protocol on top of TCP.
The same thing happens on the client side, so you basically have a deadlock there - the client can't close the connection until it reads the whole stream, and the server can't close the connection until it reads the whole stream (indeed, it doesn't even accept any new connections, since you're doing all of this on one thread). But again, a TCP stream only ends when the connection is shutdown. So both are going to wait for each other forever.
I certainly don't get a crash, though. Are you trying to connect two clients to the same server at the same time? This will not work with your present code, and will cause a timeout like yours. The problem is that the connection is still waiting in the server's queue, and you don't call AcceptTcpClient until the previous connections are closed (again, the CopyTo deadlock).
Networking is quite hard. I'd certainly recommend you to use a well-tested, well-designed communication framework instead of rolling your own TCP-based protocol. Something like WCF or Lidgren will likely help quite a bit. If you really want to make your own TCP-based communication, you'll need to go through quite a bit of learning - I'd really like to recommend a good resource, but I haven't found any for C#/.NET so far. I've started a few samples on Networking, but that's far from production-ready code, and rather incomplete. It will show you the basic ideas of how an asynchronous TCP server is built in C#, as well as how to implement a simple HTTP-style or message-style TCP-based protocol.
You can try something like this:
//Server Part
public void Start()
{
Console.WriteLine("Server started...");
TcpListener listener = new TcpListener(System.Net.IPAddress.Loopback, 1234);
listener.Start();
while (true)
{
TcpClient client = listener.AcceptTcpClient();
new Thread(new ThreadStart(() =>
{
HandleClient(client);
})).Start();
}
}
private void HandleClient(TcpClient client)
{
NetworkStream stream = client.GetStream();
StreamWriter writer = new StreamWriter(stream, Encoding.ASCII) { AutoFlush = true };
StreamReader reader = new StreamReader(stream, Encoding.ASCII);
string inputLine = reader.ReadLine();
Console.WriteLine("The client with name " + " " + inputLine + " is conected");
}
//Client Part
public void InitClient()
{
client = new TcpClient("localhost", 1234);
stream = client.GetStream();
writer = new StreamWriter(stream) { AutoFlush = true };
reader = new StreamReader(stream);
}
public void SendMessage(string userName)
{
writer.WriteLine(userName);
}
//And here are the type of the variable that are used:
TcpClient client;
NetworkStream stream;
StreamWriter writer;
StreamReader reader;
Hope it help!
I resolved the issue by using AcceptSocket rather than AcceptTcpClient on the server, and using the Socket Receive function.
The client also now reads into an array rather than using the CopyTo function.
New server code:
listener.Start();
Socket socket = listener.AcceptSocket();
byte[] b = new byte[999];
socket.Receive(b);
New client code:
client.Connect(endpt);
client.GetStream().Write(encodedMessage, 0,encodedMessage.Length);
NetworkStream ns = client.GetStream();
byte[] bb = new byte[999];
ns.Read(bb, 0, 999);
I want to open tcp connection between two machine.
I want to use the class TcpListener on the client side and on the server side and by this to have the option to make the two side 'talk' with the other by sending and receiving byte[].
That mean that each side is a server and a client.
I using the code from msdn to do it.
But on this code the server start and wait till the client will connect to him.
If i doing so on the both sides i will fail.
Is there any other way ?
The code:
public static void Main()
{
TcpListener server=null;
try
{
// Set the TcpListener on port 13000.
Int32 port = 13000;
IPAddress localAddr = IPAddress.Parse("127.0.0.1");
// TcpListener server = new TcpListener(port);
server = new TcpListener(localAddr, port);
// Start listening for client requests.
server.Start();
// Buffer for reading data
Byte[] bytes = new Byte[256];
String data = null;
// Enter the listening loop.
while(true)
{
Console.Write("Waiting for a connection... ");
// Perform a blocking call to accept requests.
// You could also user server.AcceptSocket() here.
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("Connected!");
data = null;
// Get a stream object for reading and writing
NetworkStream stream = client.GetStream();
int i;
// Loop to receive all the data sent by the client.
while((i = stream.Read(bytes, 0, bytes.Length))!=0)
{
// Translate data bytes to a ASCII string.
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("Received: {0}", data);
// Process the data sent by the client.
data = data.ToUpper();
byte[] msg = System.Text.Encoding.ASCII.GetBytes(data);
// Send back a response.
stream.Write(msg, 0, msg.Length);
Console.WriteLine("Sent: {0}", data);
}
// Shutdown and end connection
client.Close();
}
}
catch(SocketException e)
{
Console.WriteLine("SocketException: {0}", e);
}
finally
{
// Stop listening for new clients.
server.Stop();
}
Console.WriteLine("\nHit enter to continue...");
Console.Read();
}
I assume there is some missunderstanding...
The TcpListener class is used to open a listener. This represents an endpoint to whom a client can connect (like e.g. a WebServer). To actually connect to such an endpoint you need to use an instance of the TcpClient class.
Following a simple example (written out of my head and NOT TESTED!), also be advised that there is no error handling included and this should just give you a hint where and how to start.
Serverside
// Create a local endpoint (all network interfaces at port 80)
// and create a listener that uses that endpoint.
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, 80);
TcpListener listener = new TcpListener(localEndPoint);
// Start the listener.
listener.Start();
// Wait (blocking) until a client connects.
TcpClient client = listener.AcceptTcpClient();
// Stop the listener (so no one else can connect).
listener.Stop();
// Fetch the underlying network stream which
// allows reading and writing data between us and
// the connected client.
NetworkStream ns = client.GetStream();
// Read data from the stream.
byte[] dataBuffer = new byte[8192];
int receivedBytes = ns.Read(dataBuffer, 0, dataBuffer.Length);
// Translate it back to a text by using UTF-8 encoding.
Console.WriteLine($"I have received {receivedBytes} bytes:");
Console.WriteLine(Encoding.UTF8.GetString(dataBuffer, 0, receivedBytes));
// Write an answert to the client.
dataBuffer = Encoding.UTF8.GetBytes("Thank you for your message!");
ns.Write(dataBuffer, 0, dataBuffer.Length);
// Close everything.
ns.Flush();
ns.Close();
client.Close();
Clientside
// Create a remote endpoint (the ip you want to connect to at port 80)
// and create a client that uses that endpoint.
IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Parse("the ip you want to connect to"), 80);
TcpClient client = new TcpClient();
// Try to connect to that endpoint.
client.Connect(remoteEndPoint);
// Fetch the underlying network stream which
// allows reading and writing data between us and
// the connected client.
NetworkStream ns = client.GetStream();
// Write something to the server.
byte[] dataBuffer = Encoding.UTF8.GetBytes("Hello, I am here.");
ns.Write(dataBuffer, 0, dataBuffer.Length);
// Read an answer back from the server.
dataBuffer = new byte[8192];
int receivedBytes = ns.Read(dataBuffer, 0, dataBuffer.Length);
// Translate it back to a text by using UTF-8 encoding.
Console.WriteLine($"I have received an answer with {receivedBytes} bytes:");
Console.WriteLine(Encoding.UTF8.GetString(dataBuffer, 0, receivedBytes));
// Close everything.
ns.Flush();
ns.Close();
client.Close();
The example above obviously does just send one message and closes the application afterwards. If you need to wait until data has arrived, you can use the DataAvailable property of the NetworkStream which indicates whether data is available or not. If not, just sleep and try again later.
Example
bool iWantToReceiveData = true;
while (iWantToReceiveData)
{
// If no data is available...
if (!ns.DataAvailable)
{
// ...wait some time and try again later.
Thread.Sleep(100);
continue;
}
// Read an answer back from the server.
dataBuffer = new byte[8192];
int receivedBytes = ns.Read(dataBuffer, 0, dataBuffer.Length);
// Translate it back to a text by using UTF-8 encoding.
Console.WriteLine($"I have received an answer with {receivedBytes} bytes:");
Console.WriteLine(Encoding.UTF8.GetString(dataBuffer, 0, receivedBytes));
}
Of course this is some kind of blocking beaviour so you will have to handle that in a separate thread.
I would suggest building an EnhancedNetworkStream class which has a thread running in the background that does the cyclic checking for new data and fires an event once new data has arrived.
I'm having serious issue with half-closing a TcpClient. What I am trying to do is:
On the client:
Send a message
Shutdown the underlying socket for sending
Receive a response
Shutdown the underlying socket for reading (or, at this point, just close it)
On the server:
Receive a message
Shutdown the underlying socket for reading
Send a response
Shutdown the underlying socket for writing (or, at this point, just close it)
However, after the step 2 on either the client, or the server, I can't use the TcpClient's stream.
Here's a very simplified version of my code (without asynchronous calls, processing and cleaning up, and also using StreamReader and StreamWriter instead of an XmlSerializer):
//initialize the connection between the server and the client
var listener = new TcpListener(IPAddress.Any, 13546);
listener.Start();
var client = new TcpClient("127.0.0.1", 13546);
var server = listener.AcceptTcpClient();
listener.Stop();
//CLIENT: send the message
var cwriter = new StreamWriter(client.GetStream());
cwriter.Write("client's message");
cwriter.Flush();
client.Client.Shutdown(SocketShutdown.Send);
//SERVER: receive the message
string msg;
var sreader = new StreamReader(server.GetStream());
msg = sreader.ReadToEnd();
server.Client.Shutdown(SocketShutdown.Receive);
//SERVER: send a response
//Here the code fails on server.GetStream() -
//InvalidOperationException, apparently the whole connection is closed now
var swriter = new StreamWriter(server.GetStream());
swriter.Write(msg + " with server's response");
swriter.Flush();
server.Client.Shutdown(SocketShutdown.Send);
//CLIENT: receive the message
var creader = new StreamReader(client.GetStream());
var response = creader.ReadToEnd();
client.Client.Shutdown(SocketShutdown.Receive);
Is there any way to do this without using a raw socket? Is there something I'm getting wrong?
The problem is that ReadToEnd reads data up to the end of stream. By issuing Client.Shutdown you actually close the socket making it impossible to reuse it (at least in case of TCPClient). Here's the code of GetStream()
public NetworkStream GetStream() {
if(Logging.On)Logging.Enter(Logging.Sockets, this, "GetStream", "");
if (m_CleanedUp){
throw new ObjectDisposedException(this.GetType().FullName);
}
if (!Client.Connected) {
throw new InvalidOperationException(SR.GetString(SR.net_notconnected));
}
if (m_DataStream==null) {
m_DataStream = new NetworkStream(Client, true);
}
if(Logging.On)Logging.Exit(Logging.Sockets, this, "GetStream", m_DataStream);
return m_DataStream;
}
As you can see, the error occures due to closed socket.
EDIT: It is ridiculously strange but I think I found the reason why it doesn't work properly. The reason is that Shutdown always sets flags for the entire socket as disconnected. Even though we are actually not closing it that way! If we preserve stream at the begining of the method we will not face this problem since the problem lies in GetStream method which checks socket's state. But we are probably exposed to some bugs when other code would check socket's state.
I am currently working on a c# program where I am opening a connection on a socket and listening for clients.
How can I check if the TcpListener has any clients currently connected. I want to do this so when someone closes the console application instead of it just terminating anything that is connect it will instead wait for all connected clients to finish before exiting the console app.
Below is the code:
TcpClient client = listener.AcceptTcpClient();
if (client.Connected)
{
library.logging(classDetails + MethodInfo.GetCurrentMethod().Name,
string.Format("Client Connected: {0}",((IPEndPoint)client.Client.RemoteEndPoint).Address.ToString()));
NetworkStream stream = client.GetStream();
byte[] data = new byte[client.ReceiveBufferSize];
int bytesRead = stream.Read(data, 0, Convert.ToInt32(client.ReceiveBufferSize));
string request = Encoding.ASCII.GetString(data, 0, bytesRead);
byte[] msg = System.Text.Encoding.ASCII.GetBytes("200 OK");
ProcessXML process = new ProcessXML(library, appSettings);
// Send back a response.
stream.Write(msg, 0, msg.Length);
process.processXML(request, ((IPEndPoint)client.Client.RemoteEndPoint).Address.ToString());
client.Close();
Is there a method within the TcpListener to get a count of connected clients or has this got to be managed by myself by adding the client to something like a list array and then remove it when the client closes.
To the best of my knowledge, TcpListener does not internally keep track of accepted connections - that must be done explicitly by the application as needed.