I'm creating one web api application, and I want to send notification to iOS devices.
I've tried with pushsharp, but it works fine with few devices only, while sending it to multiple devices with expired/invalid tokens its not sending notifications to all devices.
So, I'm going with following code:
public async Task pushMessage(string deviceToken, string message)
{
int port = 2195;
String hostname = "gateway.sandbox.push.apple.com";
String certificatePath = "~/test.p12" // my certificate path
X509Certificate2 clientCertificate = new X509Certificate2(System.IO.File.ReadAllBytes(certificatePath), CommonSource.GetAppleCertificatePassword(), X509KeyStorageFlags.MachineKeySet);
X509Certificate2Collection certificatesCollection = new X509Certificate2Collection(clientCertificate);
TcpClient client = new TcpClient(hostname, port);
SslStream sslStream = new SslStream(client.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null);
try
{
sslStream.AuthenticateAsClient(hostname, certificatesCollection, SslProtocols.Tls, false);
MemoryStream memoryStream = new MemoryStream();
BinaryWriter writer = new BinaryWriter(memoryStream);
writer.Write((byte)0);
writer.Write((byte)0);
writer.Write((byte)32);
writer.Write(HexStringToByteArray(deviceToken.ToUpper()));
String payload = message.ToString();
writer.Write((byte)0);
writer.Write((byte)payload.Length);
byte[] b1 = System.Text.Encoding.UTF8.GetBytes(payload);
writer.Write(b1);
writer.Flush();
byte[] array = memoryStream.ToArray();
sslStream.Write(array);
sslStream.Flush();
// Read message from the server.
//byte[] response = ReadMessage(sslStream);
client.Close();
}
catch (System.Security.Authentication.AuthenticationException ex)
{
LogError(ex.Message);
client.Close();
}
catch (Exception e)
{
LogError(e.Message);
client.Close();
}
}
This code works exactly what I wanted.
But now I want to check response from APNS server. So I've checked with byte[] response = ReadMessage(sslStream);
And ReadMessage method looks like:
private byte[] ReadMessage(SslStream sslStream)
{
MemoryStream ms = new MemoryStream();
byte[] buffer = new byte[1024];
int bytes = -1;
do
{
bytes = sslStream.Read(buffer, 0, buffer.Length);
ms.Write(buffer, 0, bytes);
} while (bytes != 0);
return ms.ToArray();
}
But when I run this, it stuck at bytes = sslStream.Read(buffer, 0, buffer.Length);
I'm not able to figure out the issue.
Can anyone tell me, what is the issue with my code?
According to this article
The problem with Apples Push Notification Service… Solutions and Workarounds…
Apple never sends a response for messages that succeeded.
An error response may not immediately be returned before you have a chance to send more notifications to the stream, but before Apple closes the connection. These notifications that might still ‘make it through’ are left in limbo. They are never acknowledged or delivered, and never have error responses returned for them.
So in a case where your request works as intended there will be no response. That would mean that your attempt to read a response will not get anything and this is what you are experiencing when you can't get past the read line. It is waiting for a response that might never come.
Related
I'm trying to use tcpclient to retrieve data from a tcp server, sending a request and receiving a response, it works fine except for one thing.
When I try to use multiple times networkstream.readasync and then networkstream.writeasync the readasync function reads the previous response of the previous writeasync and not of the last one.To fix that I have to set a timeout before reading. Instead of setting a timeout is there any way to wait until the new data are available?
Pseudocode Example:
connectasync(host,port);
//reads a hello message from the server
networkstram.readasync();
//sending a request to the server
networkstram.writeasync();
//reads again the hello message from the previous read
//not the response from the previously sended writeasync
networkstram.readasync()
Pseudocode Solution:
connectasync(host,port);
//reads a hello message from the server
networkstram.readasync();
//sending a request to the server
networkstram.writeasync();
//wait for 1 second
wait(1000)
//reads correctly
networkstram.readasync()
If you have any better way to wait the newly available data instead of using a fixed timeout let me know.
Thank you.
UPDATE
NOTE:I even tried with the synchronous version of read and write still the same.
Am Just using async to no block the user interface.
public async Task<string> sendQuery()
{
try
{
client.Connect(ConfigParameters.ip, ConfigParameters.port);
if (client.Connected == true)
{
Console.WriteLine("Connected");
var networkStream = client.GetStream();
// Receive data from server
//Receiving HELLO message from the server
byte[] buffer = new byte[1024];
await networkStream.ReadAsync(buffer, 0, buffer.Length);
var serverResponse = Encoding.ASCII.GetString(buffer);
Console.WriteLine("Server: " + serverResponse);
Array.Clear(buffer,0,buffer.Lenght);
Array.Resize(ref buffer, 1024);
// Send data to server
// send query to the server
string data = QueryStore.queryStart+QueryStore.query1.getLRC() + QueryStore.queryEnd;
buffer = System.Text.Encoding.ASCII.GetBytes(data);
await networkStream.WriteAsync(buffer, 0, buffer.Length);
Array.Clear(buffer,0,buffer.Lenght);
Array.Resize(ref buffer, 1024);
// Receive data from server
// receive still HELLO message
buffer = new byte[1024];
await networkStream.ReadAsync(buffer, 0, buffer.Length);
serverResponse = Encoding.ASCII.GetString(buffer);
Console.WriteLine("Server: " + serverResponse);
networkStream.Close();
client.Close();
return "ok";
}
}
catch(SocketException)
{
client.Close();
return "error";
}
finally
{
client.Close();
return "";
}
}
C# I am developing a MIP plugin for Milestone VMS.
I have a problem while connecting to SocketIO with C#.
I have tried to connect to SocketIO with TcpClient, Socket, ClientWebSocket
TcpClient tcpClient = new TcpClient();
tcpClient.Connect("127.0.0.1, 3001);
I also have tried to connect with ClientWebSocket but again no reaction in server side.
using (var client = new ClientWebSocket())
{
// await client.ConnectAsync(new Uri("ws://192.168.100.25:8090/?token="),timeout.Token);
await client.ConnectAsync(new Uri(LOCAL_PATH), timeout.Token);
var buffer = new ArraySegment<byte>(new byte[1000]);
var result = await client.ReceiveAsync(buffer, timeout.Token);
}
Can anyone provide some libraries that may serve as clients to SocketIO?
URI has this syntax: http://127.0.0.1:3001?token=xxx
here is a tested code that i use , supposing your server is running , you need to pass the IP or HostName and port number , then come the payload or message that you want to send :
private bool ConnectAndSendMessage(String server, Int32 port, String message)
{
try
{
// Create a TcpClient.
TcpClient client = new TcpClient(server, port);
// Translate the passed message into ASCII and store it as a Byte array.
Byte[] data = System.Text.Encoding.ASCII.GetBytes(message);
// Get a client stream for reading and writing.
NetworkStream stream = client.GetStream();
// Send the message to the connected TcpServer.
stream.Write(data, 0, data.Length);
// Buffer to store the response bytes receiver from the running server.
data = new Byte[256];
// String to store the response ASCII representation.
String responseData = String.Empty;
// Read the first batch of the TcpServer response bytes.
Int32 bytes = stream.Read(data, 0, data.Length);
responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);
// Close everything.
stream.Close();
client.Close(); return true;
}
catch (ArgumentNullException e)
{
_txtStyling.WriteCustomLine(string.Format("ArgumentNullException: {0} \n\n", e.Message), 14, false, false, Brushes.Red); return false;
}
catch (SocketException e)
{
_txtStyling.WriteCustomLine(string.Format("SocketException: {0} \n\n", e.Message), 14, false, false, Brushes.Red); return false;
}
}
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 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.
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.