首先php中没有数据库连接池的东西,从来没有也不可能有。
同理。BTW: 你要是求思路就别要源码,要源码就别求思路,自相矛盾。

解决方案 »

  1.   

    求教:
    php连接mysql的时候是怎么连接的?据说pconnect的连接是可重用的啊?我想知道如何扩展php使得以实现类似于pconnect的效果,但是不是连接数据库,而是通过socket连接另外的后台!
    我担心没有思路看不懂源码!
      

  2.   

    建议你仔细阅读一下php文档中有关“永久连接”的部分。
    连接socket后不关闭就是所谓的永久连接,直到网络中断。
      

  3.   

    谢谢哈,我刚刚看php下面ext里面的mysql函数模块的实现正在想他的连接如何保持的那!
      

  4.   

    pconnect 就可以保持永久连接啊。
      

  5.   

    数据库持久连接是php在底层上实现的,你想在php之上实现是不可能的。
      

  6.   

    但是我希望socket可以被多个客户端共用啊。
      

  7.   

    我是希望用c或者c++来扩展一下php的函数库,来实现自己对后台服务器socket的持久连接。
      

  8.   

    我现在要实现前台和后台通信,前台使用php而后台使用自己做的一个服务器端,如果不控制socket连接数的话会出问题吧?
      

  9.   

    当瞬间连接数过大的时候,可以通过限制线程数来达到控制socket连接数的目的,
    但php不具有线程的概念,所以此路不通。
    但我估计你的系统应该不会出现这种情况,如果这种情况存在的话,我也只能劝你
    改用其他的实现方式。
      

  10.   

    我想,我的思路应该这么说才对,首先要避免socket连接数太多出现的错误,其次,希望避免socket多次创建和删除带来的损失。
      

  11.   

    这个问题就不好办了,首先php的socket实现我并不了解,不能给你更多的建议,
    其次php的socket功能官方的说法都是试验性的(不过我一直在用,效果还不错,:)),
    而且我不了解你的产品的结构和功用,所以具体的实现还要你自己把握。其实换个角度来思考一下,换主动为被动,由服务器来拒绝socket连接。
      

  12.   

    连接池应该是由服务端来维护的!
    php做socket客户端到无所谓,不过如果保持长连接就太浪费资源了,apache是基于进程的,每一个php连接都要开一个进程,且还一直保持??太可怕了!
    重新设计吧!
      

  13.   

    由服务器端来拒绝的话,那我的web页面的同时开socket就会有上限吧?如果是服务器端做的话,连接池的句柄又如何取得那?我想在php这边维持一个类似链表的装载socket句柄的容器是必须的吧?
      

  14.   

    首先你需要了解一下socket是什么东西,以及他是如何工作的其次你知道nanoweb这个用php写的web服务器吗?这是一个很经典的代码,请认真研读一下
      

  15.   

    用php来实现你说的容器,我想是不可能的。
    php的生命期就是他的执行期,执行结束所有变量都被销毁。原来我们曾想写一个php的module,所有的请求都通过这个module来实现。
    但最终被我们摒弃了,改用web service来实现(虽然只是soap1.1),socket只用来传输控制命令。
      

  16.   

    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
      

  17.   

    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();
    }
      

  18.   

    对不起啊,一次贴不完。
      据说这段代码中实现了我所说的类似的功能,我对zend_api不熟,看了一下,如果传说是真的话。
    EG(regular_list)///我猜想这个东西应该就是那个存储句柄的容器吧?
    ////////////////////////////////////////////////////////////////////////////////
    if (!new_link && zend_hash_find(&EG(regular_list), hashed_details, hashed_details_length+1,(void **) &index_ptr)==SUCCESS) ///这一段是在已经创建好的池中找句柄吗?
      

  19.   

    这位兄弟还真执着,与其在这里问,还不如直接去php.net找开发团队,他们能给你更有效的答案。