原文太常了,就不转了。可以去原文看。写的很全面。
ios8中的推送,看下文
上边的文章讲的是使用php的,下边这个是使用pyhton的一个第三方库实现的。
另一个python推送,applepush:http://python.jobbole.com/86847/
pip install applepush
http://www.tuicool.com/articles/aqYBna
pip install pyapns
或者使用
easy_install pyapns
如果上边两个下载twistd有问题,可以从下边的地址下载twistd
https://pypi.python.org/packages/18/85/eb7af503356e933061bf1220033c3a85bad0dbc5035dfd9a97f1e900dfcb/Twisted-16.2.0.tar.bz2
或者直接在服务器终端里输入:
curl -O https://pypi.python.org/packages/18/85/eb7af503356e933061bf1220033c3a85bad0dbc5035dfd9a97f1e900dfcb/Twisted-16.2.0.tar.bz2
下载好之后,使用
tar -xvjf Twisted-16.2.0.tar.bz2
解压后,进入目录,使用sudo python setup.py install安装
启动twisted
#linux
twistd -r epoll web --class=pyapns.server.APNSServer --port=7077
#mac os
twistd -r kqueue web --class=pyapns.server.APNSServer --port=7077
我在运行这个的时候出了些问题,在mac上运行时发现少了一个叫libffi的库,要安装上这个才能运行。安装之后一,又少service-identity,再后来说openssl的库找不到.使用下边方法
sudo ln -s /Users/username/anaconda/lib/libssl.1.0.0.dylib /usr/lib/libssl.1.0.0.dylib
sudo ln -s /Users/username/anaconda/lib/libcrypto.1.0.0.dylib /usr/lib/libcrypto.1.0.0.dylib
在ubuntu linux上发现用pip安装的twistd没有web的这个命令,后来使用
sudo apt-get install python-twisted python-libxml2 python-simplejson
使用上边的命令安装好了twistd之后运行web命令又说少了service-identity,使用pip install service-identity进行安装时又说pyopenssl的版本不对。
再使用sudo pip install openssl进行openssl安装,接着运行twistd,发现已经有一个进程在运行了。这时找到twistd进程,使用。
kill pid
终止进程后,再运行
#linux
twistd -r epoll web --class=pyapns.server.APNSServer --port=7077
#mac os
twistd -r kqueue web --class=pyapns.server.APNSServer --port=7077
没有报错,这时就可以新建下边的push.py文件了,如果运气好,你的手机应该会收到推送消息。但是也有可能你在生成pem文件时使用了密码。而pyapns默认是不使用密码的。这个时候用下边的方法重新生成一个没有安装密码的ck.pem文件。
openssl rsa -in PushChatKey.pem -out PushChatKey-noenc.pem。
cat PushChatCert.pem PushChatKey-noenc.pem > ck.pem
新建push.py文件输入下面内容
#!/usr/bin/python
# -*- coding: utf-8 -*
# Filename: push.py
from pyapns import configure, provision, notify
tokens = ["token1" ,
"token2"]
notifications = [
{'aps' :{'alert': 'Hello token 1', 'badge': 0, 'sound': 'flynn.caf'}},
]
configure({'HOST': 'http://localhost:7077/'})
provision('myapp', open('developent.pem').read(), 'sandbox')
notify('myapp', tokens, notifications)
pyapns推送消息 需要一个pem格式的证书文件,跟 Parse 里要求一个.p12文件不同啊。我看看怎么搞到这文件。从苹果下载的证书是.cer格式的,在苹果的KeyChain程序中,选择导出,可是,只能选择导出成.cer和.p12文件,.pem的选项被禁用了,好桑心。通过搜索export pem from keychain找到 Creating .pem file for APNS? ,简单说,就是在KeyChain里导出.p12格式的,再通过下面的命令转换成.pem的。搞定。
openssl pkcs12 -in Development.p12 -out developent.pem -nodes -clcerts
python push.py
推送成功
完成
pyapns源码:
https://github.com/samuraisam/pyapns
具体的.pem文件生成:
处理证书
打开终端.
cd到桌面,我们那三个文件所在的位置
三个文件:
一个是CSR请求文件,一个是aps_development .cer的SSL证书文件,还有一个刚才生成的Push.p12秘钥文件
1、把.cer的SSL证书转换为.pem文件,执行命令:
openssl x509 -in aps_development.cer -inform der -out PushChatCert.pem
在桌面上会生成一个PushChatCert.pem文件
localhost:Desktop oukoumine$ openssl x509 -in ps_development.cer -inform der -out PushChatCert.pem
localhost:Desktop oukoumine$
2、把私钥Push.p12文件转化为.pem文件:
openssl pkcs12 -nocerts -out PushChatKey.pem -in Push.p12
这里需要我们输入密码,这个密码也就是我们导出p12文件时的密码,也就是我们上面设置的abcabc。然后,需要我们对生成的pem文件设置一个密语,这里我们推荐还是用上面这个abcabc,防止混乱(当然你也可以设置成别的更有意义的密语),这里的密语是要告诉我们服务器的。这样,桌面上又会生成一个PushChatKey.pem文件
3、对生成的这两个pem文件再生成一个pem文件,来把证书和私钥整合到一个文件里:
cat PushChatCert.pem PushChatKey.pem > ck.pem
生成ck.pem文件
这样,我们的文件就制作完了
项目测试
建立我们的推送的项目(注意BundleIdentifier必须和我们推送应用的App id一致)
在AppDelegate里didFinishLaunchingWithOptions函数里写
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
……
//推送的形式:标记,声音,提示
[[UIApplication sharedApplication] registerForRemoteNotificationTypes: UIRemoteNotificationTypeBadge |UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert];
//上边的方法在ios8以上的版本不能用了。ios8以后要使用新的方法
return YES;
}
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)pToken {
NSLog(@"regisger success:%@",pToken);
//注册成功,将deviceToken保存到应用服务器数据库中
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{
// 处理推送消息
NSLog(@"userinfo:%@",userInfo);
NSLog(@"收到推送消息:%@",[[userInfo objectForKey:@"aps"] objectForKey:@"alert"]);
}
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
NSLog(@"Registfail%@",error);
}
我们运行程序的时候会有提示,说我们的程序要发送推送通知。
C++推送服务器端:
SSLCOMM_H文件
#ifndef SSLCOMM_H
#define SSLCOMM_H
#ifdef linux
#include <assert.h>
#include "openssl/pem.h"
#include "openssl/rsa.h"
#include "openssl/crypto.h"
#include "openssl/x509.h"
#include "openssl/ssl.h"
#include "openssl/err.h"
#include "openssl/rand.h"
#include "errno.h"
#include "sys/socket.h"
#include "netinet/in.h"
#include "unistd.h"
#include <arpa/inet.h>
#include <netdb.h>
#include "Utility.h"
#define APNS_DEV
#if defined(APNS_DEV)
#define CA_CERT_PATH "./pem"
#define RSA_CLIENT_CERT "./pem/a.pem"
#define RSA_CLIENT_KEY "./pem/a.pem"
/* Development Connection Infos */
#define APPLE_HOST "gateway.sandbox.push.apple.com"
#define APPLE_PORT 2195
#define APPLE_FEEDBACK_HOST "feedback.sandbox.push.apple.com"
#define APPLE_FEEDBACK_PORT 2196
#else
#define CA_CERT_PATH "./pem"
#define RSA_CLIENT_CERT "./pem/b.pem"
#define RSA_CLIENT_KEY "./pem/b.pem"
#define APPLE_HOST "gateway.push.apple.com"
#define APPLE_PORT 2195
#define APPLE_FEEDBACK_HOST "feedback.push.apple.com"
#define APPLE_FEEDBACK_PORT 2196
#endif
class
{
public:
CSSLComm();
~CSSLComm();
bool
bool ssl_connect(const char *host, int port, const char *certfile, const char *keyfile, const char* capath);
void PushNotification(const char *pToken,const char
void GenPushData(const char
int GenPayloadData(int badgeNum,const char
private:
void
private:
SSL_CTX *m_pctx;
SSL *m_pssl;
const
X509 *m_pserver_cert;
EVP_PKEY *m_pkey;
/* Socket Communications */
struct
struct
int
uint16 m_tokenLen;
struct
{
char
char
}m_data;
CSyncCritical m_lock;
};
#endif
#endif // SSLCOMM_H
SSLComm.cpp
#ifdef linux
#include "SSLComm.h"
CSSLComm::CSSLComm()
{
//ctor
m_sockfd = -1;
m_pctx = NULL;
m_pssl = NULL;
m_pmeth = NULL;
m_pserver_cert = NULL;
m_pkey = NULL;
m_tokenLen = htons(32);
memset((void*)&m_data,0,sizeof(m_data));
}
CSSLComm::~CSSLComm()
{
//dtor
Reset();
}
void
{
if(m_pssl)
{
SSL_shutdown(m_pssl);
SSL_free(m_pssl);
m_pssl = NULL;
}
if(m_pctx)
{
SSL_CTX_free(m_pctx);
m_pctx = NULL;
}
if(m_sockfd > 2)
{
close(m_sockfd);
m_sockfd = -1;
}
}
bool
{
if(m_sockfd < 2) return false;
struct
timeout.tv_sec = 0;
timeout.tv_usec = 0;
fd_set fdwrite;
fd_set fdexcept;
FD_ZERO(&fdwrite);
FD_ZERO(&fdexcept);
FD_SET(m_sockfd,&fdwrite);
FD_SET(m_sockfd,&fdexcept);
int
if(ret == -1)
return false;
if(ret > 0)
{
if(FD_ISSET(m_sockfd,&fdexcept))
return false;
else if(FD_ISSET(m_sockfd,&fdwrite))
{
int
sizeof(err);
int result = getsockopt(m_sockfd,SOL_SOCKET,SO_ERROR,(char*)&err,&len);
if(result < 0 || err != 0)
return false;
return true;
}
}
return false;
}
bool CSSLComm::ssl_connect(const char *host, int port, const char *certfile, const char *keyfile, const char* capath)
{
Reset();
int
/* Load encryption & hashing algorithms for the SSL program */
SSL_library_init();
/* Load the error strings for SSL & CRYPTO APIs */
SSL_load_error_strings();
/* Create an SSL_METHOD structure (choose an SSL/TLS protocol version) */
m_pmeth = SSLv3_method();
/* Create an SSL_CTX structure */
m_pctx = SSL_CTX_new(m_pmeth);
if(!m_pctx)
{
printf("Could not get SSL Context\n");
return false;
}
/* Load the CA from the Path */
if(SSL_CTX_load_verify_locations(m_pctx, NULL, capath) <= 0)
{
/* Handle failed load here */
printf("Failed to set CA location...\n");
ERR_print_errors_fp(stderr);
return false;
}
/* Load the client certificate into the SSL_CTX structure */
if
{
printf("Cannot use Certificate File\n");
ERR_print_errors_fp(stderr);
return false;
}
/* Load the private-key corresponding to the client certificate */
if
{
printf("Cannot use Private Key\n");
ERR_print_errors_fp(stderr);
return false;
}
/* Check if the client certificate and private-key matches */
if
{
printf("Private key does not match the certificate public key\n");
return false;
}
/* Set up a TCP socket */
m_sockfd = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
if(m_sockfd == -1)
{
printf("Could not get Socket\n");
return false;
}
memset (&m_server_addr, '\0', sizeof(m_server_addr));
m_server_addr.sin_family = AF_INET;
/* Server Port number */
m_phost_info = gethostbyname(host);
if(m_phost_info)
{
/* Take the first IP */
struct in_addr *address = (struct
/* Server IP */
}
else
{
printf("Could not resolve hostname %s\n", host);
return false;
}
/* Establish a TCP/IP connection to the SSL client */
struct sockaddr*) &m_server_addr, sizeof(m_server_addr));
if(err == -1)
{
printf("Could not connect\n");
return false;
}
/* An SSL structure is created */
m_pssl = SSL_new(m_pctx);
if(!m_pssl)
{
printf("Could not get SSL Socket\n");
return false;
}
/* Assign the socket into the SSL structure (SSL and socket without BIO) */
SSL_set_fd(m_pssl, m_sockfd);
/* Perform SSL Handshake on the SSL client */
err = SSL_connect(m_pssl);
if(err == -1)
{
printf("Could not connect to SSL Server\n");
return false;
}
return true;
}
void CSSLComm::PushNotification(const char *pToken,const char
{
CMyLock lock(&m_lock);
if(!connected())
{
ssl_connect(APPLE_HOST, APPLE_PORT, RSA_CLIENT_CERT, RSA_CLIENT_KEY, CA_CERT_PATH);
}
int
GenPushData(pToken);
int ret = SSL_write(m_pssl, (void*)&m_data, 35 + paylen);
//printf("ret = %d \n",ret);
}
void CSSLComm::GenPushData(const char
{
char
*ptr++ = 0;
memcpy(ptr,&m_tokenLen,2);
ptr += 2;
memcpy(ptr,pToken,32);
}
int CSSLComm::GenPayloadData(int badgeNum,const char
{
char
char
strcpy(&m_data.szPayload[2], "{\"aps\":{");
if(pMsg != NULL)
{
strcat(&m_data.szPayload[2], "\"alert\":");
sizeof(buf)-1,"\"%s\",", pMsg);
strcat(&m_data.szPayload[2],buf);
}
if(badgeNum > 99 || badgeNum < 0) badgeNum = 1;
sizeof(badgeBuf)-1,"%d", badgeNum);
strcat(&m_data.szPayload[2], "\"badge\":");
strcat(&m_data.szPayload[2], badgeBuf);
strcat(&m_data.szPayload[2], ",\"sound\":\"msg.wav\"}");
/*
int i = 0;
while(payload->dictKey<i> != NULL && i < 5)
{
sprintf(tmpBuff, "\"%s\":\"%s\"", payload->dictKey<i>, payload->dictValue<i>);
strcat(messageBuff, tmpBuff);
if(i < 4 && payload->dictKey[i + 1] != NULL)
{
strcat(messageBuff, ",");
}
i++;
}
*/
sizeof(buf)-1,",\"%s\":\"%d\"", "forum_id",88);
strcat(&m_data.szPayload[2],buf);
sizeof(buf)-1,",\"%s\":\"%d\"", "topic_id",999);
strcat(&m_data.szPayload[2],buf);
strcat(&m_data.szPayload[2],"}");
int len = strlen(&m_data.szPayload[2]);
assert(len <= 256);
uint16_t payload_len = htons(len);
memcpy(m_data.szPayload,&payload_len,sizeof(payload_len));
return
}
#endif
另外还有一些第三方的推送平台,用第三方平台的好处就是操作简单,不同系统的设备推送接口统一。缺点只有一个,就是推送数据的全安性,以及到一定量时要收费。
Linux系统登陆密码忘了怎么办:
使用系统安装盘,进入修复模式,输入
passwd <用户名>
就可以输入新密码了。我是在ubuntu 14.04上试的。