PHPの中のsocket_readとsocket_recv区別の詳細

4037 ワード

先日PHPでsocketネットワークサービスを書いて、ドキュメントにsocket_を見ました.readとsocket_recvという2つの方法は少しめまいがしますが、一見同じではないでしょうか.どうして2つの異なる使い方をしなければなりませんか.文書を見てよく分からなかったので、ソースコードを見てやっと分かりました.ここに記録してください.
まず、この2つの関数の宣言を見てみましょう.
 
  
string socket_read ( resource $socket , int $length [, int $type = PHP_BINARY_READ ] )
int socket_recv ( resource $socket , string &$buf , int $len , int $flags )

宣言から、受信したデータを実行結果で返し、受信したデータを参照形式で返すことがわかります.もう一つの違いは、socket_readが1つ増えたrecvにはflagsが1つ増えました(混乱しています).まずsocketを見てみましょうrecvのソースコードでしょう!
 
  
PHP_FUNCTION(socket_recv)
{
    zval        *php_sock_res, *buf;
    char        *recv_buf;
    php_socket  *php_sock;
    int         retval;
    long        len, flags;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rzll", &php_sock_res, &buf, &len, &flags) == FAILURE) {
        return;
    }

    ZEND_FETCH_RESOURCE(php_sock, php_socket *, &php_sock_res, -1, le_socket_name, le_socket);

    /* overflow check */
    if ((len + 1) < 2) {
        RETURN_FALSE;
    }

    recv_buf = emalloc(len + 1);
    memset(recv_buf, 0, len + 1);

    if ((retval = recv(php_sock->bsd_socket, recv_buf, len, flags)) < 1) {
        efree(recv_buf);

        zval_dtor(buf);
        Z_TYPE_P(buf) = IS_NULL;
    } else {
        recv_buf[retval] = '\0';

        /* Rebuild buffer zval */
        zval_dtor(buf);

        Z_STRVAL_P(buf) = recv_buf;
        Z_STRLEN_P(buf) = retval;
        Z_TYPE_P(buf) = IS_STRING;
    }

    if (retval == -1) {
        PHP_SOCKET_ERROR(php_sock, "unable to read from socket", errno);
        RETURN_FALSE;
    }

    RETURN_LONG(retval);
}


中にはたくさんありますが、実は一番重要な行があります.
 
  
if ((retval = recv(php_sock->bsd_socket, recv_buf, len, flags)) < 1) {

実際にこの関数はシステムのrecvを呼び出しただけで,入力パラメータと得られた結果を処理しただけで,理解しやすいことがわかる.じゃあソケットを見てみましょうread,socket_readはシステムのrecv関数より$typeパラメータが1つ増えています.これも私がこの関数が存在する意味だと思います.ドキュメントから見ると、typeにはPHP_という2つの値があります.BINARY_READとPHP_NORMAL_READ、文書に書いてある、PHP_BINARY_READは直接システムでのrecvメソッドを表し、PHP_NORMAL_READは、またはrに出会うまで読むことを示しています.ソースコードを見てみましょう.
 
  
//
if (type == PHP_NORMAL_READ) {
    retval = php_read(php_sock, tmpbuf, length, 0);
} else {
    retval = recv(php_sock->bsd_socket, tmpbuf, length, 0);
}

PHPならNORMAL_READモード、実際の動作とsocket_recvは同じで、システムのrecv関数を使っていますが、PHP_NORMAL_READは、大きな違いがあり、自分で実現したphp_を使っています.read関数、このphp_readは何をしていますか?ソースコードを見続けます.
 
  
*t = '\0';
while (*t != '
' && *t != '\r' && n < maxlen) {
    if (m > 0) {
        t++;
        n++;
    } else if (m == 0) {
        no_read++;
        if (nonblock && no_read >= 2) {
            return n;
            /* The first pass, m always is 0, so no_read becomes 1
             * in the first pass. no_read becomes 2 in the second pass,
             * and if this is nonblocking, we should return.. */
        }

        if (no_read > 200) {
            set_errno(ECONNRESET);
            return -1;
        }
    }

    if (n < maxlen) {
        m = recv(sock->bsd_socket, (void *) t, 1, flags);
    }

    if (errno != 0 && errno != ESPIPE && errno != EAGAIN) {
        return -1;
    }

    set_errno(0);
}


それともcopyがキー部分を指しているのか、ここでの実装は、rまたは読み出したデータの長さが指定されたmaxlenに達するまでrecvをループして呼び出すことであることがわかります.
この2つの関数は混乱していますが、ここを見るとわかるでしょう.よし寝て!