下午好,
我正在尝试创建一个连接到 Apple 推送通知服务 (APNS) 并发送推送通知的套接字程序。
我想知道是否有人可以帮助我实际编写 APNS 通知。
您可以在下面看到我使用 Scott Klement 的套接字编程教程帮助我完成的程序。
可能与所有这些相关的代码在注释中标记为“APNS 通知格式开始”、“初始化”和“向 APNS 发送消息”,尽管我包含了整个程序以供引用。
我已阅读 Apple 网站 Provider Requirements 上的提供商要求但我仍然无法让一切正常工作。
我的程序编译,当我调试它/运行我通过建立实际连接的步骤时,我“认为”这部分没问题。
我希望在 item3 数据结构中的变量 errid 中从 Apple 取回错误标识符。 Apple 在提供者要求中声明,如果出现错误,他们会返回状态代码,但该特定变量仍为 1077952576
还有很多我不确定的事情
1) 我已获得作为 Base64 字符串的设备 token 。该字符串长度为 40 个奇数字符,但据我了解,Apple 声明设备 token 长度应为 32 个字节。在 RPGLE 中,1 个字符不是代表 1 个字节吗?如果是这种情况,那么我不能只将我的变量 token 声明为
D token 32a
因为它会被切断?
2) 当我在变量 errid 中从 Apple 接收到正确的错误标识符时,有没有人能告诉我我做错了什么?
任何帮助将不胜感激
H DFTACTGRP(*NO) BNDDIR('QC2LE')
D/copy socket_h
D/copy gskssl_h
*==============================================================*
* APNS Notification Format Begin
*==============================================================*
D request s 1000a varying
D framehdr ds
D command 3I 0 inz(2)
D framelen 10I 0
D framedta s 500a varying
D item1 ds
D itemid1 3I 0 inz(1)
D itemlen1 5I 0 inz(%size(token))
D token 64a
D item2 ds
D itemid2 3I 0 inz(2)
D itemlen2 5I 0
D payload 100a varying
D item3 ds
D itemid3 3I 0 inz(3)
D itemlen3 5I 0 inz(%size(errid))
D errid 10I 0
D item4 ds
D itemid4 3I 0 inz(4)
D itemlen4 5I 0 inz(%size(expire))
D expire 10I 0 inz(0)
D item5 ds
D itemid5 3I 0 inz(5)
D itemlen5 5I 0 inz(%size(priority))
D priority 10I 0 inz(10)
*==============================================================*
* APNS Notification Format End
*==============================================================*
D gsk_strerror PR * extproc('gsk_strerror')
D gsk_ret_value 10I 0 value
D CreateEnv PR like(gsk_handle)
D ConnSock PR 10I 0
d host 256A const
D port 10I 0 value
D UpgradeSock PR like(gsk_handle)
D SslEnv like(gsk_handle) value
D sock 10I 0 value
D CloseSsl PR
D Handle like(gsk_handle) value
D CloseSslEnv PR
D SslEnv like(gsk_handle) value
D ReportError PR
D EscapeMsg PR
D errMsg s 80A varying
D CRLF c x'0d25'
D env s like(gsk_handle)
D s s 10I 0
D connto ds likeds(sockaddr_in)
D SslSock s like(gsk_handle)
D cmd s 400A
D len s 10I 0
D bytesSent s 10I 0
D Reply s 1000A
D bytesRead s 10I 0
D left s 10I 0
D buf s *
D received s 10I 0
D dataPos s 10I 0
D wait s 1A
D rc s 10I 0
/free
// Initialize
token = 'MyDevToken';
payload = '{"aps":{"alert":"You have mail"}}';
itemlen1 = %len(payload);
framedta = item1 + item2 + item3 + item4 + item5;
framelen = %len(framedta);
request = framehdr + framedta;
// Create SSL Environment
env = CreateEnv();
If (env = *NULL);
EscapeMsg();
Endif;
// Connect a socket to an SSL server (using normal socket calls)
// NOTE: Sandbox is the development environment
s = ConnSock('gateway.sandbox.push.apple.com': 2195);
// Upgrade the socket to SSL
SSLSock = UpgradeSock(env: s);
If (SSLSock = *NULL);
EscapeMsg();
Endif;
// **** Formulate message to APNS ******
len = %len(%trimr(request));
callp gsk_secure_soc_write(SSLSock
: %addr(request)
: len
: bytesSent);
// Close everything and end the program
CloseSsl(SslSock);
CloseSslEnv(Env);
*inlr = *on;
/end-free
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* CreateEnv(): Create an SSL environment for client sockets
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
P CreateEnv B
D CreateEnv PI like(gsk_handle)
D rc s 10I 0
D SslEnv s like(Gsk_handle)
/free
// Create an SSL environment with default values:
rc = gsk_environment_open(SslEnv);
If (rc <> GSK_OK);
errMsg = %str(gsk_strerror(rc));
return *NULL;
Endif;
// Instruct environment to use the *SYSTEM certificate store
rc = gsk_attribute_set_buffer( SslEnv
: GSK_OS400_APPLICATION_ID
: 'SUMITOMO_APNS_PUSH'
:0 );
If (rc<>GSK_OK);
errMsg = %str(gsk_strerror(rc));
gsk_environment_close( SslEnv );
return *NULL;
Endif;
//Tell the environment that this is a client connection
rc = gsk_attribute_set_enum( SslEnv
: GSK_SESSION_TYPE
: GSK_CLIENT_SESSION );
If (rc <> GSK_OK);
errMsg = %str(gsk_strerror(rc));
gsk_environment_close( SslEnv );
return *NULL;
Endif;
// Activate the new environment
rc = gsk_environment_init( SslEnv );
If (rc <> GSK_OK);
errMsg = %str(gsk_strerror(rc));
gsk_environment_close( SslEnv );
return *NULL;
Endif;
return SslEnv;
/end-free
P E
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* ConnSock(): Create a TCP Socket and connect to a host
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
P ConnSock B
D ConnSock PI 10I 0
d host 256A const
D port 10I 0 value
D s s 10I 0
D addr s 10U 0
/free
// look up host
addr = inet_addr(%trim(host));
If (addr = INADDR_NONE);
p_hostent = gethostbyname(%trim(host));
If (p_hostent = *NULL);
errMsg = 'Host not found!';
EscapeMsg();
Endif;
addr = h_addr;
Endif;
// Create a socket
s = socket(AF_INET: SOCK_STREAM: IPPROTO_IP);
If (s < 0);
ReportError();
Endif;
// connect to the host
connto = *ALLx'00';
connto.sin_family = AF_INET;
connto.sin_addr = addr;
connto.sin_port = port;
If (connect(s: %addr(Connto): %size(connto)) = -1);
callp close(S);
ReportError();
Endif;
return s;
/end-free
P E
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* UpgradeSock(): Upgrade a socket to use SSL
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
P UpgradeSock B
D UpgradeSock PI like(gsk_handle)
D SslEnv like(gsk_handle) value
D sock 10I 0 value
D Handle s like(Gsk_handle)
/free
rc = gsk_secure_soc_open(SslEnv: Handle);
If (rc <> GSK_OK);
errMsg = %str(gsk_strerror(rc));
return *NULL;
Endif;
rc = gsk_attribute_set_numeric_value(Handle
: GSK_HANDSHAKE_TIMEOUT
: 30 );
If (rc <> GSK_OK);
errMsg = %str(gsk_strerror(rc));
gsk_secure_soc_close(Handle);
return *NULL;
Endif;
rc = gsk_secure_soc_init( Handle );
If (rc <> GSK_OK);
errMsg = %str(gsk_strerror(rc));
gsk_secure_soc_close(Handle);
return *NULL;
Endif;
return Handle;
/end-free
P E
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* CloseSsl(): Close an SSL socket
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
P CloseSsl B
D CloseSsl PI
D Handle like(gsk_handle) value
/free
gsk_secure_Soc_close( handle);
/end-free
P E
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* CloseSslEnv(): Close SSL Environment
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
P CloseSslEnv B
D CloseSslEnv PI
D SslEnv like(gsk_handle) value
/free
gsk_environment_close( SslEnv );
/end-free
P E
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* EscapeMsg(): Send an escape message w/reason for SSL failure
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
P EscapeMsg B
D EscapeMsg PI
D SndPgmMsg PR ExtPgm('QMHSNDPM')
D MessageID 7A Const
D QualMsgF 20A Const
D MsgData 256A Const
D MsgDtaLen 10I 0 Const
D MsgType 10A Const
D CallStkEnt 10A Const
D CallStkCnt 10I 0 Const
D MessageKey 4A
D ErrorCode 1A
D ErrorCode DS
D BytesProv 10I 0 inz(0)
D BytesAvail 10I 0 inz(0)
D wwTheKey S 4A
/free
SndPgmMsg( 'CPF9897'
: 'QCPFMSG *LIBL'
: errMsg
: %len(%trimr(errMsg))
: '*ESCAPE'
: '*CTLBDY'
: 1
: wwTheKey
: ErrorCode );
/end-free
P E
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* ReportError(): Send an escape message explaining any errors
* that occurred.
*
* This function requires binding directory QC2LE in order
* to access the __errno() function.
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
P ReportError B
D ReportError PI
D get_errno PR * ExtProc('__errno')
D ptrToErrno s *
D errno s 10I 0 based(ptrToErrno)
D QMHSNDPM PR ExtPgm('QMHSNDPM')
D MessageID 7A Const
D QualMsgF 20A Const
D MsgData 1A Const
D MsgDtaLen 10I 0 Const
D MsgType 10A Const
D CallStkEnt 10A Const
D CallStkCnt 10I 0 Const
D MessageKey 4A
D ErrorCode 8192A options(*varsize)
D ErrorCode DS qualified
D BytesProv 1 4I 0 inz(0)
D BytesAvail 5 8I 0 inz(0)
D MsgKey S 4A
D MsgID s 7A
/free
ptrToErrno = get_errno();
MsgID = 'CPE' + %char(errno);
QMHSNDPM( MsgID
: 'QCPFMSG *LIBL'
: ' '
: 0
: '*ESCAPE'
: '*PGMBDY'
: 1
: MsgKey
: ErrorCode );
/end-free
P E
Best Answer-推荐答案 strong>
这还不够接近,您使用的是字符而不是二进制数据。
cmd = '2' + 3 + 1 + 64 + 'x' + 2 + 50 + '{"aps":{"alert":"You have mail"}} +
3 + 3 + '001'
这应该更接近;但它不在我的脑海中,完全未经测试......
d request s 1000a varying
d frame_hdr ds
d cmd 1a inz(x'02')
d frame_len 10i 0
d frame_data s 500a varying
d device_item ds
d 1a inz(x'01')
d 5i 0 inz(%size(device_item))
d token 32a
d item_hdr ds
d id 1a inz(x'02')
d item_len 5i 0
d item_data s 100a varying
item_data = '{"aps":{"alert":"You have mail"}}';
item_len = %len(item_data);
token = myDevID;
frame_data = device_item + item_hdr + item_data;
frame_len = %len(frame_data);
request = frame_hdr + frame_data;
callp gsk_secure_soc_write(SSLSock
: %addr(request:*DATA)
: %len(request)
: bytesSent);
我以前没有在 IBM i 上做过原始套接字,您可能需要将 EBCDIC 转换为 ASCII。我认为您无需担心小端与大端。
RPG 可能不是最好的选择,考虑到 Java PNS 等项目的存在,Java 可能是更好的选择。
Stackoverflow 没有大量的 RPG/IBM i 流量。您可能会在以下方面得到更好的回应:
关于ios - 如何在 RPGLE 中构建 APNS 通知?,我们在Stack Overflow上找到一个类似的问题:
https://stackoverflow.com/questions/29401333/
|