gpt4 book ai didi

sockets - 从半开套接字读取

转载 作者:可可西里 更新时间:2023-11-01 02:43:45 24 4
gpt4 key购买 nike

我正在尝试连接到 Apple Push Notification Service,该服务使用基于受 TLS(或 SSL)保护的 TCP 的简单二进制协议(protocol)。该协议(protocol)表明,当遇到错误时(大约有 10 种明确定义的错误条件)APNS 将发回错误响应,然后关闭连接。这导致套接字半关闭,因为远程对等方关闭了套接字。我可以看到它正常关闭,因为 APNS 使用 tcpdump 发送 FIN 和 RST。

在所有错误情况中,我可以在发送前处理大部分错误并进行验证。失败的情况是当通知发送到无效的设备 token 时,由于 token 可能格式错误,因此无法轻松处理。 token 是不透明的 32 字节值,由 APNS 提供给设备,然后向我注册。我无法知道它在提交给我的服务时是否有效。据推测,APNS 以某种方式对 token 进行校验和,以便他们可以快速对 token 进行快速验证。

无论如何,

我做了我认为正确的事:-

a.  open socket
b. try writing
c. if write failed, read the error response

不幸的是,这似乎不起作用。我认为 APNS 正在发送错误响应,但我没有正确读回它,或者我没有正确设置套接字。我尝试了以下技术:-

  1. 每套接字使用一个单独的线程,每 5 毫秒左右尝试读取响应(如果有)。
  2. 在写入失败后使用阻塞读取。
  3. 在远程断开连接后使用最终读取。

我已经在 Windows 上使用 C# + .NET 4.5 并在 Linux 上使用 Java 1.7 进行了尝试。在任何一种情况下,我似乎都没有收到错误响应,并且套接字指示没有数据可供读取。

这些操作系统和/或框架是否支持半封闭套接字?似乎没有任何迹象表明这两种方式。

我知道我设置的方式是正确的,因为如果我使用一个有效的 token 和一个有效的通知,那些就会被传送。

作为对其中一条评论的回应,我正在使用增强的通知格式,因此响应应该来自 APNS。

这是我的 C# 代码:-

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

最佳答案

我在 Java 中为 APNS 实现了服务器端,并且在可靠地读取错误响应时遇到了问题(意思是 - 永远不会错过任何错误响应),但我确实设法获得了错误响应。

可以看到这个related question , 尽管它没有足够的答案。

如果您从未设法读取错误响应,那么您的代码一定有问题。

  1. 虽然不是 100% 可靠,但使用单独的线程阅读对我有用。
  2. 在写入失败后使用阻塞读取 - 这是 Apple 建议的做法,但它并不总是有效。有可能您发送了 100 条消息,而第一条消息的 token 无效,只有在第 100 条消息之后您才会收到写入失败。此时从套接字读取错误响应有时为时已晚。
  3. 我不确定你的意思。

如果你想保证错误响应的读取有效,你应该尝试在每次写入后读取,并有足够的超时时间。当然,这对于在生产中使用是不切实际的(因为它非常慢),但您可以使用它来验证您读取和解析错误响应的代码是否正确。您还可以使用它来遍历您拥有的所有设备 token ,并找到所有无效的设备 token ,以清理您的数据库。

您没有发布任何代码,所以我不知道您使用什么二进制格式向 APNS 发送消息。如果您使用的是简单格式(以 0 字节开头且没有消息 ID),您将不会收到来自 Apple 的任何响应。

关于sockets - 从半开套接字读取,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19988513/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com