SSL连接建立过程分析(1)
Https协议:SSL建立过程分析
web訪问的两种方式:
http协议,我们普通情况下是通过它訪问web,由于它不要求太多的安全机制,使用起来也简单,非常多web网站也仅仅支持这样的方式下的訪问.
https协议(Hypertext Transfer Protocol over Secure Socket Layer),对于安全性要求比較高的情况,能够通过它訪问web,比方工商银行https://www.icbc.com.cn/icbc/(当然也能够通过http协议訪问,仅仅是没那么安全了).其安全基础是SSL协议.
SSL协议,当前版本号为3.1(SSL3.1就是TLS1.0)。它已被广泛地用于Web浏览器与server之间的身份认证和加密传输数据.它位于TCP/IP协议与各种应用层协议之间,为数据通讯提供安全支持。SSL协议可分为两层: SSL记录协议(SSL Record Protocol):它建立在可靠的传输协议(如TCP)之上,为高层协议提供数据封装、压缩、加密等基本功能的支持。 SSL握手协议(SSL Handshake Protocol):它建立在SSL记录协议之上,用于在实际的传输数据開始前,通讯两方进行身份认证、协商加密算法、交换加密密钥等。
为了了解具体过程,能够通过网络抓包工具(Commview,Iris)分析https协议,SSL连接建立过程中,数据包交换情况.
数据包分析过程用到的几个图.
图,SSL Protocol Stack
图.SSL Record Format
图.SSL Record Protocol Payload
图.Handshake Protocol Action
它们来之.Cryptography and Network Security Principles and Practices, Fourth Edition-Chapter 17. Web Security-17.2. Secure Socket Layer and Transport Layer Security(password学与网络安全 原理与实践第四版,17章web安全,17.2节,SSL与TLS)详细细节參考本书.
以下跟踪握手过程(图Handshake Protocol Action)中,数据包的交换.
以为https方式訪问www.sun.com为样例,一般大型公司,银行的web都支持https訪问,如工商银行,sun,微软,IBM.
在IE中输入:https://wwww.sun.com,由于这是https协议,所以在实际訪问web前,会建立SSL连接.
通过Commview抓包工具,过滤443port(普通情况下,HTTPS使用port443,HTTP使用port80)能够得到数据包.
数据包大致情况和(图Handshake Protocol Action)相应.
SSL连接建立过程分析(1)
{
SSL_CTX* ctx;
SSL_METHOD *meth;
int status;
// 载入SSL错误信息
SSL_load_error_strings();
// 加入�SSL的加密/HASH算法
SSLeay_add_ssl_algorithms();
// 服务器还是客户端
If(server)
meth = SSLv23_server_method();
else
meth = SSLv23_client_method();
// 建立新的SSL上下文
ctx = SSL_CTX_new (meth);
if(!ctx) return NULL;
SSL_CTX_set_default_passwd_cb_userdata(ctx, pw);
//载入本地证书文件
status=SSL_CTX_use_certificate_file(ctx, cert, SSL_FILETYPE_ASN1);
if (status <= 0) {
frintf(stderr, "Use cert fail, status=%d/n", status);
goto bad;
}
// 载入私钥文件
if (SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM) <= 0) {
fprintf(stderr, "Use private key fail/n");
goto bad;
}
// 检查证书和私钥是否匹配
if (!SSL_CTX_check_private_key(ctx)) {
fprintf("Private key does not match the certificate public key/n");
goto bad;
}
fprintf("Cert and key OK/n");
return ctx;
bad:
SSL_CTX_free (ctx);
return NULL;
}
ssl = SSL_new (ctx);
// 将SSL与TCP socket连接
SSL_set_fd (ssl, sd);
//接受新SSL连接
err = SSL_accept (ssl);
// 建立SSL
ssl = SSL_new (ctx);
// 将SSL与TCP socket连接
SSL_set_fd (ssl, sd);
// SSL连接
err = SSL_connect (ssl);
server的SSL_accept()和client的SSL_connect()函数共同完毕SSL的握手协商过程。
写/发送:SSL_write()
2.1 SSL_load_error_strings
{
#ifndef OPENSSL_NO_ERR
ERR_load_crypto_strings();
ERR_load_SSL_strings();
#endif
}
{
while (str->error)
{
str->error|=ERR_PACK(lib,0,0);
ERRFN(err_set_item)(str);
str++;
}
}
当中:
#define ERR_PACK(l,f,r) (((((unsigned long)l)&0xffL)*0x1000000)| /
((((unsigned long)f)&0xfffL)*0x1000)| /
((((unsigned long)r)&0xfffL)))
{
ERR_STRING_DATA *p;
LHASH *hash;
hash = ERRFN(err_get)(1);
if (!hash)
return NULL;
p = (ERR_STRING_DATA *)lh_insert(hash, d);
CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
}
static ERR_STRING_DATA ERR_str_functs[]=
……
static ERR_STRING_DATA ERR_str_libraries[]=
……
static ERR_STRING_DATA ERR_str_reasons[]=
……
#define OpenSSL_add_ssl_algorithms() SSL_library_init()
#define SSLeay_add_ssl_algorithms() SSL_library_init()
int SSL_library_init(void)
{
EVP_add_cipher(EVP_des_cbc());
EVP_add_cipher(EVP_des_ede3_cbc());
#endif
#ifndef OPENSSL_NO_IDEA
EVP_add_cipher(EVP_idea_cbc());
#endif
#ifndef OPENSSL_NO_RC4
EVP_add_cipher(EVP_rc4());
#endif
#ifndef OPENSSL_NO_RC2
EVP_add_cipher(EVP_rc2_cbc());
#endif
#ifndef OPENSSL_NO_AES
EVP_add_cipher(EVP_aes_128_cbc());
EVP_add_cipher(EVP_aes_192_cbc());
EVP_add_cipher(EVP_aes_256_cbc());
#endif
#ifndef OPENSSL_NO_MD2
EVP_add_digest(EVP_md2());
#endif
#ifndef OPENSSL_NO_MD5
EVP_add_digest(EVP_md5());
EVP_add_digest_alias(SN_md5,"ssl2-md5");
EVP_add_digest_alias(SN_md5,"ssl3-md5");
#endif
#ifndef OPENSSL_NO_SHA
EVP_add_digest(EVP_sha1()); /* RSA with sha1 */
EVP_add_digest_alias(SN_sha1,"ssl3-sha1");
EVP_add_digest_alias(SN_sha1WithRSAEncryption,SN_sha1WithRSA);
#endif
#if !defined(OPENSSL_NO_SHA) && !defined(OPENSSL_NO_DSA)
EVP_add_digest(EVP_dss1()); /* DSA with sha1 */
EVP_add_digest_alias(SN_dsaWithSHA1,SN_dsaWithSHA1_2);
EVP_add_digest_alias(SN_dsaWithSHA1,"DSS1");
EVP_add_digest_alias(SN_dsaWithSHA1,"dss1");
#endif
/* If you want support for phased out ciphers, add the following */
#if 0
EVP_add_digest(EVP_sha());
EVP_add_digest(EVP_dss());
#endif
return(1);
}
2.3 SSL23_server_method()
/* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
typedef struct ssl_method_st
{
int version; // 版本号号
int (*ssl_new)(SSL *s); // 建立新SSL
void (*ssl_clear)(SSL *s); // 清除SSL
void (*ssl_free)(SSL *s); // 释放SSL
int (*ssl_accept)(SSL *s); // server接受SSL连接
int (*ssl_connect)(SSL *s); // client的SSL连接
int (*ssl_read)(SSL *s,void *buf,int len); // SSL读
int (*ssl_peek)(SSL *s,void *buf,int len); // SSL查看数据
int (*ssl_write)(SSL *s,const void *buf,int len); // SSL写
int (*ssl_shutdown)(SSL *s); // SSL半关闭
int (*ssl_renegotiate)(SSL *s); // SSL重协商
int (*ssl_renegotiate_check)(SSL *s); // SSL重协商检查
long (*ssl_ctrl)(SSL *s,int cmd,long larg,void *parg); // SSL控制
long (*ssl_ctx_ctrl)(SSL_CTX *ctx,int cmd,long larg,void *parg); //SSL上下文控制
SSL_CIPHER *(*get_cipher_by_char)(const unsigned char *ptr); // 通过名称获取SSL的算法
int (*put_cipher_by_char)(const SSL_CIPHER *cipher,unsigned char *ptr);
int (*ssl_pending)(SSL *s);
int (*num_ciphers)(void); // 算法数
SSL_CIPHER *(*get_cipher)(unsigned ncipher); // 获取算法
struct ssl_method_st *(*get_ssl_method)(int version);
long (*get_timeout)(void); // 超时
struct ssl3_enc_method *ssl3_enc; /* Extra SSLv3/TLS stuff */ // SSL3加密
int (*ssl_version)(); // SSL版本号
long (*ssl_callback_ctrl)(SSL *s, int cb_id, void (*fp)()); // SSL控制回调函数
long (*ssl_ctx_callback_ctrl)(SSL_CTX *s, int cb_id, void (*fp)()); //SSL上下文控制回调函数
} SSL_METHOD;
/* ssl/s23_srvr.c */
{
static int init=1;
// 静态量,每一个进程仅仅初始化一次
static SSL_METHOD SSLv23_server_data;
{
CRYPTO_w_lock(CRYPTO_LOCK_SSL_METHOD);
{
// ssl23的基本方法结构
memcpy((char *)&SSLv23_server_data,
(char *)sslv23_base_method(),sizeof(SSL_METHOD));
// 服务器,所以要定义accept方法
SSLv23_server_data.ssl_accept=ssl23_accept;
// 依据SSL的版本号设置SSL的详细方法函数
SSLv23_server_data.get_ssl_method=ssl23_get_server_method;
init=0;
}
}
return(&SSLv23_server_data);
}
static SSL_METHOD *ssl23_get_server_method(int ver)
{
#ifndef OPENSSL_NO_SSL2
if (ver == SSL2_VERSION)
return(SSLv2_server_method());
#endif
if (ver == SSL3_VERSION)
return(SSLv3_server_method());
else if (ver == TLS1_VERSION)
return(TLSv1_server_method());
// 随着TLS1.1(RFC4346)的推出,预计不久将出现TLSv1_1_server_method()
else
return(NULL);
}
/* ssl/s23_lib.c */
SSL_METHOD *sslv23_base_method(void)
{
return(&SSLv23_data);
}
TLS1_VERSION,
tls1_new,
tls1_clear,
tls1_free,
ssl_undefined_function,
ssl_undefined_function,
ssl23_read,
ssl23_peek,
ssl23_write,
ssl_undefined_function,
ssl_undefined_function,
ssl_ok,
ssl3_ctrl,
ssl3_ctx_ctrl,
ssl23_get_cipher_by_char,
ssl23_put_cipher_by_char,
ssl_undefined_function,
ssl23_num_ciphers,
ssl23_get_cipher,
ssl_bad_method,
ssl23_default_timeout,
&ssl3_undef_enc_method,
ssl_undefined_function,
ssl3_callback_ctrl,
ssl3_ctx_callback_ctrl,
};
{
static int init=1;
static SSL_METHOD SSLv3_server_data;
if (init)
{
CRYPTO_w_lock(CRYPTO_LOCK_SSL_METHOD);
{
// ssl3的基本方法结构
memcpy((char *)&SSLv3_server_data,(char *)sslv3_base_method(),
sizeof(SSL_METHOD));
// ssl3的接受方法
SSLv3_server_data.ssl_accept=ssl3_accept;
// ssl3获取服务器的方法函数
SSLv3_server_data.get_ssl_method=ssl3_get_server_method;
init=0;
}
CRYPTO_w_unlock(CRYPTO_LOCK_SSL_METHOD);
}
return(&SSLv3_server_data);
}
/* ssl/s3_lib.c */
static SSL_METHOD SSLv3_data= {
SSL3_VERSION,
ssl3_new,
ssl3_clear,
ssl3_free,
ssl_undefined_function,
ssl_undefined_function,
ssl3_read,
ssl3_peek,
ssl3_write,
ssl3_shutdown,
ssl3_renegotiate,
ssl3_renegotiate_check,
ssl3_ctrl,
ssl3_ctx_ctrl,
ssl3_get_cipher_by_char,
ssl3_put_cipher_by_char,
ssl3_pending,
ssl3_num_ciphers,
ssl3_get_cipher,
ssl_bad_method,
ssl3_default_timeout,
&SSLv3_enc_data,
ssl_undefined_function,
ssl3_callback_ctrl,
ssl3_ctx_callback_ctrl,
};
和server端的事实上是同样的,仅仅是不定义结构中的ssl_accept而是定义ssl_connnect:
{
static int init=1;
static SSL_METHOD SSLv23_client_data;
{
CRYPTO_w_lock(CRYPTO_LOCK_SSL_METHOD);
{
memcpy((char *)&SSLv23_client_data,
(char *)sslv23_base_method(),sizeof(SSL_METHOD));
SSLv23_client_data.ssl_connect=ssl23_connect;
SSLv23_client_data.get_ssl_method=ssl23_get_client_method;
init=0;
}
}
return(&SSLv23_client_data);
}
struct ssl_ctx_st
{
SSL_METHOD *method;
/* same as above but sorted for lookup */
STACK_OF(SSL_CIPHER) *cipher_list_by_id;
struct lhash_st /* LHASH */ *sessions; /* a set of SSL_SESSIONs */
/* Most session-ids that will be cached, default is
* SSL_SESSION_CACHE_MAX_SIZE_DEFAULT. 0 is unlimited. */
unsigned long session_cache_size;
struct ssl_session_st *session_cache_head;
struct ssl_session_st *session_cache_tail;
* SSL_SESS_CACHE_CLIENT,
* SSL_SESS_CACHE_SERVER,
* Default is SSL_SESSION_CACHE_SERVER, which means only
* SSL_accept which cache SSL_SESSIONS. */
int session_cache_mode;
* when SSL_new() is called. This has been put in to make
* life easier to set things up */
long session_timeout;
* time a session id is added to the cache. If this function
* returns 1, it means that the callback will do a
* SSL_SESSION_free() when it has finished using it. Otherwise,
* on 0, it means the callback has finished with it.
* If remove_session_cb is not null, it will be called when
* a session-id is removed from the cache. After the call,
* OpenSSL will SSL_SESSION_free() it. */
int (*new_session_cb)(struct ssl_st *ssl,SSL_SESSION *sess);
void (*remove_session_cb)(struct ssl_ctx_st *ctx,SSL_SESSION *sess);
SSL_SESSION *(*get_session_cb)(struct ssl_st *ssl,
unsigned char *data,int len,int *copy);
{
int sess_connect; /* SSL new conn - started */
int sess_connect_renegotiate;/* SSL reneg - requested */
int sess_connect_good; /* SSL new conne/reneg - finished */
int sess_accept; /* SSL new accept - started */
int sess_accept_renegotiate;/* SSL reneg - requested */
int sess_accept_good; /* SSL accept/reneg - finished */
int sess_miss; /* session lookup misses */
int sess_timeout; /* reuse attempt on timeouted session */
int sess_cache_full; /* session removed due to full cache */
int sess_hit; /* session reuse actually done */
int sess_cb_hit; /* session-id that was not
* in the cache was
* passed back via the callback. This
* indicates that the application is
* supplying session-id's from other
* processes - spooky :-) */
} stats;
int (*app_verify_callback)(X509_STORE_CTX *, void *);
void *app_verify_arg;
/* before OpenSSL 0.9.7, 'app_verify_arg' was ignored
* ('app_verify_callback' was called with just one argument) */
pem_password_cb *default_passwd_callback;
void *default_passwd_callback_userdata;
int (*client_cert_cb)(SSL *ssl, X509 **x509, EVP_PKEY **pkey);
const EVP_MD *md5; /* For SSLv3/TLSv1 'ssl3-md5' */
const EVP_MD *sha1; /* For SSLv3/TLSv1 'ssl3->sha1' */
STACK_OF(SSL_COMP) *comp_methods; /* stack of SSL_COMP, SSLv3/TLSv1 */
/* Default values used when no per-SSL value is defined follow */
STACK_OF(X509_NAME) *client_CA;
/* Default values to use in SSL structures follow (these are copied by SSL_new) */
unsigned long mode;
long max_cert_list;
int read_ahead;
void (*msg_callback)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg);
void *msg_callback_arg;
int verify_depth;
unsigned int sid_ctx_length;
unsigned char sid_ctx[SSL_MAX_SID_CTX_LENGTH];
int (*default_verify_callback)(int ok,X509_STORE_CTX *ctx); /* called 'verify_callback' in the SSL */
GEN_SESSION_CB generate_session_id;
int trust; /* Trust setting */
};
typedef struct ssl_ctx_st SSL_CTX;
SSL_CTX *SSL_CTX_new(SSL_METHOD *meth)
{
SSL_CTX *ret=NULL;
if (meth == NULL)
{
SSLerr(SSL_F_SSL_CTX_NEW,SSL_R_NULL_SSL_METHOD_PASSED);
return(NULL);
}
{
SSLerr(SSL_F_SSL_CTX_NEW,SSL_R_X509_VERIFICATION_SETUP_PROBLEMS);
goto err;
}
// 分配上下文的内存空间
ret=(SSL_CTX *)OPENSSL_malloc(sizeof(SSL_CTX));
if (ret == NULL)
goto err;
ret->method=meth;
ret->session_cache_mode=SSL_SESS_CACHE_SERVER;
ret->session_cache_size=SSL_SESSION_CACHE_MAX_SIZE_DEFAULT;
ret->session_cache_head=NULL;
ret->session_cache_tail=NULL;
ret->session_timeout=meth->get_timeout();
ret->remove_session_cb=0;
ret->get_session_cb=0;
ret->generate_session_id=0;
ret->quiet_shutdown=0;
/* ret->s2->challenge=NULL;
ret->master_key=NULL;
ret->key_arg=NULL;
ret->s2->conn_id=NULL; */
ret->app_verify_arg=NULL;
ret->read_ahead=0;
ret->msg_callback=0;
ret->msg_callback_arg=NULL;
ret->verify_mode=SSL_VERIFY_NONE;
ret->verify_depth=-1; /* Don't impose a limit (but x509_lu.c does) */
ret->sid_ctx_length=0;
ret->default_verify_callback=NULL;
if ((ret->cert=ssl_cert_new()) == NULL)
goto err;
ret->default_passwd_callback_userdata=NULL;
ret->client_cert_cb=0;
LHASH_COMP_FN(SSL_SESSION_cmp));
if (ret->sessions == NULL) goto err;
ret->cert_store=X509_STORE_new();
if (ret->cert_store == NULL) goto err;
ssl_create_cipher_list(ret->method,
&ret->cipher_list,&ret->cipher_list_by_id,
SSL_DEFAULT_CIPHER_LIST);
if (ret->cipher_list == NULL
|| sk_SSL_CIPHER_num(ret->cipher_list) <= 0)
{
SSLerr(SSL_F_SSL_CTX_NEW,SSL_R_LIBRARY_HAS_NO_CIPHERS);
goto err2;
}
if ((ret->rsa_md5=EVP_get_digestbyname("ssl2-md5")) == NULL)
{
SSLerr(SSL_F_SSL_CTX_NEW,SSL_R_UNABLE_TO_LOAD_SSL2_MD5_ROUTINES);
goto err2;
}
if ((ret->md5=EVP_get_digestbyname("ssl3-md5")) == NULL)
{
SSLerr(SSL_F_SSL_CTX_NEW,SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES);
goto err2;
}
if ((ret->sha1=EVP_get_digestbyname("ssl3-sha1")) == NULL)
{
SSLerr(SSL_F_SSL_CTX_NEW,SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES);
goto err2;
}
goto err;
SSLerr(SSL_F_SSL_CTX_NEW,ERR_R_MALLOC_FAILURE);
err2:
if (ret != NULL) SSL_CTX_free(ret);
return(NULL);
}
...待续...
SSL连接建立过程分析(1)的更多相关文章
- Https协议:SSL建立过程分析(也比较清楚,而且有OpenSSL的代码)
web访问的两种方式: http协议,我们一般情况下是通过它访问web,因为它不要求太多的安全机制,使用起来也简单,很多web站点也只支持这种方式下的访问. https协议(Hypertext Tra ...
- 一个完整的SSL连接建立过程
客户端浏览器连接到Web服务器,发出建立安全连接通道的请求. 服务器接受客户端请求,发送服务器证书做为响应. 客户端验证服务器证书的有效性,如果验证通过,则用服务器证书中包含的服务器公钥加密一个会话密 ...
- 基于OpenSSL的HTTPS通信C++实现
HTTPS是以安全为目标的HTTP通道,简单讲是HTTP的安全版.即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL.Nebula是一个为开发者提供一个快速开发 ...
- 通俗的理解HTTPS以及SSL中的证书验证
一.HTTPS的安全性体现在哪 HTTP(超文本传输协议,Hyper Text Transfer Protocol)是我们浏览网站信息传输最广泛的一种协议.HTTPS(Hyper Text Trans ...
- 《图解HTTP》阅读笔记
HTTP基础的简单理解 在了解HTTP协议之前,我们先了解下TCP/IP的参考模型,TCP/IP参考模型分为四层:应用层.传输层.网络层.链路层(数据链路层). 应用层:为不同的网络应用提供所需的服务 ...
- 深入浅出HTTP请求(转自http://www.cnblogs.com/yin-jingyu/archive/2011/08/01/2123548.html)
HTTP(HyperText Transfer Protocol)是一套计算机通过网络进行通信的规则.计算机专家设计出HTTP,使HTTP客户(如Web浏览器)能够从HTTP服务器(Web服务 器)请 ...
- HTTPS 进阶
参考 一.中间人攻击 概念:攻击者插入到原本直接通信的双方,让双方以为还在直接跟对方通讯,但是实际上双方的通信对方已经变成中间人,信息已经被中间人获取或篡改. HTTPS 的攻击分为两类:SSL 连接 ...
- 杂谈X509证书, Java Keystore与Jetty
很多人对JSSE组成部分的Key Tool 工具不太明白,希望本文能有帮助 科班出身的同学应该学过课程“密码学”, 这门课详细解释了现代对称加密的算法原理, 当时学的我云里雾里. 直到现在使用过SSL ...
- iOS安全笔记
这一篇文章, 加上里面链接的几篇文章(一个百度的, 两个阮一峰的), 全看完应该了解得差不多了 如何打造一个安全的App?这是每一个移动开发者必须面对的问题.在移动App开发领域,开发工程师对于安全方 ...
随机推荐
- 改变DEV控件的字体 z
改变所有的组件字体,使用AppearanceObject.DefaultFont属性:static void Main() { DevExpress.Utils.AppearanceObject ...
- CSS选择器的兼容性
CSS 1 CSS2.1 CSS3 :hover 在IE6中只有a元素可用.E:empty 貌似在webkit核心浏览器中有些小bug.如果这个bug依然存在,不太确定如何测试.IE6不支持.clas ...
- 警惕javascript代码中的“</script>”!
之前在写<博客园自定义博客侧边栏公告的过滤漏洞>的时候遇到了一个javascript代码报错“语法错误”的问题,一直不得以解决,感谢Arliang发现了并为我进行了耐心的解释,现整理如下: ...
- html 5新特性 --用SVG绘制的微信logo
一个简单的SVG绘制图片的小案例. 效果图: 代码如下: <style> * { ; ; } body { background-color: #d5d3d4; } .container ...
- JAVA中的数据结构——集合类(序):枚举器、拷贝、集合类的排序
枚举器与数据操作 1)枚举器为我们提供了访问集合的方法,而且解决了访问对象的“数据类型不确定”的难题.这是面向对象“多态”思想的应用.其实是通过抽象不同集合对象的共同代码,将相同的功能代码封装到了枚举 ...
- Java Client for Google Cloud Storage
关于Google Cloud Storage Google Cloud Storage有益于大文件的存储与服务(serve).此外,Cloud Storage提供了对访问控制列表(ACLs)的使用,提 ...
- MUSIC算法学习笔记
MUSIC即多重信号分类. MUSIC算法仅能估计非相干关信源,对相干信源,其性能将随信源间的相 关系数的增加而逐渐降低,直至完全恶化. 阵列信号处理的只要问题包括:波束形成技术,零点形成技术,空间谱 ...
- fedora 安装python mysql
如果你服务器环境允许yum,安装MySQL-python模块就很简单了. 如果直接安装不行,先 安装MySQL-devel后正常运行 yum install mysql-devel yum insta ...
- Apache Spark GraphX
GraphX基于BSP模型,在Spark之上封装类似Pregel的接口,进行大规模同步全局的图计算,尤其是当用户进行多轮迭代时,基于Spark内存计算的优势尤为明显.
- poj 2349 Arctic Network
http://poj.org/problem?id=2349 Arctic Network Time Limit: 2000MS Memory Limit: 65536K Total Submis ...