高分求php下维持一个socket连接池思路及源码。

luopengxo 2004-08-23 02:48:15
分不够再加。
...全文
729 24 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
24 条回复
切换为时间正序
请发表友善的回复…
发表回复
Debian 2004-08-24
  • 打赏
  • 举报
回复
这位兄弟还真执着,与其在这里问,还不如直接去php.net找开发团队,他们能给你更有效的答案。
luopengxo 2004-08-24
  • 打赏
  • 举报
回复
对不起啊,一次贴不完。
据说这段代码中实现了我所说的类似的功能,我对zend_api不熟,看了一下,如果传说是真的话。
EG(regular_list)///我猜想这个东西应该就是那个存储句柄的容器吧?
////////////////////////////////////////////////////////////////////////////////
if (!new_link && zend_hash_find(&EG(regular_list), hashed_details, hashed_details_length+1,(void **) &index_ptr)==SUCCESS) ///这一段是在已经创建好的池中找句柄吗?
luopengxo 2004-08-24
  • 打赏
  • 举报
回复
if (!MySG(allow_persistent)) {
persistent=0;
}
if (persistent) {
list_entry *le;

/* try to find if we already have this link in our persistent list */
if (zend_hash_find(&EG(persistent_list), hashed_details, hashed_details_length+1, (void **) &le)==FAILURE) { /* we don't */
list_entry new_le;

if (MySG(max_links)!=-1 && MySG(num_links)>=MySG(max_links)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Too many open links (%ld)", MySG(num_links));
efree(hashed_details);
MYSQL_DO_CONNECT_RETURN_FALSE();
}
if (MySG(max_persistent)!=-1 && MySG(num_persistent)>=MySG(max_persistent)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Too many open persistent links (%ld)", MySG(num_persistent));
efree(hashed_details);
MYSQL_DO_CONNECT_RETURN_FALSE();
}
/* create the link */
mysql = (php_mysql_conn *) malloc(sizeof(php_mysql_conn));
mysql->active_result_id = 0;
#if MYSQL_VERSION_ID > 32199 /* this lets us set the port number */
mysql_init(&mysql->conn);

if (connect_timeout != -1)
mysql_options(&mysql->conn, MYSQL_OPT_CONNECT_TIMEOUT, (const char *)&connect_timeout);

if (mysql_real_connect(&mysql->conn, host, user, passwd, NULL, port, socket, client_flags)==NULL) {
#else
if (mysql_connect(&mysql->conn, host, user, passwd)==NULL) {
#endif
/* Populate connect error globals so that the error functions can read them */
if (MySG(connect_error)!=NULL) efree(MySG(connect_error));
MySG(connect_error)=estrdup(mysql_error(&mysql->conn));
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", MySG(connect_error));
#if defined(HAVE_MYSQL_ERRNO)
MySG(connect_errno)=mysql_errno(&mysql->conn);
#endif
free(mysql);
efree(hashed_details);
MYSQL_DO_CONNECT_RETURN_FALSE();
}

/* hash it up */
Z_TYPE(new_le) = le_plink;
new_le.ptr = mysql;
if (zend_hash_update(&EG(persistent_list), hashed_details, hashed_details_length+1, (void *) &new_le, sizeof(list_entry), NULL)==FAILURE) {
free(mysql);
efree(hashed_details);
MYSQL_DO_CONNECT_RETURN_FALSE();
}
MySG(num_persistent)++;
MySG(num_links)++;
} else { /* The link is in our list of persistent connections */
if (Z_TYPE_P(le) != le_plink) {
MYSQL_DO_CONNECT_RETURN_FALSE();
}
/* ensure that the link did not die */
#if MYSQL_VERSION_ID > 32230 /* Use mysql_ping to ensure link is alive (and to reconnect if needed) */
if (mysql_ping(le->ptr)) {
#else /* Use mysql_stat() to check if server is alive */
handler=signal(SIGPIPE, SIG_IGN);
#if defined(HAVE_MYSQL_ERRNO) && defined(CR_SERVER_GONE_ERROR)
mysql_stat(le->ptr);
if (mysql_errno(&((php_mysql_conn *) le->ptr)->conn) == CR_SERVER_GONE_ERROR) {
#else
if (!strcasecmp(mysql_stat(le->ptr), "mysql server has gone away")) { /* the link died */
#endif
signal(SIGPIPE, handler);
#endif /* end mysql_ping */
#if MYSQL_VERSION_ID > 32199 /* this lets us set the port number */
if (mysql_real_connect(le->ptr, host, user, passwd, NULL, port, socket, client_flags)==NULL) {
#else
if (mysql_connect(le->ptr, host, user, passwd)==NULL) {
#endif
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Link to server lost, unable to reconnect");
zend_hash_del(&EG(persistent_list), hashed_details, hashed_details_length+1);
efree(hashed_details);
MYSQL_DO_CONNECT_RETURN_FALSE();
}
}
#if MYSQL_VERSION_ID < 32231
signal(SIGPIPE, handler);
#endif
mysql = (php_mysql_conn *) le->ptr;
}
ZEND_REGISTER_RESOURCE(return_value, mysql, le_plink);
} else { /* non persistent */
list_entry *index_ptr, new_index_ptr;

/* first we check the hash for the hashed_details key. if it exists,
* it should point us to the right offset where the actual mysql link sits.
* if it doesn't, open a new mysql link, add it to the resource list,
* and add a pointer to it with hashed_details as the key.
*/
if (!new_link && zend_hash_find(&EG(regular_list), hashed_details, hashed_details_length+1,(void **) &index_ptr)==SUCCESS) {
int type;
long link;
void *ptr;

if (Z_TYPE_P(index_ptr) != le_index_ptr) {
MYSQL_DO_CONNECT_RETURN_FALSE();
}
link = (long) index_ptr->ptr;
ptr = zend_list_find(link,&type); /* check if the link is still there */
if (ptr && (type==le_link || type==le_plink)) {
zend_list_addref(link);
Z_LVAL_P(return_value) = link;
php_mysql_set_default_link(link TSRMLS_CC);
Z_TYPE_P(return_value) = IS_RESOURCE;
efree(hashed_details);
MYSQL_DO_CONNECT_CLEANUP();
return;
} else {
zend_hash_del(&EG(regular_list), hashed_details, hashed_details_length+1);
}
}
if (MySG(max_links)!=-1 && MySG(num_links)>=MySG(max_links)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Too many open links (%ld)", MySG(num_links));
efree(hashed_details);
MYSQL_DO_CONNECT_RETURN_FALSE();
}

mysql = (php_mysql_conn *) emalloc(sizeof(php_mysql_conn));
mysql->active_result_id = 0;
#if MYSQL_VERSION_ID > 32199 /* this lets us set the port number */
mysql_init(&mysql->conn);

if (connect_timeout != -1)
mysql_options(&mysql->conn, MYSQL_OPT_CONNECT_TIMEOUT, (const char *)&connect_timeout);

if (mysql_real_connect(&mysql->conn, host, user, passwd, NULL, port, socket, client_flags)==NULL) {
#else
if (mysql_connect(&mysql->conn, host, user, passwd)==NULL) {
#endif
/* Populate connect error globals so that the error functions can read them */
if (MySG(connect_error)!=NULL) efree(MySG(connect_error));
MySG(connect_error)=estrdup(mysql_error(&mysql->conn));
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", MySG(connect_error));
#if defined(HAVE_MYSQL_ERRNO)
MySG(connect_errno)=mysql_errno(&mysql->conn);
#endif
efree(hashed_details);
efree(mysql);
MYSQL_DO_CONNECT_RETURN_FALSE();
}

/* add it to the list */
ZEND_REGISTER_RESOURCE(return_value, mysql, le_link);

/* add it to the hash */
new_index_ptr.ptr = (void *) Z_LVAL_P(return_value);
Z_TYPE(new_index_ptr) = le_index_ptr;
if (zend_hash_update(&EG(regular_list), hashed_details, hashed_details_length+1,(void *) &new_index_ptr, sizeof(list_entry), NULL)==FAILURE) {
efree(hashed_details);
MYSQL_DO_CONNECT_RETURN_FALSE();
}
MySG(num_links)++;
}

efree(hashed_details);
php_mysql_set_default_link(Z_LVAL_P(return_value) TSRMLS_CC);
MYSQL_DO_CONNECT_CLEANUP();
}
luopengxo 2004-08-24
  • 打赏
  • 举报
回复
static void php_mysql_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent)
{
char *user=NULL, *passwd=NULL, *host_and_port=NULL, *socket=NULL, *tmp=NULL, *host=NULL;
char *hashed_details=NULL;
int hashed_details_length, port = MYSQL_PORT;
int client_flags = 0;
php_mysql_conn *mysql=NULL;
#if MYSQL_VERSION_ID <= 32230
void (*handler) (int);
#endif
zval **z_host=NULL, **z_user=NULL, **z_passwd=NULL, **z_new_link=NULL, **z_client_flags=NULL;
zend_bool free_host=0, new_link=0;
long connect_timeout;


connect_timeout = MySG(connect_timeout);

socket = MySG(default_socket);

if (MySG(default_port) < 0) {
#if !defined(PHP_WIN32) && !defined(NETWARE)
struct servent *serv_ptr;
char *env;

MySG(default_port) = MYSQL_PORT;
if ((serv_ptr = getservbyname("mysql", "tcp"))) {
MySG(default_port) = (uint) ntohs((ushort) serv_ptr->s_port);
}
if ((env = getenv("MYSQL_TCP_PORT"))) {
MySG(default_port) = (uint) atoi(env);
}
#else
MySG(default_port) = MYSQL_PORT;
#endif
}

if (PG(sql_safe_mode)) {
if (ZEND_NUM_ARGS()>0) {
php_error_docref(NULL TSRMLS_CC, E_NOTICE, "SQL safe mode in effect - ignoring host/user/password information");
}
host_and_port=passwd=NULL;
user=php_get_current_user();
hashed_details_length = strlen(user)+5+3;///why +5+3
hashed_details = (char *) emalloc(hashed_details_length+1);
sprintf(hashed_details, "mysql__%s_", user);
client_flags = CLIENT_INTERACTIVE;///宏的意思 ?
} else {
host_and_port = MySG(default_host);
user = MySG(default_user);
passwd = MySG(default_password);

switch(ZEND_NUM_ARGS()) {///zend_num_args是输入参数的个数
case 0: /* defaults */
break;
case 1: {
if (zend_get_parameters_ex(1, &z_host)==FAILURE) {
MYSQL_DO_CONNECT_RETURN_FALSE();
}
}
break;
case 2: {
if (zend_get_parameters_ex(2, &z_host, &z_user)==FAILURE) {
MYSQL_DO_CONNECT_RETURN_FALSE();
}
convert_to_string_ex(z_user);
user = Z_STRVAL_PP(z_user);
}
break;
case 3: {
if (zend_get_parameters_ex(3, &z_host, &z_user, &z_passwd) == FAILURE) {
MYSQL_DO_CONNECT_RETURN_FALSE();
}
convert_to_string_ex(z_user);
convert_to_string_ex(z_passwd);
user = Z_STRVAL_PP(z_user);
passwd = Z_STRVAL_PP(z_passwd);
}
break;
case 4: {
if (!persistent) {
if (zend_get_parameters_ex(4, &z_host, &z_user, &z_passwd, &z_new_link) == FAILURE) {
MYSQL_DO_CONNECT_RETURN_FALSE();
}
convert_to_string_ex(z_user);
convert_to_string_ex(z_passwd);
convert_to_boolean_ex(z_new_link);
user = Z_STRVAL_PP(z_user);
passwd = Z_STRVAL_PP(z_passwd);
new_link = Z_BVAL_PP(z_new_link);
}
else {
if (zend_get_parameters_ex(4, &z_host, &z_user, &z_passwd, &z_client_flags) == FAILURE) {
MYSQL_DO_CONNECT_RETURN_FALSE();
}
convert_to_string_ex(z_user);
convert_to_string_ex(z_passwd);
convert_to_long_ex(z_client_flags);
user = Z_STRVAL_PP(z_user);
passwd = Z_STRVAL_PP(z_passwd);
client_flags = Z_LVAL_PP(z_client_flags);
}
}
break;
case 5: {
if (zend_get_parameters_ex(5, &z_host, &z_user, &z_passwd, &z_new_link, &z_client_flags) == FAILURE) {
MYSQL_DO_CONNECT_RETURN_FALSE();
}
convert_to_string_ex(z_user);
convert_to_string_ex(z_passwd);
convert_to_boolean_ex(z_new_link);
convert_to_long_ex(z_client_flags);
user = Z_STRVAL_PP(z_user);
passwd = Z_STRVAL_PP(z_passwd);
new_link = Z_BVAL_PP(z_new_link);
client_flags = Z_LVAL_PP(z_client_flags);
}
break;
default:
WRONG_PARAM_COUNT;
break;
}
/* disable local infile option for open_basedir */
if (PG(open_basedir) && strlen(PG(open_basedir)) && (client_flags & CLIENT_LOCAL_FILES)) {
client_flags ^= CLIENT_LOCAL_FILES;
}

if (z_host) {
SEPARATE_ZVAL(z_host); /* We may modify z_host if it contains a port, separate */
convert_to_string_ex(z_host);
host_and_port = Z_STRVAL_PP(z_host);
if (z_user) {
convert_to_string_ex(z_user);
user = Z_STRVAL_PP(z_user);
if (z_passwd) {
convert_to_string_ex(z_passwd);
passwd = Z_STRVAL_PP(z_passwd);
}
}
}

hashed_details_length = sizeof("mysql___")-1 + strlen(SAFE_STRING(host_and_port))+strlen(SAFE_STRING(user))+strlen(SAFE_STRING(passwd));
hashed_details = (char *) emalloc(hashed_details_length+1);
sprintf(hashed_details, "mysql_%s_%s_%s", SAFE_STRING(host_and_port), SAFE_STRING(user), SAFE_STRING(passwd));
}

/* We cannot use mysql_port anymore in windows, need to use
* mysql_real_connect() to set the port.
*/
if (host_and_port && (tmp=strchr(host_and_port, ':'))) {
host = estrndup(host_and_port, tmp-host_and_port);
free_host = 1;
tmp++;
if (tmp[0] != '/') {
port = atoi(tmp);
if ((tmp=strchr(tmp, ':'))) {
tmp++;
socket=tmp;
}
} else {
socket = tmp;
}
} else {
host = host_and_port;
port = MySG(default_port);
}

#if MYSQL_VERSION_ID < 32200
mysql_port = port;
#endif
Debian 2004-08-24
  • 打赏
  • 举报
回复
用php来实现你说的容器,我想是不可能的。
php的生命期就是他的执行期,执行结束所有变量都被销毁。

原来我们曾想写一个php的module,所有的请求都通过这个module来实现。
但最终被我们摒弃了,改用web service来实现(虽然只是soap1.1),socket只用来传输控制命令。
xuzuning 2004-08-24
  • 打赏
  • 举报
回复
首先你需要了解一下socket是什么东西,以及他是如何工作的

其次你知道nanoweb这个用php写的web服务器吗?这是一个很经典的代码,请认真研读一下

luopengxo 2004-08-24
  • 打赏
  • 举报
回复
由服务器端来拒绝的话,那我的web页面的同时开socket就会有上限吧?如果是服务器端做的话,连接池的句柄又如何取得那?我想在php这边维持一个类似链表的装载socket句柄的容器是必须的吧?
luopengxo 2004-08-24
  • 打赏
  • 举报
回复
谢谢指点,散分走人。:)
subzero 2004-08-23
  • 打赏
  • 举报
回复
连接池应该是由服务端来维护的!
php做socket客户端到无所谓,不过如果保持长连接就太浪费资源了,apache是基于进程的,每一个php连接都要开一个进程,且还一直保持??太可怕了!
重新设计吧!
Debian 2004-08-23
  • 打赏
  • 举报
回复
这个问题就不好办了,首先php的socket实现我并不了解,不能给你更多的建议,
其次php的socket功能官方的说法都是试验性的(不过我一直在用,效果还不错,:)),
而且我不了解你的产品的结构和功用,所以具体的实现还要你自己把握。

其实换个角度来思考一下,换主动为被动,由服务器来拒绝socket连接。
luopengxo 2004-08-23
  • 打赏
  • 举报
回复
而且,最不辛的是,设计思路早就订了,其他部分接近完工,都是建立在这个的基础上的。
luopengxo 2004-08-23
  • 打赏
  • 举报
回复
我想,我的思路应该这么说才对,首先要避免socket连接数太多出现的错误,其次,希望避免socket多次创建和删除带来的损失。
Debian 2004-08-23
  • 打赏
  • 举报
回复
当瞬间连接数过大的时候,可以通过限制线程数来达到控制socket连接数的目的,
但php不具有线程的概念,所以此路不通。
但我估计你的系统应该不会出现这种情况,如果这种情况存在的话,我也只能劝你
改用其他的实现方式。
luopengxo 2004-08-23
  • 打赏
  • 举报
回复
我现在要实现前台和后台通信,前台使用php而后台使用自己做的一个服务器端,如果不控制socket连接数的话会出问题吧?
Debian 2004-08-23
  • 打赏
  • 举报
回复
你仔细的想一下,这样做是没有意义的。
我实在不明白为什么要这么做?
luopengxo 2004-08-23
  • 打赏
  • 举报
回复
我是希望用c或者c++来扩展一下php的函数库,来实现自己对后台服务器socket的持久连接。
luopengxo 2004-08-23
  • 打赏
  • 举报
回复
但是我希望socket可以被多个客户端共用啊。
Debian 2004-08-23
  • 打赏
  • 举报
回复
数据库持久连接是php在底层上实现的,你想在php之上实现是不可能的。
pswdf 2004-08-23
  • 打赏
  • 举报
回复
pconnect 就可以保持永久连接啊。
luopengxo 2004-08-23
  • 打赏
  • 举报
回复
谢谢哈,我刚刚看php下面ext里面的mysql函数模块的实现正在想他的连接如何保持的那!
加载更多回复(4)

21,893

社区成员

发帖
与我相关
我的任务
社区描述
从PHP安装配置,PHP入门,PHP基础到PHP应用
社区管理员
  • 基础编程社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧