Sockets 从半开插座读取
我正在尝试连接苹果推送通知服务,该服务使用一个简单的二进制协议,通过受TLS(或SSL)保护的TCP。协议指出,当遇到错误时(大约有10个定义良好的错误条件),APN将发送回错误响应,然后关闭连接。这会导致套接字半关闭,因为远程对等方关闭了该套接字。我可以看到这是一个优雅的关机,因为APNS使用tcpdump发送FIN和RST 在所有错误条件中,我可以在发送验证之前处理大多数错误。此操作失败的情况是,向无效的设备令牌发送通知时,由于令牌的格式可能不正确,因此无法轻松处理该令牌。令牌是不透明的32字节值,由APN提供给设备,然后向我注册。我无法知道提交给我的服务时它是否有效。据推测,APNS以某种方式对令牌进行校验和,从而可以对令牌进行快速验证 反正 我做了我认为正确的事情:-Sockets 从半开插座读取,sockets,tcp,apple-push-notifications,Sockets,Tcp,Apple Push Notifications,我正在尝试连接苹果推送通知服务,该服务使用一个简单的二进制协议,通过受TLS(或SSL)保护的TCP。协议指出,当遇到错误时(大约有10个定义良好的错误条件),APN将发送回错误响应,然后关闭连接。这会导致套接字半关闭,因为远程对等方关闭了该套接字。我可以看到这是一个优雅的关机,因为APNS使用tcpdump发送FIN和RST 在所有错误条件中,我可以在发送验证之前处理大多数错误。此操作失败的情况是,向无效的设备令牌发送通知时,由于令牌的格式可能不正确,因此无法轻松处理该令牌。令牌是不透明的32
a. open socket
b. try writing
c. if write failed, read the error response
不幸的是,这似乎不起作用。我想APNS正在发送一个错误响应,我没有正确读取它,或者我没有正确设置套接字。我尝试了以下技巧:-
X509证书=
新的X509证书(@“Foo.cer”、“密码”);
X509CertificateCollection集合=新的X509CertificateCollection();
收藏。添加(证书);
插座插座=
新套接字(AddressFamily.InterNetwork、SocketType.Stream、ProtocolType.Tcp);
socket.Connect(“gateway.sandbox.push.apple.com”,2195);
网络流=
新的网络流(socket、System.IO.FileAccess.ReadWrite、false);
stream.ReadTimeout=1000;
stream.WriteTimeout=1000;
SSL流=
新SSL流(流,真,
新的RemoteCertificateValidationCallback(ValidateServerCertificate),null);
sslStream.authenticatesClient(“gateway.sandbox.push.apple.com”,集合,
SslProtocols.Default,false);
sslStream.ReadTimeout=10000;
sslStream.WriteTimeout=1000;
//Task rdr=Task.Factory.StartNew(this.reader);
//rdr用于在每次读取之间并行读取5ms的套接字。
//现在没有使用,但另一种选择是尝试过的。
Random r=新随机(DateTime.Now.Second);
字节[]缓冲区=新字节[32];
r、 下字节(缓冲区);
字节[]resp=新字节[6];
字符串标记=toHex(缓冲区);
TimeSpan t=(DateTime.UtcNow-新的日期时间(1970,1,1));
int timestamp=(int)t.TotalSeconds;
尝试
{
对于(int i=0;i<1000;++i)
{
//生成通知;格式在APNS文档中发布。
var not=new ApplicationNotificationBuilder().withToken(缓冲区)。withPayload(
@{“aps”:{“警报”:“foo”,“声音”:“default”,“badge”:1}}')。过期(
timestamp).withIdentifier(i+1).build();
sslStream.Write(缓冲区);
sslStream.Flush();
Console.Out.WriteLine(“发送消息”#“+i);
int rd=SSL流读取(分别为0,6);
如果(rd>0)
{
Console.Out.WriteLine(“找到响应:+rd”);
打破
}
//不管我们发送的速度有多快或多慢
睡眠(500);
}
}
捕获(例外情况除外)
{
Console.Out.WriteLine(“未能写入…”);
int rd=SSL流读取(分别为0,6);
如果(rd>0)
{
Console.Out.WriteLine(“找到响应:+rd”);
}
}
//rdr.Wait();更改为非无限超时以允许错误读取器终止
我在Java中实现了APN的服务器端,在可靠地读取错误响应时遇到了问题(这意味着永远不会错过任何错误响应),但我确实设法获得了错误响应
你可以看到这一点,尽管它没有足够的答案
如果您从未设法读取错误响应,那么您的代码肯定有问题
你没有发布任何代码,所以我不知道你用什么二进制格式向APNS发送消息。如果您使用的是简单格式(以0字节开始,没有消息ID),您将无法从Apple获得任何响应。发布一些代码。任何待发送的数据在FIN之前到达。如果你看不懂的话
X509Certificate certificate =
new X509Certificate(@"Foo.cer", "password");
X509CertificateCollection collection = new X509CertificateCollection();
collection.Add(certificate);
Socket socket =
new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect("gateway.sandbox.push.apple.com", 2195);
NetworkStream stream =
new NetworkStream(socket, System.IO.FileAccess.ReadWrite, false);
stream.ReadTimeout = 1000;
stream.WriteTimeout = 1000;
sslStream =
new SslStream(stream, true,
new RemoteCertificateValidationCallback(ValidateServerCertificate), null);
sslStream.AuthenticateAsClient("gateway.sandbox.push.apple.com", collection,
SslProtocols.Default, false);
sslStream.ReadTimeout = 10000;
sslStream.WriteTimeout = 1000;
// Task rdr = Task.Factory.StartNew(this.reader);
// rdr is used for parallel read of socket sleeping 5ms between each read.
// Not used now but another alternative that was tried.
Random r = new Random(DateTime.Now.Second);
byte[] buffer = new byte[32];
r.NextBytes(buffer);
byte[] resp = new byte[6];
String erroneousToken = toHex(buffer);
TimeSpan t = (DateTime.UtcNow - new DateTime(1970, 1, 1));
int timestamp = (int) t.TotalSeconds;
try
{
for (int i = 0; i < 1000; ++i)
{
// build the notification; format is published in APNS docs.
var not = new ApplicationNotificationBuilder().withToken(buffer).withPayload(
@'{"aps": {"alert":"foo","sound":"default","badge":1}}').withExpiration(
timestamp).withIdentifier(i+1).build();
sslStream.Write(buffer);
sslStream.Flush();
Console.Out.WriteLine("Sent message # " + i);
int rd = sslStream.Read(resp, 0, 6);
if (rd > 0)
{
Console.Out.WriteLine("Found response: " + rd);
break;
}
// doesn't really matter how fast or how slow we send
Thread.Sleep(500);
}
}
catch (Exception ex)
{
Console.Out.WriteLine("Failed to write ...");
int rd = sslStream.Read(resp, 0, 6);
if (rd > 0)
{
Console.Out.WriteLine("Found response: " + rd); ;
}
}
// rdr.Wait(); change to non-infinite timeout to allow error reader to terminate