PHP的SOCKET
没办法,没找到太好的文章!
LXXXII. Socket functions
Warning
This module is EXPERIMENTAL. That means, that the behaviour of these functions, these function names, in concreto ANYTHING documented here can change in a future release of PHP WITHOUT NOTICE. Be warned, and use this module at your own risk.
The socket extension implements a low-level interface to the socket communication functions, providing the possibility to act as a socket server as well as a client.
The socket functions described here are part of an extension to PHP which must be enabled at compile time by giving the --enable-sockets option to configure.
For a more generic client-side socket interface, see fsockopen() and pfsockopen().
When using these functions, it is important to remember that while many of them have identical names to their C counterparts, they often have different declarations. Please be sure to read the descriptions to avoid confusion.
That said, those unfamiliar with socket programming can still find a lot of useful material in the appropriate Unix man pages, and there is a great deal of tutorial information on socket programming in C on the web, much of which can be applied, with slight modifications, to socket programming in PHP.
Example 1. Socket example: Simple TCP/IP server
This example shows a simple talkback server. Change the address and port variables to suit your setup and execute. You may then connect to the server with a command similar to: telnet 192.168.1.53 10000 (where the address and port match your setup). Anything you type will then be output on the server side, and echoed back to you. To disconnect, enter 'quit'.
<?php
error_reporting (E_ALL);
/* Allow the script to hang around waiting for connections. */
set_time_limit (0);
$address = '192.168.1.53';
$port = 10000;
if (($sock = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
echo "socket() failed: reason: " . strerror ($sock) . "\n";
}
if (($ret = bind ($sock, $address, $port)) < 0) {
echo "bind() failed: reason: " . strerror ($ret) . "\n";
}
if (($ret = listen ($sock, 5)) < 0) {
echo "listen() failed: reason: " . strerror ($ret) . "\n";
}
do {
if (($msgsock = accept_connect($sock)) < 0) {
echo "accept_connect() failed: reason: " . strerror ($msgsock) . "\n";
break;
}
do {
$buf = '';
$ret = read ($msgsock, $buf, 2048);
if ($ret < 0) {
echo "read() failed: reason: " . strerror ($ret) . "\n";
break 2;
}
if ($ret == 0) {
break 2;
}
$buf = trim ($buf);
if ($buf == 'quit') {
close ($msgsock);
break 2;
}
$talkback = "PHP: You said '$buf'.\n";
write ($msgsock, $talkback, strlen ($talkback));
echo "$buf\n";
} while (true);
close ($msgsock);
} while (true);
close ($sock);
?>
Example 2. Socket example: Simple TCP/IP client
This example shows a simple, one-shot HTTP client. It simply connects to a page, submits a HEAD request, echoes the reply, and exits.
<?php
error_reporting (E_ALL);
echo "<h2>TCP/IP Connection</h2>\n";
/* Get the port for the WWW service. */
$service_port = getservbyname ('www', 'tcp');
/* Get the IP address for the target host. */
$address = gethostbyname ('www.php.net');
/* Create a TCP/IP socket. */
$socket = socket (AF_INET, SOCK_STREAM, 0);
if ($socket < 0) {
echo "socket() failed: reason: " . strerror ($socket) . "\n";
} else {
"socket() successful: " . strerror ($socket) . "\n";
}
echo "Attempting to connect to '$address' on port '$service_port'...";
$result = connect ($socket, $address, $service_port);
if ($result < 0) {
echo "connect() failed.\nReason: ($result) " . strerror($result) . "\n";
} else {
echo "OK.\n";
}
$in = "HEAD / HTTP/1.0\r\n\r\n";
$out = '';
echo "Sending HTTP HEAD request...";
write ($socket, $in, strlen ($in));
echo "OK.\n";
echo "Reading response:\n\n";
while (read ($socket, $out, 2048)) {
echo $out;
}
echo "Closing socket...";
close ($socket);
echo "OK.\n\n";
?>
Table of Contents
accept_connect — Accepts a connection on a socket
bind — Binds a name to a socket
close — Closes a file descriptor
connect — Initiates a connection on a socket
listen — Listens for a connection on a socket
read — Read from a socket
socket — Create a socket (endpoint for communication)
strerror — Return a string describing a socket error
write — Write to a socket
User Contributed Notes
Socket functions
paulwade@greenbush.com
12-Nov-2000 11:55
[Editor's note: Not completely correct. Look at the (still not documented) functions (from the PHP source code):
int gethostbyaddr(string addr, string &name)
Given a human-readable address, sets name to be the host's name
int gethostbyname(string name, string &addr)
Given a hostname, sets addr to be a human-readable version of the host's address
int getpeername(int fd, string &addr[, int &port])
Given an fd, stores a string representing sa.sin_addr and the value of sa.sin_port into addr and port describing the remote side of a socket
int getsockname(int fd, string &addr[, int &port])
Given an fd, stores a string representing sa.sin_addr and the value of sa.sin_port into addr and port describing the local side of a socket
These and other functions will be documented here eventually]
I filed a wishlist bug because I do not see any way to get the IP address of the client. Until this is added I would use caution in implementing servers with PHP4. You can control access to selected ports at the OS level with linux. It might be wise to limit port access to specific machines or subnets.
tom.anheyer@berlinonline.de
09-Feb-2001 03:49
There are many undocumentated functions yet:
resource fd_alloc(void)
Allocates a file descriptor set
bool fd_dealloc(void)
De-allocates a file descriptor set
bool fd_set(int fd, resource set)
Adds a file descriptor to a set
bool fd_clear(int fd, resource set)
Clears a file descriptor from a set
bool fd_isset(int fd, resource set)
Checks to see if a file descriptor is set within the file descrirptor set
void fd_zero(resource set)
Clears a file descriptor set
int select(int max_fd, resource readfds, resource writefds, resource exceptfds, int tv_sec, int tv_usec)
Runs the select() system call on the sets mentioned with a timeout specified by tv_sec and tv_usec
int open_listen_sock(int port)
Opens a socket on port to accept connections
bool set_nonblock(int fd)
Sets nonblocking mode for file descriptor fd
int getsockname(int fd, string &addr[, int &port])
Given an fd, stores a string representing sa.sin_addr and the value of sa.sin_port into addr and port describing the local side of a socket
int gethostbyname(string name, string &addr)
Given a hostname, sets addr to be a human-readable version of the host's address
int getpeername(int fd, string &addr[, int &port])
Given an fd, stores a string representing sa.sin_addr and the value of sa.sin_port into addr and port describing the remote side of a socket
int gethostbyaddr(string addr, string &name)
Given a human-readable address, sets name to be the host's name
resource build_iovec(int num_vectors [, int ...])
Builds a 'struct iovec' for use with sendmsg, recvmsg, writev, and readv
First parameter is number of vectors, each additional parameter is the
length of the vector to create.
string fetch_iovec(resource iovec_id, int iovec_position)
Returns the data held in the iovec specified by iovec_id[iovec_position]
bool set_iovec(resource iovec_id, int iovec_position, string new_val)
Sets the data held in iovec_id[iovec_position] to new_val
bool add_iovec(resource iovec_id, int iov_len)
Adds a new vector to the scatter/gather array
bool delete_iovec(resource iovec_id, int iov_pos)
Deletes a vector from an array of vectors
bool free_iovec(resource iovec_id)
Frees the iovec specified by iovec_id
int readv(int fd, resource iovec_id)
Reads from an fd, using the scatter-gather array defined by iovec_id
int writev(int fd, resource iovec_id)
Writes to a file descriptor, fd, using the scatter-gather array defined by iovec_id
int recv(int fd, string buf, int len, int flags)
Receives data from a connected socket
May be used with SOCK_DGRAM sockets.
int send(int fd, string buf, int len, int flags)
Sends data to a connected socket
May be used with SOCK_DGRAM sockets.
int recvfrom(int fd, string &buf, int len, int flags, string &name [, int &port])
Receives data from a socket, connected or not
int sendto(int fd, string buf, int len, int flags, string addr [, int port])
Sends a message to a socket, whether it is connected or not
int recvmsg(int fd, resource iovec, array &control, int &controllen, int &flags, string &addr [, int &port])
Used to receive messages on a socket, whether connection-oriented or not
int sendmsg(int fd, resource iovec, int flags, string addr [, int port])
Sends a message to a socket, regardless of whether it is connection-oriented or not
int getsockopt(int fd, int level, int optname, array|int &optval)
Gets socket options for the socket
If optname is SO_LINGER, optval is returned as an array with members
"l_onoff" and "l_linger", otherwise it is an integer.
int setsockopt(int fd, int level, int optname, int|array optval)
Sets socket options for the socket
If optname is SO_LINGER, optval is expected to be an array
with members "l_onoff" and "l_linger", otherwise it should be an integer.
int socketpair(int domain, int type, int protocol, array &fds)
Creates a pair of indistinguishable sockets and stores them in fds.
int shutdown(int fd, int how)
Shuts down a socket for receiving, sending, or both.
11-Apr-2001 04:31
i've tested the 'one-shot http client' with some sites (yahoo, google, etc) and always had the same problem: read() won't return 0 when finished, rather a negative number. thus the read line would be
while (read ($socket, $out, 2048) >= 0)
this happens with php 4.0.4pl1.
nospam@1111-internet.com
20-Apr-2001 04:05
I also had some difficulties getting my http client to work properly when it came to reading response data from the socket (I'm using PHP 4.0.4pl1). The <=0 return value from the "read" call was only part of the problem.
I managed to get it working as follows:
<?php
function get_web_page ($url)
{
// ...
// main part of http client
// ...
/*
// this didn't work
$read="";
while (read($socket, $read_segment, 2048)>0)
{
$read.=$read_segment;
// test - even this didn't work
echo $read_segment;
// test 2 - this actually did work, but it's relatively useless
echo "1234 $read_segment";
}
close ($socket);
return $read;
*/
// this seems to work reliably
while (read($socket, $read_array[], 2048)>0) {}
close ($socket);
return implode("", $read_array);
}
?>
The scalar $read_segment method was logically sound, but it failed in some odd ways. Something to do with the "&buffer" concept perhaps (see the "read" function page)? I couldn't find any documentation that explains the difference between "&buffer" behavior vs. normal string variable behavior...
martinREMOVE@humany.REMOVE.com
09-May-2001 06:43
Socket support isn't available on windows yet :-( Hopefully soon tho
judeman@yahoo.com
04-Jun-2001 10:49
After several hours of working with sockets in an attempt to do UDP broadcasting, I thought a little help was in order for anyone else looking to do something similar, since it uses a number of those "undocumented" functions. Here's how I did it:
<?php
// here is a basic opening of the a socket. AF_INET specifies the internet domain. SOCK_DGRAM
// specifies the Datagram socket type the 0 specifies that I want to use the default protcol (which in this
// case is UDP)
$sock = socket(AF_INET, SOCK_DGRAM, 0);
// if the file handle assigned to socket is less than 0 then opening the socket failed
if($sock < 0)
{
echo "socket() failed, error: " . strerror($sock) . "\n";
}
// here's where I set the socket options, this is essential to allow broadcasting. An earlier comment (as of
// June 4th, 2001) explains what the parameters are. For my purposes (UDP broadcasting) I need to set
// the broadcast option at the socket level to true. In C, this done using SOL_SOCKET as the level param
// (2) and SO_BROADCAST as the type param (3). These may exist in PHP but I couldn't reference them
// so I used the values that referencing these variables in C returns (namely 1 and 6 respectively). This
// function is basically just a wrapper to the C function so check out the C documentation for more info
$opt_ret = setsockopt($sock, 1, 6, TRUE);
// if the return value is less than one, an error occured setting the options
if($opt_ret < 0)
{
echo "setsockopt() failed, error: " . strerror($opt_ret) . "\n";
}
// finally I am ready to broad cast something. The sendto function allows this without any
// connections (essential for broadcasting). So, this function sends the contents of $broadcast_string to the
// general broadcast address (255.255.255.255) on port 4096. The 0 (param 4) specifies no special
// options, you can read about the options with man sendto
$send_ret = sendto($sock, $broadcast_string, strlen($broadcast_string), 0, '255.255.255.255', 4096);
// if the return value is less than 0, an error has occured
if($send_ret < 0)
{
echo "sendto() failed, error: " . strerror($send_ret) . "
\n"; }
// be sure to close your socket when you're done
close($sock);
aaron.cameron@cityvu.com
12-Jun-2001 05:36
I was wondering if anyone has had any trouble setting up a simple listening server in php-4.0.5 running on linux. I have almost exactly the example, none of the commands report errors and the accept_connect() blocks the system as if it were listening, but it refuses to actually accept connects. A quick netstat also shows that it is not in fact listening. I've tried several ports (all above 1024) and the result stays the same.
My only theory is that php4 can't use sockets when it's compiled as a CGI. Any help would be great.
james@introverted.com
13-Jun-2001 12:50
I you are using PHP 4.0.7-dev from CVS then you will find that all of the Sockets module functions have changed. I've put a list together that details the functions and what their arguments are (as of June 12th 2001), as well as a re-written Example 1 from the PHP sockets documentation page (It works!): http://www.php.net/manual/en/ref.sockets.php
The new functions listing and converted Example 1 is available here: http://introverted.com/php-sockets.html
aaron.cameron@cityvu.com
13-Jun-2001 02:42
I've discovered why the server wasn't working. It is actually kind of querky. The ip and port to listen on are read in by a config file reader, and even though the values are trimed, the port wasn't being typcasted to int by bind the way it would in many other functions. By adding an explicit typecast to int in the bind call, everything worked fine.
rumblepipe@altavista.com
28-Jun-2001 12:04
The php socket read() function takes a fourth argument if you expect to use it like you would with c.
The fourth argument I've been using (with success, finally) is PHP_SYSTEM_READ.
I had to get that info from a person associated with this site (thank you), so I'm a little surprised a note about this wasn't already here.