C# client/server Question - c#

I'm incredibly confused as to what is going on here. I've been putting in break points and I just can't seem to understand. Basically, I have a client and a server. I want the client to send two separate strings of data. From putting in break points, I noticed that my client does in fact fill both strings with the appropriate data. However, the server never ever sees the second string. Why is this happening and how do I fix it? Any help at all would be greatly appreciate! Below is my code:
Server:
private static void HandleClientComm(object client)
{
/** creating a list which contains DatabaseFile objects **/
List<DatabaseFile> theDatabase = new List<DatabaseFile>();
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
StringBuilder response = new StringBuilder();
byte[] message = new byte[4096];
int bytesRead;
do
{
bytesRead = 0;
try
{
/*do
{
bytesRead = clientStream.Read(message, 0, message.Length);
response.Append(Encoding.ASCII.GetString(message, 0, bytesRead));
} while (clientStream.DataAvailable);*/
when i change this commented code to bytesRead = clientStream.Read(message, 0, 4096); i get an IOException Error that reads as follows: Unable to write data to the transport connection: An existing connection was forcibly closed by the remote host. Hence, i changed it to a do while loop. How do i get around this IOException and accept the second string?
ASCIIEncoding encoder = new ASCIIEncoding();
String file = encoder.GetString(message, 0, bytesRead);
Menu.Insert(theDatabase, file);
}
catch (Exception)
{
// A socket error has occured
break;
}
if (bytesRead == 0)
{
// The client has disconnected from the server
break;
}
} while (clientStream.DataAvailable);
// Release connections
clientStream.Close();
tcpClient.Close();
}
Client:
static void Main(string[] args)
{
TcpClient client = new TcpClient();
IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8888);
client.Connect(serverEndPoint);
NetworkStream clientStream = client.GetStream();
NetworkStream clientStream2 = client.GetStream();
ASCIIEncoding encoder = new ASCIIEncoding();
ASCIIEncoding encoder2 = new ASCIIEncoding();
String text = System.IO.File.ReadAllText("FirstNames.txt");
String text2 = System.IO.File.ReadAllText("LastNames.txt");
byte[] buffer = encoder.GetBytes(text);
Console.ReadLine();
clientStream.Write(buffer, 0, buffer.Length);
clientStream.Flush();
Console.ReadLine();
byte[] buffer2 = encoder2.GetBytes(text2);
clientStream2.Write(buffer2, 0, buffer2.Length);
clientStream2.Flush();
Console.ReadLine();
}
}

The communication between client and server happens like this (note that the order of steps is just for illustration purposes, the actual order at runtime may be different):
Client: client.Connect(serverEndPoint)
Server: HandleClientComm(newClient)
Client: clientStream.Write(buffer, 0, buffer.Length)
Server: bytesRead = clientStream.Read(message, 0, message.Length)
Note that Read is not guaranteed to read entire message. It is perfectly ok to return just the portion that has been received so far
Client: Console.ReadLine()
Server: while (clientStream.DataAvailable)
There is no data on the stream - the client has not sent any. This would likely happen even without ReadLine - there is a window of time before the client sends data again
Server: tcpClient.Close()
Client: clientStream2.Write(buffer2, 0, buffer2.Length)
You can get an exception here, or not - depending on whether the server has already closed the connection, in any case the server is not reading anymore.
You need to define your own message protocol that both server and client will honor. For example, you can have the client close the connection when it is done sending:
Client:
using (var client = new TcpClient("localhost", 8888))
using (var clientStream = client.GetStream())
{
var buffer = Encoding.ASCII.GetBytes( File.ReadAllText("FirstNames.txt") );
clientStream.Write(buffer, 0, buffer.Length);
buffer = Encoding.ASCII.GetBytes( File.ReadAllText("LastNames.txt") );
clientStream.Write(buffer, 0, buffer.Length);
}
Server:
using (var tcpClient = (TcpClient)client)
using (var clientStream = tcpClient.GetStream())
{
// Store everything that the client sends.
// This will work if the client closes the connection gracefully
// after sending everything
var receivedData = new MemoryStream();
clientStream.CopyTo(receivedData);
var rawBytes = receivedData.ToArray();
var file = Encoding.ASCII.GetString(rawBytes, 0, rawBytes.Length);
Menu.Insert(theDatabase, file);
}
The protocol is simple, and may be enough for your case. However, there are issues with it which should be addressed in production code (e.g. what if the client sends too much data, exhausting server memory, what if the client stops sending without closing the connection, etc.)

because while (clientStream.DataAvailable) is no longer true after your first client call.

You are exiting your client-recv loop in your server just because DatAvailable is false. This means if the client were to send a frame of data (which you consume) and pause then your server would see no data available at that moment and disconnect, even if a split second later another frame of data from the client was about to come in. Almost always, the end of a dialog is based on the content of the data being passed. You can certainly never try to rely on the fact that DataAvailable happens to be false one time.
As a follow-up, if you provide more info on the protocol that is used we can give more assitance. For example, if the prototcol is that two strings are sent with CR/LF at the end then the server loop should be inspecting the buffer for that to know when to disconnect.

Related

TCP Server gets ???????? instead of the real message

The server is written in c# and works correctly with a client I made in c#, now i'm trying to make an android client but the server doesn't get the real message, it gets just a lot of question marks.
Here is the server
TcpListener listen = new TcpListener(IPAddress.Any, 1200);
TcpClient client;
listen.Start();
client = listen.AcceptTcpClient();
NetworkStream stream = client.GetStream();
byte[] buffer = new byte[client.ReceiveBufferSize];
int data = stream.Read(buffer, 0, client.ReceiveBufferSize);
string message = Encoding.Unicode.GetString(buffer, 0, data);
Console.WriteLine(message);
this is the Android client
EditText et = (EditText) findViewById(R.id.EditText01);
String str = et.getText().toString()
PrintWriter out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())),
true);
out.println(str);
For example if I send the message "Hello", the server prints "???????????" and it happens the same for any message I send, even just 1 letter
I also tried with different methods like this one but the result is the same:
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
out.writeBytes(str);
Change:
string message = Encoding.Unicode.GetString(buffer, 0, data);
into:
string message = Encoding.UTF8.GetString(buffer, 0, data);
Try also UTF16. I think java uses this encoding now.

C# one tcp networkstream accepted

I have an issue with a TCP Listener.
The scenario is the following:
- I am receiving TCP packets (8192 Bytes each) and I would like to dump the data received from NetworkStream into a file (using FileStream);
- What I saw is that all the TCP packets arrived to the TCP listener but only the first 8192 Bytes are dumped into the file.
I believe that the NetStream is faster than the IO operation to the file.
My code is:
try
{
// Set TcpListener on port 8
Int32 portN = 8;
TcpListener server = new TcpListener(IPAddress.Any, portN);
// Start listening for client requests
server.Start();
Console.Write("Waiting for connection... ");
// Define File Name
string RcvFileName = #"c:\ethernet\out_file.raw";
// Buffer for reading data
int NrBytesRec;
Byte[] RecData = new Byte[8192];
// enter into listening loop
while (true)
{
// Perform a blocking call to accept requests.
// You can also user server.AcceptSocket() here.
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("Connected!");
// Get a stream object for reading and writing
NetworkStream netstream = client.GetStream();
// Append data into file
FileStream fs_wr = new FileStream(RcvFileName, FileMode.Append, FileAccess.Write);
// Dump data
while ((NrBytesRec = netstream.Read(RecData, 0, RecData.Length)) > 0)
{
fs_wr.Write(RecData, 0, NrBytesRec);
Console.WriteLine("Received: {0}", NrBytesRec);
}
netstream.Close();
fs_wr.Close();
//client.Close();
}

Calling method from loop in tcp server c#

I was writing a threaded tcp server and within this thread i wrote this:
private void HandleClientComm(object client)
{
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
byte[] message = new byte[4096];
int bytesRead;
byte[] buffer = null;
string answer = null;
while (true)
{
bytesRead = 0;
try
{
bytesRead = clientStream.Read(message, 0, 4096);
}
catch(Exception ex)
{
write("Error: " + ex.Message);
break;
}
if (bytesRead == 0)
{
write("Client connection lost!");
break;
}
txtLogger.Text += "Command accepted\n";
ASCIIEncoding encoder = new ASCIIEncoding();
clientreq = encoder.GetString(message, 0, bytesRead);
clientreq = clientreq.ToUpper();
if (clientreq == "CLIENTIP")
{
//THIS PART
answer = ((IPEndPoint)tcpClient.Client.RemoteEndPoint).Address.ToString();
buffer = encoder.GetBytes(answer);
}
//some more if's
clientStream.Write(buffer, 0, buffer.Length);
clientStream.Flush();
write("Server finished work.");
}
//some more code
Now i would like the THIS PART to be a method that will be called if the input is CLIENTIP, as requested from client. how i would be doind that.
Thanks in advance :)
By the way, every client req should be handled with new tcp connection.
I've tried this, with pretty bad result: the client freezes and NOTRespondin occured
public void IPKLIENTI()
{
TcpClient client = this.TCPMonitoruesi.AcceptTcpClient();
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
byte[] Bufer = null;
string answer = null;
ASCIIEncoding encoder = new ASCIIEncoding();
answer = ((IPEndPoint)tcpClient.Client.RemoteEndPoint).Address.ToString();
Bufer = encoder.GetBytes(answer);
}
To break up your if statement to handle the "CLIENTIP" request, you need to pass the TcpClient you are connected to to the method which does all the work (the IPKLIENTI method) as below.
if (clientreq == "CLIENTIP")
{
// call to IPCLIENTI retrives the RemoteEndPoint of the given TcpClient and encodes a response to be sent
buffer = IPKLIENTI(client, encoder);
}
A revised IPKLIENTI implementation is shown below. The key changes are:
Takes a TcpClient as a paramater rather than accepting a new TcpClient (this behavior lets you work with the TcpClient you recieved the request from and will later respond to, the old behavior attempted to accept another client all together)
Takes an ASCIIEncoding object to do the encoding with - you could re-build it as you used to, but this is tidier and ensures consistency in the future
We don't need to access the NetStream in this function, so we can do away with the call to GetStream
We return an encoded byte array to use as the response to the client when we call clientStream.Write() later in the HandleClientComm function
Revised IPKLIENTI method:
// Method takes a TcpClient Object and Encoder, returning a response to the CLIENTIP request
public byte[] IPKLIENTI(TcpClient tcpClient, ASCIIEncoding encoder)
{
string answer = ((IPEndPoint)tcpClient.Client.RemoteEndPoint).Address.ToString();
byte[] buffer = encoder.GetBytes(answer);
return buffer;
}
Essentially it just stores the intended response in a string (the RemoteEndPoint of the given TcpClient) and then encodes it via the given encoder, returning a byte array of the encoded response to be sent to the client.

Sending long XML over TCP

I'm sending an object (class name House) over TCP using the TcpListener on the server side in response to any message received from the TcpClient.
When the message is received, it is currently populating a text box named textBox1.
If I send a line of text, it works fine. You'll notice that I have a redundant line "Hello, I'm a server" for testing this purpose. But when I send the XML, it is cutting it off prematurely.
When I send serialised XML in to the stream, I'm also receiving this error from the server side:
Unable to read data from the transport connection: An existing
connection was forcibly closed by the remote host.
Here's my server code
// Set the variables for the TCP listener
Int32 port = 14000;
IPAddress ipaddress = IPAddress.Parse("132.147.160.198");
TcpListener houseServer = null;
// Create IPEndpoint for connection
IPEndPoint ipend = new IPEndPoint(ipaddress, port);
// Set the server parameters
houseServer = new TcpListener(port);
// Start listening for clients connecting
houseServer.Start();
// Buffer for reading the data received from the client
Byte[] bytes = new Byte[256];
String data = "hello, this is a house";
// Show that the TCP Listener has been initialised
Console.WriteLine("We have a TCP Listener, waiting for a connection...");
// Continuing loop looking for
while (true)
{
// Create a house to send
House houseToSendToClient = new House
{
house_id = 1,
house_number = 13,
street = "Barton Grange",
house_town = "Lancaster",
postcode = "LA1 2BP"
};
// Get the object serialised
var xmlSerializer = new XmlSerializer(typeof(House));
using (var memoryStream = new MemoryStream())
{
xmlSerializer.Serialize(memoryStream, houseToSendToClient);
}
// Accept an incoming request from the client
TcpClient client = houseServer.AcceptTcpClient();
// Show that there is a client connected
//Console.WriteLine("Client connected!");
// Get the message that was sent by the server
NetworkStream stream = client.GetStream();
// Blank int
int i;
// Loop for receiving the connection from the client
// >>> ERROR IS ON THIS LINE <<<
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
Console.WriteLine("here");
// Take bytes and convert to ASCII string
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("Received s, return house");
// Convert the string to a byte array, ready for sending
Byte[] dataToSend = System.Text.Encoding.ASCII.GetBytes("Hello, I'm a server");
// Send the data back to the client
//stream.Write(dataToSend, 0, dataToSend.Length);
// Send serialised XML in to the stream
xmlSerializer.Serialize(stream, houseToSendToClient);
}
// Close the connection
client.Close();
}
Client code
// Get the object serialised
var xmlSerializer = new XmlSerializer(typeof(House));
// Set the variables for the TCP client
Int32 port = 14000;
IPAddress ipaddress = IPAddress.Parse("127.0.0.1");
IPEndPoint ipend = new IPEndPoint(ipaddress, port);
string message = "s";
try
{
// Create TCPCLient
//TcpClient client = new TcpClient("localhost", port);
TcpClient client = new TcpClient();
// Convert the string to a byte array, ready for sending
Byte[] dataToSend = System.Text.Encoding.ASCII.GetBytes(message);
// Connect using TcpClient
client.Connect(ipaddress, port);
// Client stream for reading and writing to server
NetworkStream stream = client.GetStream();
// Send the data to the TCP Server
stream.Write(dataToSend, 0, dataToSend.Length);
//xmlSerializer.Serialize(stream, houseToSend);
// Buffer to store response
Byte[] responseBytes = new Byte[256];
string responseData = String.Empty;
// Read the response back from the server
Int32 bytes = stream.Read(responseBytes, 0, responseBytes.Length);
responseData = System.Text.Encoding.ASCII.GetString(responseBytes, 0, bytes);
textBox1.Text = responseData;
// Close the stream and the client connection
stream.Close();
client.Close();
}
catch (SocketException e)
{
MessageBox.Show(e.ToString());
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
I've marked on the code where the error is appearing.
Is it because the message is too long?
Your client code is assuming that the entire message will come through in one call to the Read(...) method, which is absolutely wrong. From the MSDN docs: "An implementation is free to return fewer bytes than requested even if the end of the stream has not been reached."
It's possible that, for a 1024-byte XML document, you may have to call Read(...) 1024 times to get the entire message.
Really, you'd do well to send a four-byte length before you send the XML, so that the client knows how much data to expect. The client will read four bytes, convert that to an integer length, then read that many more bytes, then turn those bytes into XML.

TCP Client Server Problem

I have the following code for the server application:
TcpListener recSock = new TcpListener(400);
recSock.Start();
TcpClient client = recSock.AcceptTcpClient();
NetworkStream netStream = client.GetStream();
Byte[] data = new Byte[256];
int i;
while((i = netStream.Read(data, 0, data.Length)) != 0) {
string cmd = ASCIIEncoding.ASCII.GetString(data, 0, i);
Console.WriteLine(cmd);
if(cmd == "R") {
RestartScheduler();
}
}
client.Close();
And the client looks like:
TcpClient client = new TcpClient();
client.Connect("VM-SCHEDULER", 400);
NetworkStream netStream = client.GetStream();
Byte[] data = ASCIIEncoding.ASCII.GetBytes("R");
netStream.Write(data, 0, data.Length);
netStream.Flush();
client.Close();
All is fine the first time the client connects the "R" command is read and the RestartScheduler() method is called, however all subsequent commands fail until the server is restarted.
I have used telnet to connect to the server after the first attempt and it is still listening on the port.
Where am i going wrong?
EDIT:
Basically what I am trying to accomplish is that the server will listen always, a client will then connect send the "R" command then close the connection. The client must be able to connect to the server at any time to issue the command. There will only be 1 client at any given time.
If there is no data to be read, netStream.Read will return 0 and your while loop will exit, disconnecting the client at client.Close();. You have nothing in your code to allow the server to continue receiving in this scenario.
You need to keep listening for connections until the application is shutdown, so put the listen and GetStream in a while loop. Since Stream.Read is a blocking call, you should have some data for the data reading while loop (unless timeout occurs). Otherwise it will close the connection and go back to listening for a new one.
Note: I've not included any error handling in here, you'll need to add that yourself.
TcpListener recSock = new TcpListener(400);
recSock.Start();
while (!stopping)
{
TcpClient client = recSock.AcceptTcpClient();
NetworkStream netStream = client.GetStream();
Byte[] data = new Byte[256];
int i = netStream.Read(data, 0, data.Length);
while(i != 0)
{
string cmd = ASCIIEncoding.ASCII.GetString(data, 0, i);
Console.WriteLine(cmd);
if(cmd == "R") {
RestartScheduler();
}
i = stream.Read(bytes, 0, bytes.Length);
}
client.Close();
Thread.Sleep(1); // Will allow the stopping bool to be updated
}
Module level add:
private bool stopping = false;
In your shutdown function:
stopping = true;
Are you connecting multiple times, or sending multiple commands down the same connection? If you could provide a short but complete program to demonstrate the problem, that would really help.
My guess is that you're running into problems due to reading multiple commands from a single connection in one go, but it's hard to know without more information. Don't forget that a single call to Write from the client can easily result in multiple reads at the server end - or vice versa.
Well the server will exit after the first command it receives, no?
At the least, you're missing using statements:
TcpListener recSock = new TcpListener(IPAddress.Loopback, 400);
recSock.Start();
using (TcpClient client = recSock.AcceptTcpClient())
{
using (NetworkStream netStream = client.GetStream())
{
Byte[] data = new Byte[256];
int i;
while ((i = netStream.Read(data, 0, data.Length)) != 0)
{
string cmd = Encoding.ASCII.GetString(data, 0, i);
Console.WriteLine(cmd);
if (cmd == "R")
{
RestartScheduler();
}
}
}
client.Close();
}
and
using (TcpClient client = new TcpClient())
{
client.Connect("VM-SCHEDULER", 400);
using (NetworkStream netStream = client.GetStream())
{
Byte[] data = Encoding.ASCII.GetBytes("R");
netStream.Write(data, 0, data.Length);
netStream.Flush();
}
client.Close();
}

Categories