I am trying to send image via TcpClient and BufferedStream. The problem is that i cant send the data without disconnecting the TcpClient.
Send data:
while ((bytesread = bufferedinput.Read(buffer, 0, sizeBuffer)) > 0)
{
//Sending data
bufferedoutput.Write(buffer, 0, bytesread);
}
Receive data:
while ((bytesread = bufferedinput.Read(buffer, 0, buffsize)) > 0)
{
bufferedoutput.Write(buffer, 0, bytesread);
}
where :
NetworkStream serverStream = client.GetStream();
and BufferedStream bufferedoutput = new BufferedStream(serverStream);
The problem is that i must cast bufferedoutput.Close(); in the client side to get the data received by the server, but this disconnects my client, which is a problem. Any suggestions?
It is evident that by closing NetworkStream object associated with a TcpClient object, disconnects the client. Since TCP is a stream based protocol, you can do only one of two thing, either 1.] use networkstream.readtimeout to disconnect if no data is available till the readtimeout, OR 2.] devise a protocol to tell the receiver about the length of data, sender is willing to send, and read only that length of bytes.
Have you tried just bufferedoutput.Flush() instead?
Related
I'm following this example about the creation of an async tcp listener in C#.
MSDN Example
I see that all data is encoded as string to check for message completeness. More precisely, every message sent is already a string, which we append the 'EOF' char to for string termination.
The server side part i'm talking about is in this snippet:
public static void ReadCallback(IAsyncResult ar) {
String content = String.Empty;
// Retrieve the state object and the handler socket
// from the asynchronous state object.
StateObject state = (StateObject) ar.AsyncState;
Socket handler = state.workSocket;
// Read data from the client socket.
int bytesRead = handler.EndReceive(ar);
if (bytesRead > 0) {
// There might be more data, so store the data received so far.
state.sb.Append(Encoding.ASCII.GetString(
state.buffer, 0, bytesRead));
// Check for end-of-file tag. If it is not there, read
// more data.
content = state.sb.ToString();
if (content.IndexOf("<EOF>") > -1) {
// All the data has been read from the
// client. Display it on the console.
Console.WriteLine("Read {0} bytes from socket. \n Data : {1}",
content.Length, content );
// Echo the data back to the client.
Send(handler, content);
} else {
// Not all data received. Get more.
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
}
}
Is there a way, as i usually do with TcpListener/TcpClient classes, to check if received bytes are available on the socket?
I mean something like this:
private void HandleClientConnection(TcpClient client)
{
NetworkStream clientStream = client.GetStream();
MemoryStream memoryStream = new MemoryStream();
while (true)
{
int read = clientStream.ReadByte();
if (read != -1)
{
memoryStream.WriteByte((byte)read);
}
else
{
break;
}
}
}
I'm aware that i probably misunderstood this example, or at least the Begin/End part and the "legacy" async pattern. But this is my goal, do you know some way to get it working without involving strings?
You said : "Is there a way to check if received bytes are available on the socket?"
In general 'EndReceive' will block the thread until data is available. So you don't need to do anything because 'EndReceive' is doing all the job for you.
'bytesRead' is an int that shows you how much data you have received.
a quote from docs.microsoft
The EndReceive method will block until data is available.1
But if you are using a SYNC socket (which you are not) then it's another topic.
The Info
I have been developing a web http server in c# and decided to add a remote console feature. The console can be used from any location and uses a TcpListener (web server) and a TcpClient (remote console) to send commands and functions through.
The Code
This is what my server looks like:
TcpListener consoleListener = new TcpListener(consolePort);
consoleListener.Start();
byte[] bytes = new Byte[256];
string data = null;
while (true)
{
TcpClient client = consoleListener.AcceptTcpClient();
data = null;
byte[] msg = { 0 };
int i;
while ((i = client.GetStream().Read(bytes, 0, bytes.Length)) != 0)
{
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
if (data == "shutdown")
{
//Server shutdown logic.
}
//Other commands here...
else
{
msg = Encoding.ASCII.GetBytes("Invalid command. Type 'help' or '?' to get a list of commands.");
}
client.GetStream().Write(msg, 0, msg.Length); //sends return message to console
}
client.Close(); //closes connection between client and server after EVERY command. Connection is reopened when a new command is sent.
}
Note - The server is run on a separate thread to both the webserver and main console application thread.
This is my client:
public static string Communicate(string text)
{
try
{
TcpClient client = new TcpClient(ip, port); //initializes tcpclient (ip and port are correct)
byte[] data = System.Text.Encoding.ASCII.GetBytes(text); //converts text to bytes for stream writing
NetworkStream stream = client.GetStream();
stream.Write(data, 0, data.Length);
Console.WriteLine("Sent data: " + text);
data = new Byte[256];
string responseData = String.Empty; //initializes responsData string
Int32 bytes = stream.Read(data, 0, data.Length);
responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);
client.Close();
return responseData; //returns what server writes
}
catch (Exception ex)
{
return "An error occured\n" + ex.ToString();
}
}
The Problem
I can send one command to the server with a successful return. However, when I try and send another command, the server throws the error below:
System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. ---> System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
at System.Net.Sockets.Socket.Receive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags)
at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
--- End of inner exception stack trace ---
at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
at ---.Server.ConsoleListener() in X:\Users\---\Documents\Visual Studio 2013\Projects\---\---\Program.cs:line x
I know it is not firewall or administrator elevation problems as I can send one command through successfully. It is only on the second command sent that it throws this error.
Here is a screenshot describing the problem:
EDIT: By doing a little research, I found that the problem is most likely a result of a small error in my for loop. However, I do not know any way of fixing this as I do not know the exact problem :). Please help me identify it so I can fix it.
Thanks again
It seems that your client closes the connection after one message.
responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);
client.Close();
return responseData; //returns what server writes
If you want to persist the connection you should have a loop on the client similar to the one you have on the server. If you want to establish a new connection every time you should close the stream gracefully on the server and not have a loop like this. You will still need to loop in case the message is longer or you need to specify max length for the command.
I don't know if you fixed your issue or not but I guess you should post your workaround at least so others can check it.
I don't fully understand your issue but I had the same exception, but mine was triggered while the client disconnected and server was trying to read the stream (networkStream).
I had a single command for reading
networkstream.Read(mybuffer, 0, mybuffer.length);
As the checked answer suggested I changed that for:
do
{
byte[] buff = new byte[1];
networkstream.Read(buff, 0, 1);
myreceivedbuff.Add(buff);
} while (networkstream.DataAvailable)
this also produced the issue while client disc, so I had to do this
do
{
byte[] buff = new byte[1];
try
{
networkstream.Read(buff, 0, 1);
}
catch(exception ex)
{
throw new exception("The dam client disconnected in the middle of a transaction.");
}
myreceivedbuff.Add(buff);
} while (networksteam.DataAvailable)
I had to do this since it doesn't matter if its on a client or a server the exception is the same. host disconnection meanwhile my exception was CLIENT disconnection and this generic message misguided me to the solution.
Sorry if the code is not pasted from vs but I typed here so fix the capitalization so it can compile.
Hope this helps someone.
I had same solution. it is usually happens if client is disconnected. Solution from Alex RG is not working unfortunately. you will get another exception. Best solutions is described here by Microsoft
you need to check using CanRead
TcpClient tcpClient = new TcpClient ();
// Uses the GetStream public method to return the NetworkStream.
NetworkStream netStream = tcpClient.GetStream ();
if (netStream.CanRead)
{
// Reads NetworkStream into a byte buffer.
byte[] bytes = new byte[tcpClient.ReceiveBufferSize];
// Read can return anything from 0 to numBytesToRead.
// This method blocks until at least one byte is read.
netStream.Read (bytes, 0, (int)tcpClient.ReceiveBufferSize);
// Returns the data received from the host to the console.
string returndata = Encoding.UTF8.GetString (bytes);
Console.WriteLine ("This is what the host returned to you: " + returndata);
}
else
{
Console.WriteLine ("You cannot read data from this stream.");
tcpClient.Close ();
// Closing the tcpClient instance does not close the network stream.
netStream.Close ();
return;
}
i have a hardware than joins to a laptop(server) in ad hoc Network.
when server sends data alone, it works correctly. and client sends data alone , works correctly too.
but when server and client send data together , after a period of time , time out will occur.
after 35 and sometimes 33 packet time out will occur.
i changed transfer rate of hardware but it disconnects too.
although hard ware supports full duplex.
after time out , i ping hard ware and it is not on port.
and check port on server , and it is open.
how can i do?
byte[] bytes = new byte[512];
//try
//{
IPHostEntry ipHost = Dns.GetHostEntry("");
// Gets first IP address associated with a localhost
IPAddress add = ipHost.AddressList[3];
TcpListener tcpListener = new TcpListener(add, 6000);
tcpListener.Start();
TcpClient tcpClient = tcpListener.AcceptTcpClient();
NetworkStream stream = tcpClient.GetStream();
String data = null;
while (true)
{
int j = 0;
int i;
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
j = j + 1;
// Translate data bytes to a ASCII string.
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
AddItem("j="+j+" Received:"+ data);
// Process the data sent by the client.
//data = data.ToUpper();
byte[] msg = System.Text.Encoding.ASCII.GetBytes("thanks");
// Send back a response.
stream.Write(msg, 0, msg.Length);
AddItem("Sent:"+"thanks");
}
// Shutdown and end connection
tcpClient.Close();
The standard socket calls are all blocking, so if both participants are sending to each other, they each wait for their opposite to receive the message they send, causing a deadlock.
In .NET, there are three typical solutions:
Microsoft has a parallel API for asynchronous socket activity. It requires more overhead code than your example, but handles just about everything in a Windows-like manner.
You can handle the asynchronous activity yourself by testing for readable data before you write with Socket.Select(). This is a typical polling approach, but you're doing everything yourself and need to make sure there's no starvation or other bias.
Put your Read and Write code in different threads, so that blocking one doesn't block the entire program.
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.
i have a GPS device that will be installed in many trucks.
i can configure the device to send data statement "gps data, device id" over gprs to IP and Port.
i'm using TcpListener class to read the data on the server side.
TcpListener server = null;
private void listen_data()
{
Int32 port = controller_port;
IPAddress localAddr = IPAddress.Parse(this_ip);
server = new TcpListener(localAddr, port);
server.Start();
Byte[] bytes = new Byte[256];
String data = null;
while (true)
{
Console.Write("Waiting for a connection...-- ");
TcpClient client = server.AcceptTcpClient();
Console.Write("Connected!");
data = null; int i;
NetworkStream stream = client.GetStream();
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
}
}
}
that method is listening to what is coming on server ip and port.
i want to know if i configured the devices to send to the server on the same port.am i able to listen to all the devices or the first device to connect will be the only one ?
is this method the the best way to read the coming data from the devices?
do i need to configure a different port for each device and create a new listen thread for each device port?
sometimes i'm facing exceptions "the request channel timed out while waiting for a reply"
many thanks in advance for your help.
In your code you are listening to the all devices but only after finish read all data from the first device so you are receiving "the request channel timed out while waiting for a reply".You should have a different threads each one handle a tcpClient.
so the code should be something like:
TcpListener server = null;
private void listen_data()
{
Int32 port = controller_port;
IPAddress localAddr = IPAddress.Parse(this_ip);
server = new TcpListener(localAddr, port);
server.Start();
while (true)
{
Console.Write("Waiting for a connection...-- ");
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("new client connected");
ThreadPool.QueueUserWorkItem(new WaitCallback(HandleClient), client);//or use Task if 4.0 or new Thread...
}
}
private void HandleClient(object tcpClient)
{
TcpClient client = (TcpClient)tcpClient;
Byte[] bytes = new Byte[256];
String data = null;
int i;
NetworkStream stream = client.GetStream();
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
}
Console.WriteLine(data);
}
1) Both. You should be able to listen for all devices, but you often cannot with your code because the listener thread is tied up waiting for the stream from a device that connected earlier.
2) Probably not. IIRC, NetworkStream.Read returns 0 when the connection is closed by the peer device. Is this your protocol - ie. the device connects, sends some data and disconnects? If so that will work, though slowly. Anyway, there is another problem. You should be concatenating the bytes received on your stream to data, not just replacing them - Read() my return multiple times for one communication, perhaps even with a single byte each time, (unlikely, but permitted with TCP streams). You could keep a count of bytes rx. so far and use the 'offset' parameter to do this.
3) You only need one listening thread, ie. the one that calls AcceptTcpClient(). This thread should not be making blocking calls to receive data from the socket returned by AcceptTcpClient(). Either create/allocate/depool/whatever a new client-server thread to run your Read() loop for each 'client' socket returned by AcceptTcpClient() or use asynchronous IO.
4) Your single listener/read thread will be non-responsive for new connections while it is waiting on the NetworkStream - other devices will be unable to connect. The listener should get back to AcceptTcpClient() quickly and not wait for slow networks/devices to send data.
Rgds,
Martin