I have a problem with reliably read a bluetooth stream.
It's the first time I worked with bluetooth connections.
The application communicates with a Arduino over a bluetooth module.
It will send a command and get a response.
For example, the response should look something like this:
100,200,300,400
This is what I get:
1
and if I get another response (also if it should look completely different) I get rest of the response requested before:
00,200,300,400
Sometimes I even get an empty response.
Here is the code I use to read and write to the stream:
void BluetoothClientConnectCallback(IAsyncResult result)
{
try
{
BluetoothClient client = (BluetoothClient)result.AsyncState;
client.EndConnect(result);
NetworkStream stream = client.GetStream();
stream.ReadTimeout = 1000;
_frm.printMsg("Connected!", false);
byte[] receive = new byte[1024];
while (true)
{
while (!ready) ;
if (stopConnection == true)
{
return;
}
try
{
stream.Write(message, 0, message.Length);
}
catch
{
_frm.printMsg("Error occurred while writing stream.", true);
}
try
{
if (Commands.awaitresponse == true)
{
Array.Clear(receive, 0, receive.Length);
readMessage = "";
do
{
stream.Read(receive, 0, receive.Length);
readMessage += Encoding.ASCII.GetString(receive);
}
while (stream.DataAvailable);
_frm.printMsg("Received: " + readMessage, false);
Commands.awaitresponse = false;
}
}
catch
{
_frm.printMsg("Error occurred while receiving stream.", true);
}
ready = false;
}
}
catch
{
_frm.printMsg("Error occurred while connecting.", true);
}
}
I was looking a while into it, but couldn't come to a solution.
After some more debugging and testing I came to a solution by myself.
I added 1 secound of delay Thread.Sleep(1000); before reading the stream.
All packages are now red correctly.
Related
I have inherited the code below, from another developer, which makes requests to an external system.
I call the GenerateRequest method using different values for the 'method' parameter (from a BackgroundWorker) all of which work fine. When I then make a second call it still works for all but one of the 'method' values (which also contains different values for the 'parameters' value, I'll include the calls too below), which hangs on the StreamReader ReadLine() call. However, if I debug and step through the code allowing 10-20 seconds, the output shows a few 'The thread 0xd0f0 has exited with code 0 (0x0)' messages and the code then works.
I feel I have an issue with the thread from which I'm doing this work, but I can't figure it out, please help.
This works everytime;
ClientParameters parameters = new ClientParameters();
string request = requestHandler.GenerateRequest("GetFunctions", parameters);
This only works the first time, unless I debug and step through, allowing time for threads to exit.
ClientParameters parameters = new ClientParameters();
parameters.Filter = new ClientParametersFilter();
parameters.Filter.Demographics = "";
parameters.Filter.Medication = "";
parameters.Filter.MinEffectiveDate = DateTime.Now;
parameters.Filter.MaxEffectiveDate = DateTime.MaxValue;
string request = null;
try
{
request = requestHandler.GenerateRequest("GetRecord", parameters);
}
catch(Exception e)
{
// log error
return null;
}
Hear is the class for making requests;
public class MyRequestHandler : IRequestHandler{
public string GenerateRequest(string method, ClientParameters parameters)
{
ClientIntegrationRequest request = new ClientIntegrationRequest();
request.APIKey = ApplicationSettings.APIKey;
request.Function = method;
request.FunctionVersion = 1.0M;
request.RequestUID = DateTime.Now.ToString();
request.DeviceID = ApplicationSettings.DeviceId;
request.DeviceVersion = ApplicationSettings.DeviceVersion;
request.FunctionParameters = parameters;
XmlSerializer ser = new XmlSerializer(typeof(ClientIntegrationRequest));
string xml;
using (MemoryStream m = new MemoryStream())
{
ser.Serialize(m, request);
// reset to 0
m.Position = 0;
xml = new StreamReader(m).ReadToEnd();
}
try
{
TcpClient tcpClient = new TcpClient("127.0.0.1", ApplicationSettings.Port);
NetworkStream netStream = tcpClient.GetStream();
if (netStream.CanWrite)
{
xml = xml + "\n";
Byte[] sendBytes = Encoding.UTF8.GetBytes(xml);
netStream.Write(sendBytes, 0, sendBytes.Length);
netStream.Flush();
}
else
{
tcpClient.Close();
netStream.Close();
return null;
}
netStream = tcpClient.GetStream();
if (netStream.CanRead)
{
StreamReader l_textReader = new StreamReader(netStream);
string str = l_textReader.ReadLine(); // Here's the issue
l_textReader.Close();
tcpClient.Close();
netStream.Close();
return str.ToString();
}
else
{
tcpClient.Close();
netStream.Close();
return null;
}
}
catch (SocketException e)
{
// log error
return null;
}
catch (Exception e)
{
// log error
return null;
}
}}
If you look the Microsoft example: https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.tcpclient.getstream?view=netframework-4.7.2
you can view that the code read the client stream by low level code reading the content returned by a byte array:
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);
}
Can you try this reading method?
I have a TCP server which writes data back to the client only for certain messages which the clients sends to the server.
It is basically is a command based server for which the server responds with a string only for certain commands otherwise nothing is sent back to the client.
The code given below is an approach which assumes that if any data is sent by the server it shows it as "MESSAGE FROM SERVER" appended with the data which was sent.
class TcpEchoClient
{
static void Main(string[] args)
{
Console.WriteLine("Starting echo client...");
string ipaddress = "127.0.0.1";
TcpClient client = null;
NetworkStream netstream = null;
try
{
client = new TcpClient(ipaddress,1000);
netstream = client.GetStream();
}
catch
{
Console.ReadKey();
Environment.Exit(0);
}
while(true)
{
Console.WriteLine("Message : ");
string t = Console.ReadLine();
string readdata = null;
Console.WriteLine("\n");
if (write(t,netstream))
{
Console.WriteLine("Message sent.");
if (client.Available!=0)
{
readdata = read(netstream);
Console.WriteLine("MESSAGE FROM SERVER : "+readdata);
}
}
else
{
Console.WriteLine("Unable to send message.");
}
}
}
static bool write(string dat, NetworkStream stream)
{
try
{
StreamWriter writer = new StreamWriter(stream) { AutoFlush = true };
try{writer.WriteLine(dat);}
catch (IOException){return false;}
if (SHAHash(dat, "DATA") != SHAHash(read(stream), "DATA"))
return false;
}catch (InvalidOperationException){return false;}
return true;
}
static string read(NetworkStream stream)
{
StreamReader reader = new StreamReader(stream);
string readdata = null;
try
{
readdata = reader.ReadLine();
reader.BaseStream.Flush();
}
catch(IOException)
{
return null;
}
return readdata;
}
}
The function SHAHash is not shown in this post. Its format is SHAHash(message,salt).
The problem faced is that messages sent by the server is not always read by the client. Sometimes the data sent by the server shows up a the client console, and sometimes it does not.
What correction should I make to the above code so that I can read data from the server only when it sends it. That is I require the following code to be executed only when the server sends some data to the client otherwise it should not be executed.
readdata = read(netstream);
Console.WriteLine("MESSAGE FROM SERVER : "+readdata);
Be prudent when using flush or autoflush. Sometimes it executes before send/receive operations... but this usually happens when working with threads.
My first tip that the stream readers/writers are not destructed properly. Try packing them into a using statement.
TCP isnt synchronous so you can't write data and expect the response to be available immediately. When you do the following check
if (client.Available!=0)
there is no guarantee that the server has sent any response yet. You need to keep checking until there is data available or read the data asynchronously
I would use NetworkStream.BeginRead and callbacks to get the server response
class StreamData
{
public NetworkStream netstream;
public byte[] myReadBuffer;
}
class TcpEchoClient
{
static void Main(string[] args)
{
Console.WriteLine("Starting echo client...");
string ipaddress = "127.0.0.1";
TcpClient client = null;
NetworkStream netstream = null;
try
{
client = new TcpClient(ipaddress, 13000);
netstream = client.GetStream();
}
catch
{
Console.ReadKey();
Environment.Exit(0);
}
var streamData = new StreamData
{
netstream = netstream,
myReadBuffer = new byte[1024],
};
netstream.BeginRead(streamData.myReadBuffer, 0, streamData.myReadBuffer.Length,
new AsyncCallback(myReadCallBack),
streamData);
while (true)
{
Console.WriteLine("Message : ");
string t = Console.ReadLine();
Console.WriteLine("\n");
if (write(t, netstream))
{
Console.WriteLine("Message sent.");
}
else
{
Console.WriteLine("Unable to send message.");
}
}
}
static void myReadCallBack(IAsyncResult ar)
{
var streamData = (StreamData)ar.AsyncState;
int bytesRead = streamData.netstream.EndRead(ar);
var readdata = Encoding.ASCII.GetString(streamData.myReadBuffer, 0, bytesRead);
//Be aware that this might not be the complete message depending on the size of the message and the buffer size
Console.WriteLine("You received the following message : " + readdata);
//Start waiting for more data
streamData.netstream.BeginRead(streamData.myReadBuffer, 0, streamData.myReadBuffer.Length,
new AsyncCallback(myReadCallBack),
streamData);
}
static bool write(string dat, NetworkStream stream)
{
try
{
StreamWriter writer = new StreamWriter(stream) { AutoFlush = true };
try { writer.WriteLine(dat); }
catch (IOException) { return false; }
//if (SHAHash(dat, "DATA") != SHAHash(read(stream), "DATA"))
// return false;
}
catch (InvalidOperationException) { return false; }
return true;
}
}
Currently developing a simple message server using sockets and sometimes the TCPClient receives the correct number of bytes but each byte is 0.
Here's the sender code.
try
{
//c.clientSocket.NoDelay = true;
// Send back an OK
var clientStream = c.clientSocket.GetStream();
var Response = JsonConvert.SerializeObject(new Packet("SERVER", c.ClientName, new List<Payload>() { new Payload(MessageLibrary.Commands.OK, null) }));
var msg = System.Text.Encoding.ASCII.GetBytes(Response);
clientStream.Write(msg, 0, msg.Length);
}
catch (Exception ex)
{
if (ExceptionRaised != null)
ExceptionRaised(c.ClientName, ex);
}
Response = "{\"TimeStamp\":\"2016-03-18T08:15:15.0881326+00:00\",\"Sender\":\"SERVER\",\"Payload\":[{\"Command\":\"OK\",\"CommandValue\":\"\"}],\"Destination\":\"GBCO0101\"}"
Msg contains 139 bytes
So this seems ok, here is the receiving code.
static void OnDataRecieved(IAsyncResult result)
{
TcpClient client = result.AsyncState as TcpClient;
// Get a stream object for reading and writing
try
{
NetworkStream stream = client.GetStream();
int ReadBytes = stream.EndRead(result);
if (ReadBytes == 0)
{
// Client gone
Console.WriteLine("Server lost");
}
else
{
// Translate data bytes to a ASCII string.
var data = System.Text.Encoding.ASCII.GetString(ClientReadBuffer, 0, ReadBytes);
ClientReadBuffer = new byte[ClientReadBuffer.Length];
stream.BeginRead(ClientReadBuffer, 0, ClientReadBuffer.Length, new AsyncCallback(OnDataRecieved), client);
ProcessData(data);
}
}
catch (Exception ex)
{
Console.WriteLine("lost connection");
Console.WriteLine(ex.Message);
}
}
If I take a look at ProcessData(data); I can see that data = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
ReadBytes = 139
So the right amount of bytes seems to be correct but the data itself is wrong. What can cause this?
It's unlikely.
Are you really using ClientReadBuffer on the first stream.BeginRead() (it's not included in the code above)? You probably have one somewhere that doesn't do the read in the same way.
And why do you create a new instance of it for every read? Waste of resources. Just reuse it.
Another thing is that TCP is stream based. Don't expect the bytes received to match the buffer that you sent. See this question for instance.
I wasn't taught networking very well. I know the basics of TCP/IP, but I'm facing an assignment where I have to manage multiple threads for multiple projects that communicate with each other in the same solution. I'm working in Window's Forms, C#, and for simplicity's sake I'll write only what needs to be written.
This is my Client class, which connects to the Server, handles messages to and from the server, and logs out from the server.
private TcpClient ClientConnection = null;
private NetworkStream CommandStream = null;
private Thread ClientThread = null;
bool isRunning = false;
public Client()
{
InitializeComponent();
try
{
//open the connection to the command port
ClientConnection = new TcpClient(address, Convert.ToInt32(port));
//Get the command stream
CommandStream = ClientConnection.GetStream();
if (CommandStream != null)
{
isConnected = true;
ClientThread = new Thread(Receive);
isRunning = true;
ClientThread.Start();
}
errorLabel.Visible = false;
}
catch (Exception ex)
{
errorLabel.Visible = true;
errorLabel.Text = "Failed to Connect";
}
}
private void Receive()
{
Byte[] data = new Byte[1024];
string message = string.Empty;
int BytesReceived = 0;
while (isRunning == true)
{
BytesReceived = CommandStream.Read(data, 0, 1024);
message = Encoding.ASCII.GetString(data, 0, BytesReceived);
//Do something with the message
}
}
private void logoutButton_Click(object sender, EventArgs e)
{
//Do logout logic here
errorLabel.Visible = false;
try
{
if (ClientConnection != null)
{
Byte[] command = new Byte[1024];
string commandStr = "SHUTDOWN";
command = Encoding.ASCII.GetBytes(commandStr);
CommandStream.Write(command, 0, command.GetLength(0));
ClientConnection.Close();
CommandStream.Close();
isRunning = false;
if (ClientThread.IsAlive == true)
{
errorLabel.Visible = true;
errorLabel.Text = "Thread still alive. Failed to Disconnect";
}
}
}
catch(Exception ex)
{
errorLabel.Visible = true;
errorLabel.Text = "Failed to Disconnect";
}
}
And this is my server class' Process Handler Function:
private void CommandProcessHandler(Socket client)
{
Byte[] data = new Byte[1024];
NetworkStream NetStream = null;
//Exception check
if(client.Connected == true)
NetStream = new NetworkStream(client);
while(bCommandListener == true)
{
//Read the command from the client
int bytes = NetStream.Read(data, 0, 1024);
string Command = Encoding.ASCII.GetString(data, 0, bytes);
//Do something with the command
if (Command == "SHUTDOWN")
{
NetStream.Close();
client.Close();
bCommandListener = false;
continue;
}
//Display the command in the command list box
string buttonPressed;
string buttonLetter;
buttonPressed = CommandDataObject.Instance.DecodeUIDFromMessage(Command);
buttonLetter = CommandDataObject.Instance.DecodeMessageFromUID(Command);
Command = ((client.RemoteEndPoint) as IPEndPoint).Address.ToString() + ">>>" + Command;
UpdateCommandsListBox(Command);
}
}
I'm sure that I'm starting up the threads perfectly fine, but the issue lies in shutting them down. This was an aspect I was never properly taught, and am having trouble learning. As it stands, I press the "log out" button, which should send a message to the server to shutdown, as well as close the TcpClient and NetworkStream. It also sets the isRunning bool, which keeps the client's Receive thread active, to false.
However, as it stands, I keep getting an error when I do this, on line 98 (during the client's Receive function, when BytesReceived = CommandStream.Read) as follows:
An unhandled exception of type 'System.IO.IOException' occurred in System.dll
Additional information: Unable to read data from the transport connection: A blocking operation was interrupted by a call to WSACancelBlockingCall.
I'm not sure what the error is referring to, but I've been stuck on this for a while and want to get it fixed. Any solutions?
When you use NetworkStream, it will throw an IOException if the underlying socket is closed while trying to read, see MSDN documentation . So your code is perfectly fine. You just have to handle the exception.
If you were to read the socket directly, you would just receive 0 when the socket is closed.
I have built a server that receives requests from a client and gives a response that depends on the request Type. If the request type is streaming, the server must send data array. While the server’s streaming data the client may send a stop request to stop the streaming. If the request and the response is transferred on the same TCP connection the server only receives the stop request when all the data has finished streaming to the client. I think I must use Asynchronous write to solve this problem. This is my code:
First I create a loop back to receive connection from clients:
while (!done)
{
try
{
Socket socket = listener.AcceptSocket();
ClientInteraction clIr = new ClientInteraction(socket, statusList);
Thread thread = new Thread(new ThreadStart(clIr.Process));
thread.Start();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
In Process function of ClientInteraction class :
Public void Process()
{
ns = new NetworkStream(socket);
while (true)
{
try
{
this.myReadBuffer = new byte[socket.ReceiveBufferSize];
this.numberOfBytesRead = ns.Read(myReadBuffer, 0, myReadBuffer.Length);
}
catch
{
break;
}
if (numberOfBytesRead == 0)
{
break;
}
else
{
HandleRequest(myReadBuffer, numberOfBytesRead);
}
}
}
In HandleRequest Function, if request’s STREAM, I will send data in an array to client:
Public void HanldeRequest(……)
{
myCompleteMessage = "";
myCompleteMessage =
String.Concat(myCompleteMessage, Encoding.ASCII.GetString(myReadBuffer, 0, numberOfBytesRead));
If(myCompleteMessage == “Stream”)
{
//I get data and call SendData function
foreach(.......)
{
//get data
........
SendData(data);
}
}
}
public void SendData(byte[] data)
{
try
{
//ns.Write(data, 0, data.Length);
ns.BeginWrite(data, 0, data.Length, new AsyncCallback(StreamData), null);
}
catch
{
}
}
public void StreamData(IAsyncResult asynResult)
{
if(asynResult != null)
ns.EndWrite(asynResult);
}
With this code, I connected with client, send data to client. But I still can’t receive Stop request until all data is streamed. Please show me the correct way to fix my problem. Thank you.
I think you can try using multithread to solve this problem. I have met this circumstance and multithread is a good choice to solve. You can create a thread to write and a thread to read.