SerialPort BaseStream.EndRead return data even after disconnecting the device - serial-port

I have a device that is connected to the computer with a USB cable (Prolific USB to Serial ), I use the following code to read data
(code taken from https://www.vgies.com/a-reliable-serial-port-in-c/)
public class ReliableSerialPort : SerialPort
{
:
:
private void ContinuousRead()
{
byte[] buffer = new byte[4096];
Action kickoffRead = null;
kickoffRead = () =>
{
try
{
BaseStream.BeginRead(buffer, 0, buffer.Length, delegate (IAsyncResult ar)
{
try
{
int count = BaseStream.EndRead(ar);
byte[] dst = new byte[count];
Buffer.BlockCopy(buffer, 0, dst, 0, count);
OnDataReceived(dst);
}
catch (Exception exception)
{
Console.WriteLine($"OptimizedSerialPort exception!\r\n {exception.ToString()}");
}
kickoffRead();
}, null);
}
catch (Exception e)
{
//When disconnecting while accessing BaseStream an InvalidOperationException is raised, we ignore it
}
};
kickoffRead();
}
Every few seconds I also send a message to the device.
After disconnecting the cable from the device (the cable stays connected to the computer) I still get data!!!
i.e. the line int count = BaseStream.EndRead (ar);
Returns a number greater than 0.
the data is the message I sent.
What could be the reason?

Related

TCP Communication: How to send data from HoloLens by pressing a key and read data in a loop?

I need to establish a two-way communication like TCP between the UWP app (Hololens) as a client and Python on my PC as a server in a way that client sends the data when a key is pressed and receives the data in a while loop (when the data comes from the server).
I went through this link. This blog code is completely in accordance with what I need. The only problem is that it is written with system networking but I need to use windows networking instead.
Part of the code in Link1 of sending and reading functions:
Read stream
private void ListenForData()
{
try
{
socketConnection = new TcpClient("192.168.0.16", 5000);
Debug.Log("Connection successful");
Byte[] bytes = new Byte[1024];
while (true)
{
// Get a stream object for reading
using (NetworkStream stream = socketConnection.GetStream())
{
int length;
// Read incoming stream into byte array.
while ((length = stream.Read(bytes, 0, bytes.Length)) != 0)
{
var incomingData = new byte[length];
Array.Copy(bytes, 0, incomingData, 0, length);
// Convert byte array to string message.
string serverMessage = Encoding.ASCII.GetString(incomingData);
Debug.Log("server message received as: " + serverMessage);
updateText = serverMessage;
}
}
}
}
catch (SocketException socketException)
{
Debug.Log("Socket exception: " + socketException);
}
}
Write stream:
public void SendMessage(string clientMessage)
{
if (socketConnection == null)
{
return;
}
try
{
// Get a stream object for writing.
NetworkStream stream = socketConnection.GetStream();
if (stream.CanWrite)
{
//string clientMessage = "This is a message from one of your clients.";
// Convert string message to byte array.
byte[] clientMessageAsByteArray = Encoding.ASCII.GetBytes(clientMessage);
// Write byte array to socketConnection stream.
stream.Write(clientMessageAsByteArray, 0, clientMessageAsByteArray.Length);
Debug.Log("Client sent message: " + clientMessage);
}
}
catch (SocketException socketException)
{
Debug.Log("Socket exception: " + socketException);
}
}
Other published codes do not put read and write parts in separate functions.

How can I read byte array coming from server in UWP app?

I have a client-server app. The client is HoloLens 2 and the server is unity running on PC. I have created a socket using HoloLens but I can't read the byte array on HoloLens. In the connect method _inputStream and _outputStream are System.IO.Streams.
PC client uses System.Net.Sockets.TcpClient, System.Net.Sockets.NetworkStream but UWP (HoloLens) uses Windows.Networking.Sockets.StreamSocket.
In the ReceiveCallback I have an issue with int byteLenght = _inputStream.EndRead(result); When I tried this code on HoloLens I got the exception: "System.ArgumentException: The specified AsyncResult does not correspond to any outstanding IO operation". But I tested it with PC client (System.Net.Socket) and everything works fine.
Btw, I gave all related permissions.
How can I read byte array in UWP app?
Update:
#if UNITY_EDITOR
private void ConnectUWP(string host, string port)
#else
private async void ConnectUWP(string host, string port)
#endif
{
#if UNITY_EDITOR
errorStatus = "UWP TCP client used in Unity!";
#else
try
{
socket = new Windows.Networking.Sockets.StreamSocket();
Windows.Networking.HostName serverHost = new Windows.Networking.HostName(host);
_receivedData = new Packet();
_receiveBuffer = new byte[DataBufferSize];
await socket.ConnectAsync(serverHost, port);
successStatus = "Connected!";
_outputStream = socket.OutputStream.AsStreamForWrite();
//_streamWriter = new StreamWriter(_outputStream) { AutoFlush = true };
_inputStream = socket.InputStream.AsStreamForRead();
Task.Run(() => StreamToBytes(socket.InputStream));
}
catch (Exception e)
{
errorStatus = e.ToString();
Debugger.GetComponent<TextMeshPro>().text += "\n Exception: " + errorStatus;
}
#endif
#if !UNITY_EDITOR
public async Task StreamToBytes(Windows.Storage.Streams.IInputStream stream)
{
using (var reader1 = new Windows.Storage.Streams.DataReader(stream))
{
reader1.InputStreamOptions = Windows.Storage.Streams.InputStreamOptions.ReadAhead;
reader1.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;
reader1.ByteOrder = Windows.Storage.Streams.ByteOrder.LittleEndian;
//InBuffer is always 256,
//even if there is more data waiting. If I put a task.delay in it will always return 25
try
{
await reader1.LoadAsync(256);
}
catch (Exception ex)
{
//..
}
while (reader1.UnconsumedBufferLength > 0)
{
var bytes1 = new byte[reader1.UnconsumedBufferLength];
reader1.ReadBytes(bytes1);
_receivedData.Reset(await HandleData(bytes1));
await reader1.LoadAsync(256);
}
reader1.DetachStream();
}
}
private async Task<bool> HandleData(byte[] data)
{
int packetLength = 0;
_receivedData.SetBytes(data);
if (_receivedData.UnreadLength() >= 4)
{
// If client's received data contains a packet
packetLength = _receivedData.ReadInt();
if (packetLength <= 0)
{
// If packet contains no data
return true; // Reset receivedData instance to allow it to be reused
}
}
while (packetLength > 0 && packetLength <= _receivedData.UnreadLength())
{
// While packet contains data AND packet data length doesn't exceed the length of the packet we're reading
byte[] packetBytes = _receivedData.ReadBytes(packetLength);
ThreadManager.ExecuteOnMainThread(() =>
{
using (Packet packet = new Packet(packetBytes))
{
int packetId = packet.ReadInt();
_packetHandlers[packetId](packet); // Call appropriate method to handle the packet
}
});
packetLength = 0; // Reset packet length
if (_receivedData.UnreadLength() >= 4)
{
// If client's received data contains another packet
packetLength = _receivedData.ReadInt();
if (packetLength <= 0)
{
// If packet contains no data
return true; // Reset receivedData instance to allow it to be reused
}
}
}
if (packetLength <= 1)
{
return true; // Reset receivedData instance to allow it to be reused
}
return false;
}
#endif
When I tried this code on HoloLens I got the exception: "System.ArgumentException: The specified AsyncResult does not correspond to any outstanding IO operation".
Please refer to BeginRead method document, In the .NET Framework 4 and earlier versions, you have to use methods such as BeginRead and EndRead to implement asynchronous I/O operations. These methods are still available in the .NET Framework 4.5 to support legacy code; however, the new async methods, such as ReadAsync, WriteAsync, CopyToAsync, and FlushAsync, help you implement asynchronous I/O operations more easily. I suppose this old api could not compatible with HoloLens device, so please try to use ReadAsync to replace like the following
byte[] bytes = await StreamToBytes(_inputStream);
public async Task<byte[]> StreamToBytes(Stream stream)
{
byte[] bytes = new byte[stream.Length];
await stream.ReadAsync(bytes, 0, bytes.Length);
stream.Seek(0, SeekOrigin.Begin);
return bytes;
}
Or follow the official's processing that use DataReader to read ReadBytes, for more code please refer streamsocket.
Update
using (var reader1 = new DataReader(_inputStream)
{
reader1.InputStreamOptions = Windows.Storage.Streams.InputStreamOptions.Partial;
reader1.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;
reader1.ByteOrder = Windows.Storage.Streams.ByteOrder.LittleEndian;
await reader1.LoadAsync(256); //InBuffer is always 256,
//even if there is more data waiting. If I put a task.delay in it will always return 25
while (reader1.UnconsumedBufferLength > 0)
{
var bytes1 = new byte[reader1.UnconsumedBufferLength];
reader1.ReadBytes(bytes1);
await reader1.LoadAsync(256);
}
reader1.DetachStream();
}
I tried everything for TCP but TCP is nearly impossible for HoloLens with UWP app. So I tried UDP and it works perfectly (https://github.com/mbaytas/HoloLensUDP). I hope Microsoft put a TCP example for HoloLens 1 and 2 in near future. Thanks Nico for your help.

ReadAsync blocks only once (one read) then it won't block again in loop

I'm new with async sockets, I'm writing a server that receives data from many clients and needs to reply, when I start my Listener Task it will block on the ReadAsync line and wait for a packet to be received but then after it loops it will not block again to wait for another packet and does not receive any more data, I don't think I should restart the TcpListener with every packet, I cannot figure out what I'm missing.
private static async Task StartListener(int port)
{
var tcpListener = TcpListener.Create(port);
TcpClient tcpClient;
byte[] dataIn = new Byte[128];
byte[] dataOut = new Byte[128];
tcpListener.Start();
Console.WriteLine("Waiting for clients...");
tcpClient = await tcpListener.AcceptTcpClientAsync();
Console.WriteLine("A Client has connected");
var networkStream = tcpClient.GetStream();
int read = 0;
for (; ; )
{
try
{
read = await networkStream.ReadAsync(dataIn, 0, 128);
dataOut = Encoding.ASCII.GetBytes("$value=0");
await networkStream.WriteAsync(dataOut, 0, 8);
}
catch (Exception e)
{
Console.WriteLine("Exception!");
break;
}
}

SocketServer application, Client App won't start

I am trying to wrap my server and client console apps in a class so I can initialize it. When I try to code in the Client side in AppStart it won't let me call the StartClient method. It works just fine for my server, but not the client.
Here is the server class:
namespace Server
{
public class RunServer
{
// State object for reading client data asynchronously
public class StateObject
{
// Client socket.
public Socket workSocket = null;
// Size of receive buffer.
public const int BufferSize = 1024;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
// Received data string.
public StringBuilder sb = new StringBuilder();
}
public class AsynchronousSocketListener
{
// Thread signal.
public static ManualResetEvent allDone = new ManualResetEvent(false);
public AsynchronousSocketListener()
{
}
public static void StartListening()
{
// Data buffer for incoming data.
byte[] bytes = new Byte[1024];
// Establish the local endpoint for the socket.
// The DNS name of the computer
// running the listener is "host.contoso.com".
IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000);
// Create a TCP/IP socket.
Socket listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.
try
{
listener.Bind(localEndPoint);
listener.Listen(100);
while (true)
{
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
Console.WriteLine("Waiting for a connection...");
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
}
public static void AcceptCallback(IAsyncResult ar)
{
// Signal the main thread to continue.
allDone.Set();
// Get the socket that handles the client request.
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
// Create the state object.
StateObject state = new StateObject();
state.workSocket = handler;
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
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);
Random rand = new Random();
content = rand.ToString();
// 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);
}
}
}
private static void Send(Socket handler, String data)
{
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.ASCII.GetBytes(data);
// Begin sending the data to the remote device.
handler.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), handler);
}
private static void SendCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket handler = (Socket)ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = handler.EndSend(ar);
Console.WriteLine("Sent {0} bytes to client.", bytesSent);
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
public static int Main(String[] args)
{
StartListening();
return 0;
}
}
}
}
And here is the program that initializes it:
namespace AppStart
{
class Program
{
static void Main(string[] args)
{
Server.RunServer.AsynchronousSocketListener.StartListening();
Client.RunClient.AsynchronousClient. //Won't let me call StartClient method
}
}
}
Here is the Client side:
namespace Client
{
public class RunClient
{
// State object for receiving data from remote device.
public class StateObject
{
// Client socket.
public Socket workSocket = null;
// Size of receive buffer.
public const int BufferSize = 256;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
// Received data string.
public StringBuilder sb = new StringBuilder();
}
public class AsynchronousClient
{
// The port number for the remote device.
private const int port = 11000;
// ManualResetEvent instances signal completion.
private static ManualResetEvent connectDone =
new ManualResetEvent(false);
private static ManualResetEvent sendDone =
new ManualResetEvent(false);
private static ManualResetEvent receiveDone =
new ManualResetEvent(false);
// The response from the remote device.
private static String response = String.Empty;
private static void StartClient()
{
// Connect to a remote device.
try
{
// Establish the remote endpoint for the socket.
IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000);
// Create a TCP/IP socket.
Socket client = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// Connect to the remote endpoint.
client.BeginConnect(localEndPoint,
new AsyncCallback(ConnectCallback), client);
connectDone.WaitOne();
// Send test data to the remote device.
Send(client, "This is a test<EOF>");
sendDone.WaitOne();
// Receive the response from the remote device.
Receive(client);
receiveDone.WaitOne();
// Write the response to the console.
Console.WriteLine("Response received : {0}", response);
// Release the socket.
//client.Shutdown(SocketShutdown.Both);
//client.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void ConnectCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete the connection.
client.EndConnect(ar);
Console.WriteLine("Socket connected to {0}",
client.RemoteEndPoint.ToString());
// Signal that the connection has been made.
connectDone.Set();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void Receive(Socket client)
{
try
{
// Create the state object.
StateObject state = new StateObject();
state.workSocket = client;
// Begin receiving the data from the remote device.
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReceiveCallback), state);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void ReceiveCallback(IAsyncResult ar)
{
try
{
// Retrieve the state object and the client socket
// from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.workSocket;
// Read data from the remote device.
int bytesRead = client.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));
// Get the rest of the data.
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReceiveCallback), state);
}
else {
// All the data has arrived; put it in response.
if (state.sb.Length > 1)
{
response = state.sb.ToString();
}
// Signal that all bytes have been received.
receiveDone.Set();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void Send(Socket client, String data)
{
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.ASCII.GetBytes(data);
// Begin sending the data to the remote device.
client.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), client);
}
private static void SendCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = client.EndSend(ar);
Console.WriteLine("Sent {0} bytes to server.", bytesSent);
// Signal that all bytes have been sent.
sendDone.Set();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
public static int Main(String[] args)
{
StartClient();
return 0;
}
}
}
}

C# detect TCP client disconnection

I am working on TCP multithread server with C# window application form, and I am trying to detect if the machine of client is shutdown and disconnects from the server. I have read some posts and have some ideas:
How to determine if the tcp is connected or not?
Instantly detect client disconnection from server socket
But I'm not sure where to call the function IsConnected
My code is like the following:
public BindingList<Tablet> tabletList = new BindingList<Tablet>();
private Socket socket_Server = null;
private Thread myThread = null;
private Socket socket_Connect = null;
private Dictionary<string, Socket> dic = new Dictionary<string, Socket> { };
private string RemoteEndPoint;
socket_Server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ServerIP = IPAddress.Parse("192.168.2.146");
IPEndPoint point = new IPEndPoint(ServerIP, portNum);
socket_Server.Bind(point);
socket_Server.Listen(50);
myThread = new Thread(Listen_Disp);
myThread.IsBackground = true;
myThread.Start();
Console.WriteLine("Server start");
private void Listen_Disp()
{
try
{
while (true)
{
//This is not working
for (int i = 0; i < tabletList.Count; i++)
{
if (!SocketConnected(dic[tabletList[i].ip]))
{
Console.WriteLine(RemoteEndPoint + "disconnected");
}
}
try
{
socket_Connect = socket_Server.Accept();
RemoteEndPoint = socket_Connect.RemoteEndPoint.ToString();
Console.WriteLine(RemoteEndPoint + " is connected");
dic.Add(RemoteEndPoint, socket_Connect);
Tablet newTablet = new Tablet();
newTablet.ip = RemoteEndPoint;
newTablet.status = "Online";
tabletList.Add(newTablet);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
Console.WriteLine("end of while");
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
static class SocketExtensions
{
public static bool IsConnected(this Socket socket)
{
try
{
return !(socket.Poll(1, SelectMode.SelectRead) && socket.Available == 0);
}
catch (SocketException) { return false; }
}
}
Thanks for help.
There's a lot of misinformation on that subject, and some of it is present in the questions you linked. The only reliable way to detect a TCP disconnection is to try to write to the connection. A read timeout can also indicate a dropped connection, but it may mean a lot of other things too, such as a stuck server. An EOS condition when reading indicates a graceful disconnect. The IsConnected() method and friends only give you a history of what you have done to this socket: they don't give you the current state of the connection. They can't, because, absent a pending write request, there is no state to
know. TCP doesn't maintain anything akin to a dial tone.

Resources