Comparing a string received via TCP against another string - c#

I obtained the following code from MSDN :
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
class MyTcpListener
{
public static void Main()
{
TcpListener server = null;
try
{
Int32 port = 13000; // Set the TcpListener on port 13000.
IPAddress localAddr = IPAddress.Parse("127.0.0.1");
server = new TcpListener(localAddr, port); // TcpListener server = new TcpListener(port);
server.Start(); // Start listening for client requests.
// 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;
NetworkStream stream = client.GetStream();// Get a stream object for reading and writing
int i;
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0) // Loop to receive all the data sent by the client.
{
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i); // Translate data bytes to a ASCII string.
Console.WriteLine("Received: {0}", data);
data = data.ToUpper();// Process the data sent by the client.
byte[] msg = System.Text.Encoding.ASCII.GetBytes(data);
stream.Write(msg, 0, msg.Length); // Send back a response.
Console.WriteLine("Sent: {0}", data);
if(data == "STOP")
{
Console.WriteLine("Stop command Received.");
Console.ReadKey();
Environment.Exit(0);
}
Console.WriteLine(data.Length);
}
client.Close(); // Shutdown and end connection
}
}
catch (SocketException e)
{
Console.WriteLine("SocketException: {0}", e);
}
finally
{
server.Stop();// Stop listening for new clients.
}
Console.WriteLine("\nHit enter to continue...");
Console.Read();
}
}
except the following lines which were inserted by me:
if(data == "STOP")
{
Console.WriteLine("Stop command Received.");
Console.ReadKey();
Environment.Exit(0);
}
I sent a string "STOP" via a tcp client. However, in the server, comparing the received string "STOP" against "STOP" in the 'if block' was of no use ie., nothing in that block got executed.
What is the actual error in this approach ? What changes should I make to compare the strings properly ?

If Ben's answer does not solve your problem there is a 2nd major problem with your code.
Your code has no guarantees that you won't get ST in one read and OP in the next read. A single send is allowed to be split in to multiple reads, and multiple sends are allowed to be combined in to a single read. So sending Test then STOP could show up as TestSTOP when you call the read function.
You need to add additional logic to the code to tell when one message stops and another starts on the receiving side. This is called Message Framing and for your additions to the program to work you will need to add that logic in to your program.

If you are sending the text via WriteLine (vs. Write), the string you are getting won't be "STOP" but rather "STOP\r\n", so you would want to Trim() the string to check for equality.
data.Trim() == "STOP"

Related

Why isn't TcpListener listening?

We have a C++ v100 application that is processing every event in our system, listening on port 1705, running off the Hostname. (it works perfectly for the C++ app, and we don't want to change anything in the c++ code) We are trying to intercept some of those events into a C# 4.5.2 solution, simply to display specific events in our new web system.
I have coded the following, in an attempt to listen to port 1705 traffic... but I never receive any data. (I can create events that get sent to 1705)
The following code runs, and it makes it to 'Waiting for a connection', but never makes it to 'Connected!'. If you see any reason in the following code as to why I wouldn't be receiving data, please let me know:
private void PortListener()
{
TcpListener server = null;
try
{
// Set the TcpListener on port 13000.
var port = 1705;
var localAddr = IPAddress.Parse(Dns.GetHostAddresses(Environment.MachineName)[0].ToString());
server = new TcpListener(localAddr, port);
// Start listening for client requests.
server.Start();
// Buffer for reading data
var bytes = new byte[256];
// 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.
var client = server.AcceptTcpClient();
Console.WriteLine("Connected!");
// Get a stream object for reading and writing
var 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.
var data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("Received: {0}", data);
// Process the data sent by the client.
data = data.ToUpper();
//TODO: Process the data
}
// Shutdown and end connection
client.Close();
}
}
catch (SocketException e)
{
Console.WriteLine("SocketException: {0}", e);
}
finally
{
// Stop listening for new clients.
server?.Stop();
}
}
Make sure that you are binding/listening to the right ip-address. If you bind/listen on localhost (127.0.0.1) you can only connect from the same host.
Check what
Dns.GetHostAddresses(Environment.MachineName)[0].ToString());
really produces.
I'm doing this all wrong. In order to listen to an already opened Port, I need to use a TcpClient to connect and listen. Only a single TcpListener is allowed per port. Several TcpClients can connect at once. Sigh.

Open two tcp connection using TcpListener class on both side

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.

Why does my C# TcpClient fail to receive content from the server if the server sends before reading everything from the client?

In an application I'm working on I want to disconnect clients that are trying to send me packets that are too large.
Just before disconnecting them I want to send them a message informing them about the reason for disconnecting them.
The issue I am running into is that the client cannot receive this server message, if the server does not read everything the client has send him first. I do not understand why this is happening.
I've managed to narrow it down to a very small test setup where the problem is demonstrated.
The StreamUtil class is a simple wrapper class that helps to get around the TCP message boundary problem, basically on the sender side it sends the size of each message first and then the message itself, and on the receiver side it receives the size of the message first and then the message.
The client uses a ReadKey command to simulate some time between sending and receiving, seeing in my real application these two actions are not immediately back to back either.
Here is a test case that works:
Run server as shown below
Run client as shown below, it will show a "Press key message", WAIT do not press key yet
Turn off server since everything is already in the clients receive buffer anyway (I validated this using packet sniffer)
Press key on the client -> client correctly shows the messages from the server.
This is what I was expecting, so great so far no problem yet.
Now in the server code, comment out the 2nd receive call and repeat the steps above.
Step 1 and 2 complete successfully, no errors sending from client to server.
On step 3 however the client crashes on the read from the server, EVEN though the server reply HAS arrived on the client (again validated with packet sniffer).
If I do a partial shutdown (eg socket.Shutdown (...send...)) without closing the socket on the server, everything works.
1: I just cannot get my head around WHY not processing the line of text from the client on the server causes the client to fail on receiving the text send back from the server.
2: If I send content from server to client but STOP the server before actually closing the socket, this content never arrives, but the bytes have already been transmitted to the server side... (see ReadKey in server to simulate, basically I block there and then just quit the server)
If anyone could shed light on these two issues, I'd deeply appreciate it.
Client:
class TcpClientDemo
{
public static void Main (string[] args)
{
Console.WriteLine ("Starting....");
TcpClient client = new TcpClient();
try
{
client.Connect("localhost", 56789);
NetworkStream stream = client.GetStream();
StreamUtil.SendString(stream, "Client teststring...");
Console.WriteLine("Press key to initiate receive...");
Console.ReadKey();
Console.WriteLine("server reply:" + StreamUtil.ReceiveString(stream));
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
finally
{
client.Close();
}
Console.WriteLine("Client ended");
Console.ReadKey(true);
}
}
Server:
class TcpServerDemo
{
public static void Main (string[] args)
{
TcpListener listener = new TcpListener (IPAddress.Any, 56789);
listener.Start ();
Console.WriteLine ("Waiting for clients to serve...");
while (true)
{
TcpClient client = null;
NetworkStream stream = null;
try
{
client = listener.AcceptTcpClient();
stream = client.GetStream();
//question 1: Why does commenting this line prevent the client from receiving the server reply??
Console.WriteLine("client string:" + StreamUtil.ReceiveString(stream));
StreamUtil.SendString(stream, "...Server reply goes here...");
//question 2: If I close the server program without actually calling client.Close (while on this line), the client program crashes as well, why?
//Console.ReadKey();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
break;
}
finally
{
if (stream != null) stream.Close();
if (client != null) client.Close();
Console.WriteLine("Done serving this client, everything closed.");
}
}
listener.Stop();
Console.WriteLine("Server ended.");
Console.ReadKey(true);
}
}
StreamUtil:
public class StreamUtil
{
public static byte[] ReadBytes (NetworkStream pStream, int byteCount) {
byte[] bytes = new byte[byteCount];
int bytesRead = 0;
int totalBytesRead = 0;
try {
while (
totalBytesRead != byteCount &&
(bytesRead = pStream.Read (bytes, totalBytesRead, byteCount - totalBytesRead)) > 0
) {
totalBytesRead += bytesRead;
Console.WriteLine("Read/Total:" + bytesRead + "/" + totalBytesRead);
}
} catch (Exception e) {
Console.WriteLine(e.Message);
}
return (totalBytesRead == byteCount) ? bytes : null;
}
public static void SendString (NetworkStream pStream, string pMessage) {
byte[] sendPacket = Encoding.ASCII.GetBytes (pMessage);
pStream.Write (BitConverter.GetBytes (sendPacket.Length), 0, 4);
pStream.Write (sendPacket, 0, sendPacket.Length);
}
public static string ReceiveString (NetworkStream pStream) {
int byteCountToRead = BitConverter.ToInt32(ReadBytes (pStream, 4), 0);
Console.WriteLine("Byte count to read:"+byteCountToRead);
byte[] receivePacket = ReadBytes (pStream, byteCountToRead);
return Encoding.ASCII.GetString (receivePacket);
}
}
The client fails because it detects the socket was already closed.
If C# socket operations detect a closed connection during earlier operations, an exception is thrown on the next operation which can mask data which would otherwise have been received
The StreamUtil class does a couple of things when the connection is closed before/during a read:
Exceptions from the reads are swallowed
A read of zero bytes isn't treated
These obfuscate what's happening when an unexpected close hits the client.
Changing ReadBytes not to swallow exceptions and to throw a mock socket-closed exception (e.g. if (bytesRead == 0) throw new SocketException(10053);) when it reads zero bytes I think makes the outcome more clear.
Edit
I missed something subtle in your examples - your first example causes a TCP RST flag to be sent as soon as the server closes connection, due to the socket being closed with data waiting to be read.
The RST flag results in a closedown that doesn't preserve pending data.
This blog has some discussion based on a very similar scenario (web server sending a HTTP error).
So I don't think there's an easy fix, options are:
As you already tried, shutdown the socket on the server before closing to force a FIN to be sent before the RST
Read the data in question but never process it (taking up bandwidth for no reason)

Client Socket not getting reponse bytes in .NET

I am creating and sending a message on server socket and not getting any response in return , I would like to know what could be possible reasons for the same. Below is my sample code for client socket
static void Main()
{
int _DCPport = 9090;
IPHostEntry ipHostInfo = Dns.GetHostEntry("HostName");
Console.WriteLine("Got the IP Host Info" , ipHostInfo.ToString ());
IPAddress ipAddress = ipHostInfo.AddressList[0];
Console.WriteLine("Got the IP hadress Info");
//End point of the host where the socket will be connected
IPEndPoint remoteDAPEndPoint = new IPEndPoint(ipAddress, _DCPport);
// Create a clientSocket that connects to host
Socket clientDAP = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
clientDAP.Connect(remoteDAPEndPoint);
Console.WriteLine("Client socket connected to remote end point");
#region Input variables
string requestString = "Hello";
string responseString = "";
byte[] requestByte = System.Text.Encoding.UTF8.GetBytes(requestString);
byte[] responseByte = new byte[1024];
StringBuilder messageBuilder = new StringBuilder();
int byteResult = 0;
#endregion
try
{
//sending the string as bytes over the socket
Console.WriteLine("Sending the input " + requestString);
clientDAP.Send(requestByte);
}
catch (SocketException eX)
{
Console.WriteLine(eX.Message);
}
try
{
//recieving the response bytes
byteResult = clientDAP.Receive(responseByte, clientDAP.Available, SocketFlags.None);
Console.WriteLine("Recieved {0} bytes as response from remote end point" , byteResult);
if (clientDAP.Connected)
{
responseString = Encoding.UTF8.GetString(responseByte);
messageBuilder.Append(responseString);
}
}
catch (SocketException eX)
{
Console.WriteLine(eX.Message);
}
clientDAP.Shutdown(SocketShutdown.Both);
clientDAP.Disconnect(true);
string sResult = messageBuilder.ToString();
Console.WriteLine(sResult);
}
I am not getting any bytes when i call socket.Recieve() , Any reasons why such is happening ?
From Socket.Send:
There is also no guarantee that the data you send will appear on the network immediately. To increase network efficiency, the underlying system may delay transmission until a significant amount of outgoing data is collected. A successful completion of the Send method means that the underlying system has had room to buffer your data for a network send
Which means that the data may not have even arrived at the server yet when your call to Send has completed. Let alone that the server has had time to process your data and return a response.
And yet your code charges straight ahead to try to receive the server's response. This isn't unreasonable, in and of itself. Your call to Receive would have blocked until it had received some data if you had specified the size of your buffer, rather than using Available, which will happily return 0 if there's no data yet available. So your Receive call is asking for up to 0 bytes and that's how many you're being given.
So change this line
byteResult = clientDAP.Receive(responseByte, 1024, SocketFlags.None);
(Or better yet, introduce a constant and/or use responseByte.Length or switch to an overload where you don't explicitly specify how many bytes you want)

Why can't I use the TCP client to send two message? (continuation)

This is a continuation of an earlier question. I am starting a new thread so that I can show the latest complete server and client code, including all of the suggestions I have received in that thread and on Reddit.
I am running under Windows 7 Pro.
I have a very simple TCP server written in Python. It creates a socketserver object and waits for a message. When one arrives, the server prints it to its console and sends a simple acknowledgement back through the same port.
The client sends a numbered message to the server, waits for an acknowledgement, and displays it. It then asks the user if another message should be sent.
The first message is sent and acknowledged successfully. On the client side, it appears that the second message is sent successfully; the call to the network stream's Write() method succeeds. But when the Read() message is called to get the acknowledgement, an exception is thrown: "An established connection was aborted by the software in your host machine."
Here is the server code:
import json
import threading
import socketserver
import time
with open('CAPS_TWMS_config.json', 'rt') as c:
caps_config = json.load(c)
# We are listening on this port and all defined IP addresses
# listenPort = 5001
listenPort = caps_config["listen_port"]
# Were to send the information to.
clientIPAddress = '127.0.0.1' # socket.gethostbyname('client')
# clientPort = 12345
clientPort = caps_config["send_port"]
dsnName = caps_config["dsn_name"]
# Message sequence number
sequence_num = 1
exit_app = False
class ListenSocketHandler(socketserver.BaseRequestHandler):
"""
The RequestHandler class for our server.
It is instantiated once per connection to the server, and must
override the handle() method to implement communication to the
client.
"""
def __init__(self, request, client_address, this_server):
socketserver.BaseRequestHandler.__init__(self, request, client_address, this_server)
self.timeout = 10
def handle(self):
try:
data = self.request.recv(1024).decode()
# print (str.format("dataString[21]: {0}; dataString[24:26]: {1}", data[21], data[24:26]))
print ('ListenSocketHandler recv()-> "%s"' % data)
print ('ListenSocketHandler recv().length-> "%d"' % len(data))
if len(data) > 0:
self.request.send("I got a message!".encode())
return
except Exception as value:
print('ListenSocketHandler - %s' % str(value))
return
class ListenServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
"""
The multi-threaded server that will spawn threads running the Socket Handler for each
connection
"""
pass
if __name__ == '__main__':
try:
# Create the Server Handler for connections to this computer listening on all IP addresses,
# change '' to 'x.x.x.x' to listen on a specific IP network. This class will listen for messages # from CAPS.
server = ListenServer(('', listenPort), ListenSocketHandler)
ip, port = server.server_address
# Start a thread with the server -- that thread will then start one
# more thread for each request
server_thread = threading.Thread(target=server.serve_forever)
# Exit the server thread when the main thread terminates
server_thread.setDaemon(True)
server_thread.start()
while not exit_app:
time.sleep(1)
print ('Out of main loop.')
server.shutdown()
server.server_close()
except Exception as value:
print("Failed to do something: %s", str(value))
Here is the client code:
private void button1_Click(object sender, EventArgs e)
{
TcpClient client = new TcpClient();
try
{
client.Connect("127.0.0.1", 5001);
NetworkStream stream = client.GetStream();
int messageCount = 1;
while (true)
{
// Translate the passed message into ASCII and store it as a Byte array.
string message = string.Format("This is message {0}", messageCount++);
Byte[] data = System.Text.Encoding.ASCII.GetBytes(message);
// Send the message to the connected TcpServer.
stream.Write(data, 0, data.Length);
// Receive the TcpServer.response.
// Buffer to store the response bytes.
data = new Byte[1024];
// String to store the response ASCII representation.
String responseData = String.Empty;
// Read the first batch of the TcpServer response bytes.
Int32 receivedCount = 0;
int sleepCount = 0;
while (receivedCount == 0)
{
receivedCount = stream.Read(data, 0, data.Length);
responseData = System.Text.Encoding.ASCII.GetString(data, 0, receivedCount);
if (receivedCount == 0)
{
Thread.Sleep(250);
if (sleepCount++ > 20)
{
MessageBox.Show("Response timeout.");
break;
}
}
}
if (MessageBox.Show("Reply: " + responseData + " Try again?", "Try again?", MessageBoxButtons.YesNo) == DialogResult.No)
{
break;
}
}
client.Close();
}
catch (Exception ex)
{
MessageBox.Show("Failed to do something with TcpClient: " + ex.Message);
}
}
In your code, every time when a new client is connected it is reading the data and acknowledges to client and handler is closed(i.e. return) immediately after the following statement
self.request.send("I got a message!".encode())
return
Hence the connection is closed.and further command from client is not sending. You can wait in a loop to receive and acknowledge.

Categories