• PHP Socket基础


    出处:CSDN 作者: Matt Rutledget
    翻译: heiyeluren <heiyeluren_gmail_com>
    ◇ Socket基础
    ◇ 产生一个服务器
    ◇  产生一个客户端
    在这一章里你将了解到迷人而又让人容易糊涂的套接字(Sockets)。Sockets在PHP中是没有充分利用的功能。今天你将看到产生一个能使用客户端连接的服务器,并在客户端使用socket进行连接
    ,服务器端将详细的处理信息发送给客户端。
    当你看到完整的socket过程,那么你将会在以后的程序开发中使用它。这个服务器是一个能让你连接的HTTP服务器,客户端是一个Web浏览器,这是一个单一的 客户端/服务器 的关系。
    ◆ Socket 基础PHP使用Berkley的socket库来创建它的连接。你可以知道socket只不过是一个数据结构。你使用这个socket数据结构去开始一个客户端和服务器之间的会话。这个服务器是一直在监听准备产生一个


    新的会话。当一个客户端连接服务器,它就打开服务器正在进行监听的一个端口进行会话。这时,服务器端接受客户端的连接请求,那么就进行一次循环。现在这个客户端就能够发送信息到服务器
    ,服务器也能发送信息给客户端。
    产生一个Socket,你需要三个变量:一个协议、一个socket类型和一个公共协议类型。产生一个socket有三种协议供选择,继续看下面的内容来获取详细的协议内容。
    定义一个公共的协议类型是进行连接一个必不可少的元素。下面的表我们看看有那些公共的协议类型。

     

     

     

    表一:协议
    名字/常量     描述
    AF_INET  这是大多数用来产生socket的协议,使用TCP或UDP来传输,用在IPv4的地址
    AF_INET6     与上面类似,不过是来用在IPv6的地址
    AF_UNIX  本地协议,使用在Unix和Linux系统上,它很少使用,一般都是当客户端和服务器在同一台及其上的时候使用

    表二:Socket类型
    名字/常量     描述
    SOCK_STREAM  这个协议是按照顺序的、可靠的、数据完整的基于字节流的连接。这是一个使用最多的socket类型,这个socket是使用TCP来进行传输。
    SOCK_DGRAM  这个协议是无连接的、固定长度的传输调用。该协议是不可靠的,使用UDP来进行它的连接。
    SOCK_SEQPACKET  这个协议是双线路的、可靠的连接,发送固定长度的数据包进行传输。必须把这个包完整的接受才能进行读取。
    SOCK_RAW  这个socket类型提供单一的网络访问,这个socket类型使用ICMP公共协议。(ping、traceroute使用该协议)
    SOCK_RDM  这个类型是很少使用的,在大部分的操作系统上没有实现,它是提供给数据链路层使用,不保证数据包的顺序

    表三:公共协议
    名字/常量     描述
    ICMP  互联网控制消息协议,主要使用在网关和主机上,用来检查网络状况和报告错误信息
    UDP      用户数据报文协议,它是一个无连接,不可靠的传输协议
    TCP 传输控制协议,这是一个使用最多的可靠的公共协议,它能保证数据包能够到达接受者那儿,如果在传输过程中发生错误,那么它将重新发送出错数据包。

    现在你知道了产生一个socket的三个元素,那么我们就在php中使用socket_create()函数来产生一个socket。这个socket_create()函数需要三个参数:一个协议、一个socket类型、一个公共协议
    。socket_create()函数运行成功返回一个包含socket的资源类型,如果没有成功则返回false。
    Resourece socket_create(int protocol, int socketType, int commonProtocol);
    现在你产生一个socket,然后呢?php提供了几个操纵socket的函数。你能够绑定socket到一个IP,监听一个socket的通信,接受一个socket;现在我们来看一个例子,了解函数是如何产生、接受
    和监听一个socket。
    <?php
    $commonProtocol = getprotobyname(“tcp”);
    $socket = socket_create(AF_INET, SOCK_STREAM, $commonProtocol);
    socket_bind($socket, ‘localhost’, 1337);
    socket_listen($socket);
    // More socket functionality to come
    ?>
    上面这个例子产生一个你自己的服务器端。例子第一行,
    $commonProtocol = getprotobyname(“tcp”);
    使用公共协议名字来获取一个协议类型。在这里使用的是TCP公共协议,如果你想使用UDP或者ICMP协议,那么你应该把getprotobyname()函数的参数改为“udp”或“icmp”。还有一个可选的办法
    是不使用getprotobyname()函数而是指定SOL_TCP或SOL_UDP在socket_create()函数中。
    $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
    例子的第二行是产生一个socket并且返回一个socket资源的实例。在你有了一个socket资源的实例以后,你就必须把socket绑定到一个IP地址和某一个端口上。
    socket_bind($socket, ‘localhost’, 1337);
    在这里你绑定socket到本地计算机(127.0.0.1)和绑定socket到你的1337端口。然后你就需要监听所有进来的socket连接。
    socket_listen($socket);
    在第四行以后,你就需要了解所有的socket函数和他们的使用。

    表四:Socket函数
    函数名      描述
    socket_accept()接受一个Socket连接
    socket_bind()把socket绑定在一个IP地址和端口上
    socket_clear_error()清除socket的错误或者最后的错误代码
    socket_close()关闭一个socket资源
    socket_connect()开始一个socket连接
    socket_create_listen()在指定端口打开一个socket监听
    socket_create_pair()产生一对没有区别的socket到一个数组里
    socket_create()产生一个socket,相当于产生一个socket的数据结构
    socket_get_option()获取socket选项
    socket_getpeername()获取远程类似主机的ip地址
    socket_getsockname()获取本地socket的ip地址
    socket_iovec_add()添加一个新的向量到一个分散/聚合的数组
    socket_iovec_alloc()这个函数创建一个能够发送接收读写的iovec数据结构
    socket_iovec_delete()删除一个已经分配的iovec
    socket_iovec_fetch()返回指定的iovec资源的数据
    socket_iovec_free()释放一个iovec资源
    socket_iovec_set()设置iovec的数据新值
    socket_last_error()获取当前socket的最后错误代码
    socket_listen()监听由指定socket的所有连接
    socket_read()读取指定长度的数据
    socket_readv()读取从分散/聚合数组过来的数据
    socket_recv()从socket里结束数据到缓存
    socket_recvfrom()接受数据从指定的socket,如果没有指定则默认当前socket
    socket_recvmsg()从iovec里接受消息
    socket_select()多路选择
    socket_send()这个函数发送数据到已连接的socket
    socket_sendmsg()发送消息到socket
    socket_sendto()发送消息到指定地址的socket
    socket_set_block()在socket里设置为块模式
    socket_set_nonblock()socket里设置为非块模式
    socket_set_option()设置socket选项
    socket_shutdown()这个函数允许你关闭读、写、或者指定的socket
    socket_strerror()返回指定错误号的详细错误
    socket_write()写数据到socket缓存
    socket_writev()写数据到分散/聚合数组
    (注: 函数介绍删减了部分原文内容,函数详细使用建议参考英文原文,或者参考PHP手册)

    以上所有的函数都是PHP中关于socket的,使用这些函数,你必须把你的socket打开,如果你没有打开,请编辑你的php.ini文件,去掉下面这行前面的注释:
    extension=php_sockets.dll
    如果你无法去掉注释,那么请使用下面的代码来加载扩展库:
    <?php
    if(!extension_loaded(‘sockets’)) {
    if(strtoupper(substr(PHP_OS, 3)) == “WIN”) {
    dl(‘php_sockets.dll’);
    } else {
    dl(‘sockets.so’);
    }
    }
    ?>
    如果你不知道你的socket是否打开,那么你可以使用phpinfo()函数来确定socket是否打开。你通过查看phpinfo信息了解socket是否打开。如下图:

    查看phpinfo()关于socket的信息

    ◆ 产生一个服务器

    现在我们把第一个例子进行完善。你需要监听一个指定的socket并且处理用户的连接。

    <?php
    $commonProtocol = getprotobyname("tcp");
    $socket = socket_create(AF_INET, SOCK_STREAM, $commonProtocol);
    socket_bind($socket, 'localhost', 1337);
    socket_listen($socket);
    // Accept any incoming connections to the server
    $connection = socket_accept($socket);
    if($connection) {
    	socket_write($connection, "You have connected to the socket...\n\r");
    }
    ?>

    你应该使用你的命令提示符来运行这个例子。理由是因为这里将产生一个服务器,而不是一个Web页面。如果你尝试使用Web浏览器来运行这个脚本,那么很有可能它会超过30秒的限时。你可以使用
    下面的代码来设置一个无限的运行时间,但是还是建议使用命令提示符来运行。
    set_time_limit(0);
    在你的命令提示符中对这个脚本进行简单测试:
    Php.exe example01_server.php
    如果你没有在系统的环境变量中设置php解释器的路径,那么你将需要给php.exe指定详细的路径。当你运行这个服务器端的时候,你能够通过远程登陆(telnet)的方式连接到端口1337来测试这个
    上面的服务器端有三个问题:1. 它不能接受多个连接。2. 它只完成唯一的一个命令。3. 你不能通过Web浏览器连接这个服务器。
    这个第一个问题比较容易解决,你可以使用一个应用程序去每次都连接到服务器。但是后面的问题是你需要使用一个Web页面去连接这个服务器,这个比较困难。你可以让你的服务器接受连接,然
    后些数据到客户端(如果它一定要写的话),关闭连接并且等待下一个连接。
    在上一个代码的基础上再改进,产生下面的代码来做你的新服务器端:

    <?php
    // Set up our socket
    $commonProtocol = getprotobyname("tcp");
    $socket = socket_create(AF_INET, SOCK_STREAM, $commonProtocol);
    socket_bind($socket, 'localhost', 1337);
    socket_listen($socket);
    // Initialize the buffer
    $buffer = "NO DATA";
    while(true) {
    	// Accept any connections coming in on this socket
    	$connection = socket_accept($socket);
    	printf("Socket connected\r\n");
    	// Check to see if there is anything in the buffer
    	if($buffer != "") {
    		printf("Something is in the buffer...sending data...\r\n");
    		socket_write($connection, $buffer . "\r\n");
    		printf("Wrote to socket\r\n");
    	} else {
    		printf("No Data in the buffer\r\n");
    	}
    	// Get the input
    	while($data = socket_read($connection, 1024, PHP_NORMAL_READ)) {
    		$buffer = $data;
    		socket_write($connection, "Information Received\r\n");
    		printf("Buffer: " . $buffer . "\r\n");
    	}
    	socket_close($connection);
    	printf("Closed the socket\r\n\r\n");
    }
    ?>

    这个服务器端要做什么呢?它初始化一个socket并且打开一个缓存收发数据。它等待连接,一旦产生一个连接,它将打印“Socket connected”在服务器端的屏幕上。这个服务器检查缓冲区,如果
    缓冲区里有数据,它将把数据发送到连接过来的计算机。然后它发送这个数据的接受信息,一旦它接受了信息,就把信息保存到数据里,并且让连接的计算机知道这些信息,最后关闭连接。当连接
    关闭后,服务器又开始处理下一次连接。(翻译的烂,附上原文)
    This is what the server does. It initializes the socket and the buffer that you use to receive
    and send data. Then it waits for a connection. Once a connection is created it prints
    “Socket connected” to the screen the server is running on. The server then checks to see if
    there is anything in the buffer; if there is, it sends the data to the connected computer.
    After it sends the data it waits to receive information. Once it receives information it stores
    it in the data, lets the connected computer know that it has received the information, and
    then closes the connection. After the connection is closed, the server starts the whole
    process again.

    ◆ 产生一个客户端
    处理第二个问题是很容易的。你需要产生一个php页连接一个socket,发送一些数据进它的缓存并处理它。然后你又个处理后的数据在还顿,你能够发送你的数据到服务器。在另外一台客户端连接
    ,它将处理那些数据。
    To solve the second problem is very easy. You need to create a PHP page that connects to
    a socket, receive any data that is in the buffer, and process it. After you have processed the
    data in the buffer you can send your data to the server. When another client connects, it
    will process the data you sent and the client will send more data back to the server.

    下面的例子示范了使用socket:

    <?php
    // Create the socket and connect
    $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
    $connection = socket_connect($socket,’localhost’, 1337);
    while($buffer = socket_read($socket, 1024, PHP_NORMAL_READ)) {
    	if($buffer == "NO DATA") {
    		echo("<p>NO DATA</p>");
    		break;
    	} else {
    		// Do something with the data in the buffer
    		echo("<p>Buffer Data: " . $buffer . "</p>");
    	}
    }
    echo("<p>Writing to Socket</p>");
    // Write some test data to our socket
    if(!socket_write($socket, "SOME DATA\r\n")) {
    	echo("<p>Write failed</p>");
    }
    // Read any response from the socket
    while($buffer = socket_read($socket, 1024, PHP_NORMAL_READ)) {
    	echo("<p>Data sent was: SOME DATA<br> Response was:" . $buffer . "</p>");
    }
    echo("<p>Done Reading from Socket</p>");
    ?>

    这个例子的代码演示了客户端连接到服务器。客户端读取数据。如果这是第一时间到达这个循环的首次连接,这个服务器将发送“NO DATA”返回给客户端。如果情况发生了,这个客户端在连接之
    上。客户端发送它的数据到服务器,数据发送给服务器,客户端等待响应。一旦接受到响应,那么它将把响应写到屏幕上。

    这些Socket函数直接跟互联网的协议进行发送信息。相对于fopensock的流来讲,他们操作在一个比较底层的级别。通常,他们都是对C函数进行封装,并且名称都类似。如果你有使用C进行socket编
    程的经验,那么使用这些函数将是非常熟练的。我们这里不讨论特别详细的socket编程。
    使用这些函数能够解决高层级别函数所不能解决的难题。使用这些函数能够实现类似fopen的功能,你也许有很多方法来实现socket的功能,比如在PHP中使用CLI(Command-line Interface)来实
    现的Internet守护进程。
    resource socket_accept(resource socket)
    在你的脚本服务器端中,使用socket_accept接受一个进入的连接。你必须首先产生一个socket,绑定它到一个名字,并且设置它监听一个端口。在块模式中,socket_accept将产生一个唯一接受后
    的连接。在非块模式中,它没有建立连接则返回false。另外,当你有了一个新的socket资源后就能够进行读写操作。
    下面我们将示范一个简单的回显服务器端。它运行在CLI(命令行)下面,它在12345端口等待客户端的连接。
    socket_accept

    <?php
       set_time_limit(0);
        //create the socket
        if(($socket = socket_create(AF_INET, SOCK_STREAM, 0)) < 0)
        {
            print("Couldn't create socket: " . socket_strerror(socket_last_error()) . "\n");
        }
        //bind it to the given address and port
        if(($error = socket_bind($socket, gethostbyname($_SERVER['HOSTNAME']), 12345)) < 0)
        {
            print("Couldn't bind socket: " . socket_strerror(socket_last_error()) . "\n");
        }
        if(($error = socket_listen($socket, 5)) < 0)
        {
            print("Couldn't list on socket: " .
                socket_strerror(socket_last_error()) . "\n");
        }
        while(TRUE)
        {
            //wait for connection
            if(($accept = socket_accept($socket)) < 0)
            {
                print("Error while reading: " . socket_strerror($message) . "\n");
                break;
            }
            //send welcome message
            socket_write($accept, "Connection accepted\n");
            print(date('Y-m-d H:i:s') . " STATUS: Connection accepted\n");
            ob_flush();
            while(TRUE)
            {
                //read line from client
                if(FALSE === ($line = socket_read($accept, 1024)))
                {
                    print("Couldn't read from socket: " .
                        socket_strerror(socket_last_error()) . "\n");
                    break 2;
                }
                if(!@socket_write($accept, "ECHO: $line"))
                {
                    print(date('Y-m-d H:i:s') . " STATUS: Connection interrupted\n");
                    break;
                }
                print(date('Y-m-d H:i:s') . " READ: $line");
                ob_flush();
            }
            socket_close($accept);
        }
    ?>

    bool socket_bind(resource socket, string address, integer port)
    这个socket_bind()把一个socket资源绑定在一个地址上。这个socket必须由socket_create()函数返回的一个资源。这个地址必须是一个IP地址或者是一个保存Unix socket的路径。如果是运行在
    Internet上的socket,你还必须提供一个端口。
    socket_clear_error(resource socket)
    这个函数能够清除制定socket的错误,如果没有指定参数,那么将清除所有socket的错误。
    socket_close(resource socket)
    socket_close函数关闭一个socket并且清除该socket所占用的内存资源。
    boolean socket_connect(resource socket, string address, integer port)
    这个函数创建一个客户端到一个端口或者socket的连接。你必须提供一个由socket_create产生的socket。这个address参数必须到一个socket的路径或者是一个IP地址。如果是后者,还必须跟一个
    数字的端口号。
    下面例子演示了使用UDP协议的连接到游戏服务器然后获取信息的过程。
    socket_connect

    <?php
        //create UDP socket
        if(($socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP)) < 0)
        {
            print("Couldn't create socket: " .
                socket_strerror(socket_last_error()) . "\n");
        }
        //timeout after 5 seconds
        socket_set_option($socket, SOL_SOCKET,
            SO_RCVTIMEO, array('sec'=>5,'usec'=>0));
        //connect to the RtCW master server
        if(!socket_connect($socket, 'wolfmaster.idsoftware.com', 27950))
        {
            print("Couldn't connect: " .
                socket_strerror(socket_last_error()) . "\n");
        }
        //send request for servers
        socket_write($socket, "\xFF\xFF\xFF\xFFgetservers\x00");
        //get servers
        $server = array();
        while(FALSE !== ($line = @socket_read($socket, 4096)))
        {
            //parse data
            for($i=22; ($i+5) < strlen($line); $i += 7)
            {
                $ip = ord(substr($line, $i+1, 1)) . '.' .
                    ord(substr($line, $i+2, 1)) . '.' .
                    ord(substr($line, $i+3, 1)) . '.' .
                    ord(substr($line, $i+4, 1));
                $port = (ord(substr($line, $i+5, 1)) * 256) +
                    ord(substr($line, $i+6, 1));
                $server[] = array('ip'=>$ip, 'port'=>$port);
            }
        }
        print("<h1>" . count($server) . " Servers</h1>\n");
        //loop over servers, getting status
        foreach($server as $s)
        {
            print("<h1>{$s['ip']}:{$s['port']}</h1>\n");
            //connect to RtCW server
            if(!socket_connect($socket, $s['ip'], $s['port']))
            {
                print("<p>\n" .
                    socket_strerror(socket_last_error()) .
                    "\n</p>\n");
                continue;
            }
            //send request for status
            socket_write($socket, "\xFF\xFF\xFF\xFFgetstatus\x00");
            //get status from server
            if(FALSE === ($line = @socket_read($socket, 1024)))
            {
                print("<p>\n" .
                    socket_strerror(socket_last_error()) .
                    "\n</p>\n");
                continue;
            }
            $part = explode("\n", $line);
            //settings are in second line separated by backslashes
            $setting = explode("\\", $part[1]);
            print("<h2>Configuration</h2>\n");
            print("<p>\n");
            for($s=1; $s < count($setting); $s += 2)
            {
                print("\t\t{$setting[$s]} = {$setting[$s+1]}<br>\n");
            }
            print("</p>\n");
            print("<h2>Players</h2>\n");
            $lastPlayer = count($part) - 1;
            for($p=2; $p < $lastPlayer; $p++)
            {
                $player = explode(" ", $part[$p]);
                print("{$player[2]} Score={$player[0]} " .
                    "Ping={$player[1]}<br>\n");
            }
            print("</p>\n");
            ob_flush();
        }
        print("</table>\n");
        socket_close($socket);
    ?>

    resource socket_create(integer family, integer socket_type, integer protocol)
    socket_create初始化一个socket的结构。第一个参数是一个protocol family,或者域。你必须使用AF_INET来指定一个Internet连接,或者使用AF_UNIX来指定一个Unix socket连接。第二个参数
    是一个socket的类型,你可以从下面的表中选择。一般情况下,使用SOCK_STREAM来使用TCP协议,UDP协议使用SOCK_DGRAM。第三个参数指定为一个协议。使用SOL_TCP或SOL_UDP来分别对应TCP和
    UDP协议。还有一个选择是你能够使用getprotobyname函数来处理。
    Socket 类型
    常量 描述
    SOCK_DGRAM 自动寻址数据包socket
    SOCK_RAW RAW协议接口
    SOCK_RDM 可靠交换消息
    SOCK_SEQPACKET 顺序数据包socket
    SOCK_STREAM 流socket
    resource socket_create_listen(integer port, integer backlog)
    使用socket_create_listen是一种比socket_create更简单的产生一个socket进行监听。这个产生的socket将监听指定的端口,后面可选的参数backlog是设置允许最大的连接数。
    boolean socket_create_pair(integer family, integer socket_type, integer protocol, array handles)
    socket_create_pair函数产生一对socket连接。首先前三个参数是对一个socket_create的描述,这个handles参数是一个包含两个socket资源的数组。该函数是对C里面socketpair函数的封装。
    socket_create_pair

    <?php
        if(!socket_create_pair(AF_UNIX, SOCK_STREAM, 0, $socket))
        {
            print("Couldn't make sockets!\n");
            exit();
        }
        $child = pcntl_fork();
        if($child == -1)
        {
            print("Couldn't fork!\n");
            exit();
        }
        elseif($child > 0)
        {
            //parent
            socket_close($socket[0]);
            print("Parent: waiting for message\n");
            $message = socket_read($socket[1], 1024, PHP_NORMAL_READ);
            print("Parent: got message--$message\n");
            socket_write($socket[1], "Hello, Child Process!\n");
            pcntl_waitpid($child, $status);
        }
        else
        {
            //child
            socket_close($socket[1]);
            socket_write($socket[0], "Hello, Parent Process!\n");
            print("Child: waiting for message\n");
            $message = socket_read($socket[0], 1024, PHP_NORMAL_READ);
            print("Child: got message--$message\n");
            exit(0);
        }
    ?>

    value socket_get_option(resource socket, integer level, integer option)
    socket_get_option函数返回一个下表中所列的一个添加值,你必须提供一个由socket_create产生的socket资源和一个等级。这个获取的socket级别,可以使用SOL_SOCKET来确定这个级别参数。另
    外,使用协议,比如象SOL_TCP来表示一个TCP协议。这些选项可能是由socket_set_option设置的。
    socket_get_options

    <?php
        $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
        print('SO_BROADCAST: ' .
            socket_get_option($socket, SOL_SOCKET,
                SO_BROADCAST) . "<br>\n");
        print('SO_DEBUG: ' .
            socket_get_option($socket, SOL_SOCKET,
                SO_DEBUG) . "<br>\n");
        print('SO_DONTROUTE: ' .
            socket_get_option($socket, SOL_SOCKET,
                SO_DONTROUTE) . "<br>\n");
        print('SO_ERROR: ' .
            socket_get_option($socket, SOL_SOCKET,
                SO_ERROR) . "<br>\n");
        print('SO_KEEPALIVE: ' .
            socket_get_option($socket, SOL_SOCKET,
                SO_KEEPALIVE) . "<br>\n");
        print('SO_LINGER: ' .
            print_r(socket_get_option($socket, SOL_SOCKET,
                SO_LINGER), TRUE) . "<br>\n");
        print('SO_OOBINLINE: ' .
            socket_get_option($socket, SOL_SOCKET,
                SO_OOBINLINE) . "<br>\n");
        print('SO_RCVBUF: ' .
            socket_get_option($socket, SOL_SOCKET,
                SO_RCVBUF) . "<br>\n");
        print('SO_RCVLOWAT: ' .
            socket_get_option($socket, SOL_SOCKET,
                SO_RCVLOWAT) . "<br>\n");
        print('SO_RCVTIMEO: ' .
            print_r(socket_get_option($socket, SOL_SOCKET,
                SO_RCVTIMEO), TRUE) . "<br>\n");
        print('SO_REUSEADDR: ' .
            socket_get_option($socket, SOL_SOCKET,
                SO_REUSEADDR) . "<br>\n");
        print('SO_SNDBUF: ' .
            socket_get_option($socket, SOL_SOCKET,
                SO_SNDBUF) . "<br>\n");
        print('SO_SNDLOWAT: ' .
            socket_get_option($socket, SOL_SOCKET,
                SO_SNDLOWAT) . "<br>\n");
        print('SO_SNDTIMEO: ' .
            print_r(socket_get_option($socket, SOL_SOCKET,
                SO_SNDTIMEO), TRUE) . "<br>\n");
        print('SO_TYPE: ' .
            socket_get_option($socket, SOL_SOCKET,
                SO_TYPE) . "<br>\n");
    ?>

    Socket选项表
    选项 描述
    SO_BROADCAST 允许自动寻址的socket发送和接受广播包
    SO_DEBUG 打开socket调试功能,只有root才有权限打开该选项
    SO_DONTROUTE 不接受路由包通过网关
    SO_ERROR 获取并且清除最后一次的socket错误,这个选项也许不用设置
    SO_KEEPALIVE 打开保持激活状态的消息
    SO_LINGER Socket_colse和socket_shutdown的中止消息发送超时,该选项使用一个数组,包括l_onoff和l_linger两个键。
    SO_OOBINLINE 把数据直接插入到接受缓冲
    SO_RCVBUF 限制接受缓冲的最大字节
    SO_RCVLOWAT 延迟通过接受一个最小的数据
    SO_RCVTIMEO 延迟报告一个接受超时报告,使用数组的两个键:sec和usec
    SO_REUSEADDR 允许重新使用本地地址
    SO_SNDBUF 限制发送缓冲的最大字节
    SO_SNDLOWAT 延迟发送数据到这个协议当接受一个最小的字节
    SO_SNDTIMEO 延迟报告超时错误,当发送发送通过一个时间。该选项使用数组的键值:sec和usec
    SO_TYPE 获取socket的类型,该选项可能不用设置

    boolean socket_getpeername(resource socket, string address, integer port)
    socket_getpeername从指定的一个连接中获取地址和端口。如果连接为Unix socket,那么将返回文件系统的路径。
    boolean socket_getsockname(resource socket, string address, integer port)
    socket_getsockname放置一个名字到socket中,并且加上address和port参数。失败返回false。
    (下面的socket_iovec_* 函数不太了解,不敢乱翻译,保留原文)
    boolean socket_iovec_add(resource iovector, integer length)
    The socket_iovec_add unction adds an I/O vector to the scatter/gather array.
    resource socket_iovec_alloc(integer count, …)
    The socket_iovec_alloc function returns a resource for handling a collection of I/O vectors. The first argument specifies the number of vectors. Following arguments specify
    the length of each vector.
    boolean socket_iovec_delete(resource iovector, integer position)
    The socket_iovec_delete function removes the I/O vector at the given position.
    string socket_iovec_fetch(resource iovector, integer position)
    The socket_iovec_fetch function returns the value of the specified vector in the I/O vector resource.
    boolean socket_iovec_free(resource iovector)
    The socket_iovec_free function frees the memory used for an I/O vector resource.
    boolean socket_iovec_set(resource iovector, integer position, string value)
    The socket_iovec_set sets the value of I/O vector at the given position.
    integer socket_last_error(resource socket)
    socket_last_error函数返回操作中的任何socket函数产生的最后错误。你也许在上面函数中设置了socket资源的socket选项在指定的连接上。下面的表列出了返回的错误代码,你同样可以使用
    soclet_strerror函数来获取详细的错误。使用socket_clear_error函数清除socket的错误。
    Socket错误代码表
    常量  描述
    SOCKET_E2BIG 参数列表太长
    SOCKET_EACCES  没有许可权限
    SOCKET_EADDRINUSE  地址已经被使用
    SOCKET_EADDRNOTAVAIL  不能解析请求的地址
    SOCKET_EADV  广播(广告)错误
    SOCKET_EAFNOSUPPORT  Address family不支持的协议
    SOCKET_EAGAIN  资源暂时不能获得
    SOCKET_EALREADY 操作已经在执行
    SOCKET_EBADE 无效的交换
    SOCKET_EBADF  错误的文件描述符
    SOCKET_EBADFD  文件描述符错误的状态
    SOCKET_EBADMSG  错误的消息
    SOCKET_EBADR  无效的请求描述
    SOCKET_EBADRQC 无效的请求代码
    SOCKET_EBADSLT  无效的操作位置
    SOCKET_EBUSY  驱动或资源繁忙
    SOCKET_ECHRNG 信道号码超出范围
    SOCKET_ECOMM  发送通讯错误
    SOCKET_ECONNABORTED  软件原因导致通行中断
    SOCKET_ECONNREFUSED  连接被拒绝
    SOCKET_ECONNRESET  连接被相同的socket重置
    SOCKET_EDESTADDRREQ  必须需要目标地址
    SOCKET_EDQUOT 超出磁盘配额
    SOCKET_EEXIST 文件已存在
    SOCKET_EFAULT 错误的地址
    SOCKET_EHOSTDOWN  主机已关闭
    SOCKET_EHOSTUNREACH  没有路由到主机
    SOCKET_EIDRM  表示ID被删除
    SOCKET_EINPROGRESS  操作正在执行
    SOCKET_EINTR  系统调用被阻止
    SOCKET_EINVAL  无效的参数
    SOCKET_EIO  输入/ 输出错误
    SOCKET_EISCONN  传输终端已经连接
    SOCKET_EISDIR 是一个目录
    SOCKET_EISNAM  是一个指定的类型文件
    SOCKET_EL2HLT  级别2已中止
    SOCKET_EL2NSYNC  级别2不同步
    SOCKET_EL3HLT  级别3已中止
    SOCKET_EL3RST  级别3被重置
    SOCKET_ELNRNG 连接号超出范围
    SOCKET_ELOOP  太多级别的符号连接
    SOCKET_EMEDIUMTYPE  错误的媒介类型(中间类型)
    SOCKET_EMFILE  太多打开的文件
    SOCKET_EMLINK 太多的连接
    SOCKET_EMSGSIZE  消息太长
    SOCKET_EMULTIHOP  尝试次数太多
    SOCKET_ENAMETOOLONG  文件名太长
    SOCKET_ENETDOWN  网络已关闭
    SOCKET_ENETRESET  网络中断,连接被重置
    SOCKET_ENETUNREACH 网络不可达
    SOCKET_ENFILE  系统中太多打开的文件
    SOCKET_ENOANO 没有正极
    SOCKET_ENOBUFS  没有可用的缓存空间
    SOCKET_ENOCSI  没有可用的CSI结构
    SOCKET_ENODATA  没有可用的数据
    SOCKET_ENODEV 没有这样的驱动
    SOCKET_ENOENT  没有这样的文件或目录
    SOCKET_ENOLCK  没有可用的记录锁
    SOCKET_ENOLINK  已经有的服务的连接
    SOCKET_ENOMEDIUM  没有媒介被找到
    SOCKET_ENOMEM 不能分配内存
    SOCKET_ENOMSG  没有指定的消息类型
    SOCKET_ENONET 设备不在网络上
    SOCKET_ENOPROTOOPT  协议不可用
    SOCKET_ENOSPC 没有空间在驱动器
    SOCKET_ENOSR  超出的流资源
    SOCKET_ENOSTR 驱动不是一个流
    SOCKET_ENOSYS  函数没有执行
    SOCKET_ENOTBLK  块驱动是必须的
    SOCKET_ENOTCONN  传输终端没有连接
    SOCKET_ENOTDIR  没有一个目录
    SOCKET_ENOTEMPTY  目录为空
    SOCKET_ENOTSOCK Socket操作在一个非socket上
    SOCKET_ENOTTY  不相符的IO控制器
    SOCKET_ENOTUNIQ  在网络上名字不是唯一的
    SOCKET_ENXIO 没有这样的驱动或地址
    SOCKET_EOPNOTSUPP 操作不支持
    SOCKET_EPERM  操作不允许
    SOCKET_EPFNOSUPPORT Protocol family不支持
    SOCKET_EPIPE  失败的管道
    SOCKET_EPROTO 协议错误
    SOCKET_EPROTONOSUPPORT  协议不支持
    SOCKET_EPROTOTYPE  Socket上协议错误的类型
    SOCKET_EREMCHG  远程地址已改变
    SOCKET_EREMOTE  对象是远程的
    SOCKET_EREMOTEIO  远程I/O错误
    SOCKET_ERESTART 中断的系统调用将要重新开始
    SOCKET_EROFS  文件系统为只读
    SOCKET_ESHUTDOWN.  传输端点中断不能发送
    SOCKET_ESOCKTNOSUPPORT Socket类型不支持
    SOCKET_ESPIPE  不合法的检索
    SOCKET_ESTRPIPE  流管道错误
    SOCKET_ETIME  定时器到时
    SOCKET_ETIMEDOUT 连接超时
    SOCKET_ETOOMANYREFS  太多连接无法结合
    SOCKET_EUNATCH  无法附加协议驱动
    SOCKET_EUSERS  太多用户
    SOCKET_EWOULDBLOCK 资源暂时无法获得
    SOCKET_EXDEV  无效的交叉驱动连接
    SOCKET_EXFULL 交换已满

    boolean socket_listen(resource socket, integer backlog)
    这个socket_listen函数等待从客户端过来的连接,backlog参数设置允许最多等待连接的队列数。
    string socket_read(resource socket, integer length, integer type)
    socket_read函数从特定的socket中读取指定的字节,如果错误返回false。缺省下,是采用二进制安全的读取模式。你可以外在的设置type参数为PHP_BINARY_READ来改变读取模式。你也可以把
    type设置为PHP_NORMAL_READ。
    boolean socket_readv(resource socket, resource iovector)
    socket_readv函数把读取的数据插入到iovector资源中。
    integer socket_recv(resource socket, string buffer, integer length, integer flags)
    socket_recv函数读取数据插入到缓冲中。Length参数设置最多读取的字节数,flag参数可以使用MSG_OOB或MSG_PEEK。函数返回读取的字节数。
    integer socket_recvfrom(resource socket, string buffer, integer length, string host, integer port)
    socket_frcvfrom函数读取数据插入到缓存中。Length参数设置获取最多允许接受的字节数。设置flags参数可以为MSG_OOB 或 MSG_PEEK。PHP设置主机和端口参数适当的值能够获取从主机发出的数
    据。
    boolean socket_recvmsg(resource socket, resource iovector, array control, integer length, integer flags, string host, integer port)
    socket_recvmsg函数从socket中读取数据并且插入到一个I/O向量资源中。PHP设置control参数是一个具有三个元素的联合数组:cmsg_level, cmsg_type, 和 cmsg_data。Length参数是一个附加在
    数据中的关于获取数据的长度参数。Flags参数是设置允许值和返回值。在写的时间,PHP无法执行所有的输出常量。PHP设置host和port参数适当的值是为了获取从远程主机中发送的数据。
    (Socket_slect函数没有翻译,因为怕词不达意)
    integer socket_select(array read, array write, array exception, integer timeout_seconds, integer timeout_microseconds)
    The socket_select function waits for changes to sockets. PHP watches the sockets given in the read array for new data coming in. PHP watches the streams given in the write
    array for being ready to accept more data. PHP watches the streams given in the exception argument for errors. If the number of seconds specified in the timeout_seconds
    argument passes, the function returns. Use the optional timeout_microseconds argument to specify a timeout less than 1 second.
    The socket_select function returns the number of sockets that changed or FALSE if an error occurred. If the call timed out, this function returns zero. It also modifies the
    given arrays so that they include only those sockets that changed.
    If you have no sockets of a particular type to watch, you may pass an empty array or a variable set to NULL.
    integer socket_send(resource socket, string buffer, integer length, integer flags)
    socket_send函数把写数据到缓冲中,然后插入到连接中。你必须指定一个缓冲最大可写字节数。你同样可以设置flags参数为空,或者为下面联合常量中的一个:MSG_DONTROUTE和 MSG_OOB。函数
    结束返回已经写的字节数,失败返回false。
    boolean socket_sendmsg(resource socket, resource iovector, integer flags, string address, integer port)
    socket_sendmsg尝试发送数据到一个socket。它适合无连接的socket。Iovector参数是一个通过socket_iovec_alloc函数产生的资源。你必须指定flags参数为:NULL, MSG_DONTROUTE, MSG_OOB,或
    者是两个联合常量。你应当指定一个地址和一个Internet请求的端口。
    Socket_sendmsg函数发送数据返回true,但是不能保证数据一定到达。
    integer socket_sendto(resource socket, string buffer, integer length, integer flags, string address, integer port)
    socket_sendto函数尝试写数据到buffer缓冲中,并且发送给一个socket。它适合大部分无连接的socket。你必须指定flags为:NULL,MSG_DONTROUTE,MSG_OOB或者是一个两个联合常量。你还应但
    指定地址和一个请求的端口。
    Socket_sendto函数数据发送出去返回true,但是不能保证数据一定到达。

    boolean socket_set_block(resource socket)
    socket_set_block函数设置socket插入到一个块模式中,这是缺省模式。在块模式中,I/O操作正对于一个完成的请求。
    boolean socket_set_nonblock(resource socket)
    socket_set_nonblock函数设置socket插入到意个非块模式中。在非块模式中,I/O操作马上返回,即使没有数据。
    boolean socket_set_option(resource socket, integer level, integer option, integer value)
    socket_set_option函数给socket设置一个选项。Level参数设置一个标志级别的常量。有效的值包括:SOL_SOCKET, SOL_TCP和SOL_UDP。Option参数必须匹配文章上面的Socket选项表中的常量。
    boolean socket_shutdown(resource socket, integer how)
    socket_shutdown函数关闭一个关于I/O的socket。设置how为0则中止接受数据,设置为1则停止发送数据,设置为2则中止二者操作。
    string socket_strerror(integer error)
    socket_strerror函数返回一个错误号的详细错误信息。
    integer socket_write(resource socket, string buffer, integer length)
    socket_write函数写数据到buffer缓冲中然后输出到socket中。你可以指定length参数来指定缓冲的最大字节数。这个函数通常情况下比socket_send更方便。
    boolean socket_writev(resource socket, resource iovector)
    socket_writev函数通过I/O向量写数据到一个socket中。

  • 相关阅读:
    YARN分析系列之三 -- 从脚本入口分析 ResourceManager的初始化过程
    YARN分析系列之二 -- Hadoop YARN各个自模块说明
    MacOS平台上编译 hadoop 3.1.2 源码
    YARN分析系列之一 -- 总览YARN组件
    WCF入门 (14)
    WCF入门 (13)
    WCF入门(12)
    WCF入门(11)
    WCF入门(10)
    WCF入门(9)
  • 原文地址:https://www.cnblogs.com/gxldan/p/4066850.html
Copyright © 2020-2023  润新知