php-socket编程代码实例

  最近在看计算机网络,对socket原语有了一个新的认识,发现php也可以支持socket编程,而且非常方便。大家可以查看php手册,里面有很全面的socket操作函数。

然后我就写了一个简单的实例,大家可以借鉴一下。

首先说明一下,如果大家对socket不是很了解的话,那么先补充一下socket的知识。

socket可以直接和传输层的tcp协议交互,然后实现端对端的数据传输,socket的存在其实是一对,服务器端对客户端。

所以我们要实现的代码也是首先要实现服务器端,然后再实现客户端,先启动服务器端,以一个进程的形式在等待客户端调用,一旦客服端发起连接请求,服务器端就会和客户端创建一个连接,然后开始和客户端进行数据传输。

原语 含义
SOCKET 创建一个新的通讯端点
BIND 将套接字与一个本地地址关联
LISTEN 声明愿意接受连接;给出队列长度
ACCEPT 被动创建一个入境连接
CONNECT 主动创建一个连接
SEND 通过连接发送一些数据
RECEIVE 从连接上接收一些数据
CLOSE 释放链接
下面是php服务器端的代码: server.php

 #!/usr/bin/php -q
    <?php
    require './socket.php';
    $error_code = socket_server();

客户端代码:client.php

 <?php                                                                                                                  
    require './socket.php';
    $server_ip      = LOCALHOST_IP;
    $socket_port    = DEFAULT_SOCKET_PORT;
    $data           = 'hello world!';
    socket_client($server_ip, $socket_port, $data);
公用脚本(这里面是对服务器端和客户端具体实现): socket.php
<?php                                                                                                                  
    set_time_limit(0);
    define('LOCALHOST_IP',                  '127.0.0.1');
    define('DEFAULT_SOCKET_PORT',           2407);
    //允许同时连接到服务器端的客户机数目
    define('MAX_CONNECT_NUM',               5);
    define('DATA_LENGTH',                   1024);
    //定义服务器端错误code
    define('SOCKET_CREATE_ERROR',           '44001');
    define('SOCKET_SETBLOCK_ERROR',         '44002');
    define('SOCKET_BIND_ERROR',             '44003');
    define('SOCKET_LISTEN_ERROR',           '44004');
    define('SOCKET_ACCEPT_ERROR',           '44005');
    define('SOCKET_READ_DATA_ERROR',        '44005');
    define('SOCKET_WRITE_ERROR',            '44006');
    //定义客户端错误code
    define('SOCKET_CLIENT_CREATE_FAILED',   '55001');
    define('SOCKET_CLIENT_CONNECT_FAILED',  '55002');
    define('SOCKET_CLIENT_WRTIE_ERROR',     '55003');
    
    /**
     * 启用socket服务器端方法
     * @param:$host string 服务器端地址 default localhost
     * @param:$port int 服务器端口地址 default 2406
     * @param:$block bool 设置阻塞模式,true:阻塞 false:非阻塞 default true
     * @param:$error string 错误信息
     */
     function socket_server($host = LOCALHOST_IP, $port = DEFAULT_SOCKET_PORT, $block = true, 
        $max_connect = MAX_CONNECT_NUM, &$error = '') {
        //创建一个soket通讯端点
        if ( !($socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) ) {
            $error = "socket端点创建失败:" . get_socket_last_err();
            return SOCKET_CREATE_ERROR;
        }
        if ( $block ) $block_ret = socket_set_block($socket);
        else $block_ret = socket_set_nonblock($socket);
        if ( !$block_ret ) {
            $error = '阻塞模式设置失败:' . get_socket_last_err();
            return SOCKET_SETBLOCK_ERROR;
        }
        //将套接字和服务器地址绑定
        if ( !socket_bind($socket, $host, $port) ) {
            $error = "绑定服务器地址失败:" . get_socket_last_err();
            return SOCKET_BIND_ERROR;
        }
        //声明自己愿意接受连接,给出队列长度,同时可以允许多少个客户端连接到服务器
        if ( !socket_listen($socket, $max_connect) ) {
            $error = "服务器监听失败" . get_socket_last_err();
            return SOCKET_LISTEN_ERROR;
        }
        $curr_buff = '';
        $client_id = 0;
        while ( true ) {
            //被动创建一个入境连接
            if ( !($msg_socket = socket_accept($socket)) ) {
                $error = "创建入境连接失败" . get_socket_last_err();
                return SOCKET_ACCEPT_ERROR;
            }
            //从连接开始接收数据
            $buf = socket_read($msg_socket, DATA_LENGTH, PHP_BINARY_READ);
            if ( false === $buf ) {
                $error = "读取数据失败" . get_socket_last_err();
                return SOCKET_READ_DATA_ERROR;
            }
            $client_id ++;
            if ( $buf == "\r\n" ) {
                if ( $curr_buff == 'quit' ) {
                    $error = "Client #" . $client_id . ":Disconnect\n";
                }
                if ( $curr_buff == 'shutdown' ) {
                    socket_close($msg_socket);
                }
            }
            $msg = "Received msg was:$buf \n";
            //error_log(date("Y-m-d H:i:s") . "\t" . $msg, 3, "/tmp/log");
            if ( !socket_write($msg_socket, $msg, strlen($msg)) ) {
                $error = "write failed reason:" . get_socket_last_err();
                return SOCKET_WRITE_ERROR;
            }
            socket_close($msg_socket);
        }
    }
    /**
     * socket客户端方法 
     * @param:$host string 服务器端地址 default localhost
     * @param:$port int 服务器端口地址 default 2406
     * @param:$data mixed 要发送给服务器端的数据
     * @param:$error string 错误信息
     */
    function socket_client($host = LOCALHOST_IP, $port = DEFAULT_SOCKET_PORT, $data = '', &$error = '') {
        //创建客户端socket通讯端点
        if ( !($socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) ) {
            $error = "socket端点创建失败:" . get_socket_last_err();                                                        
            return SOCKET_CLIENT_CREATE_FAILED;
        }
        if ( !socket_connect($socket, LOCALHOST_IP, DEFAULT_SOCKET_PORT) ) {
            $error = "连接socket服务器失败:" . get_socket_last_err();
            return SOCKET_CLIENT_CONNECT_FAILED;
        }
        if ( !socket_write($socket, $data) ) {
            $error = "数据发送失败" . get_socket_last_err();
            return SOCKET_CLIENT_WRTIE_ERROR;
        }
        while ($buff = @socket_read($socket, DATA_LENGTH, PHP_NORMAL_READ) ) {
            echo ("Respones was:" . $buff . "\n");
        }
        socket_close($socket);
    } 
    /**
     * 获取socket执行的最后一条错误
     */
    function get_socket_last_err() {
        $error = socket_strerror(socket_last_error()) . "\n";
    }
把三个文件放到相同的目录下,然后php cli方式运行server.php以进程的方式挂载起来:php server.php &之后就可以运行client.php,也用cli方式运行:php client.php就可以看到hello world!,这说明客户端已经把data数据发送给服务器端,并且服务器端有做了简单的处理返回给了客户端。

你可能感兴趣的:(PHP,socket编程)