i want my socket to use UDP. I changed this line:

if (!($s_listen = socket_create(AF_INET, SOCK_STREAM, getprotobyname("tcp"))))
  myerror_d();

to this:

if (!($s_listen = socket_create(AF_INET, SOCK_DGRAM, getprotobyname("udp"))))
  myerror_d();

and i get an error:
Operation not supported

i'm using php 4.3.6 with sockets enabled.

    hmm... would a more verbose error message be given by:

    if (!($s_listen = socket_create(AF_INET, SOCK_DGRAM, getprotobyname("udp"))))
    	die(socket_strerror(socket_last_error()));

    ?

      like your picture. 😉

      that's precisely what my error function does

      /* display error message */
      function myerror() {
        echo '[error]: ' . socket_strerror(socket_last_error()) . "\n";
      }
      
      /* display error message and die */
      function myerror_d() {
        myerror();
        die();
      }
      
      

        my sysadmin tells me that i'm working in User Mode Linux (UML). i'm wondering if this will make a difference...he mentioned something about http aarp or something....

        it's debian 2.4 kernel

        when i login, get
        Linux server 2.4.24-1um #1 Mon Mar 1 18:23:10 PST 2004 i686 GNU/Linux

          anybody have ideas? c'mon! it's my birthday today!

            i found more detail....i started taking apart my code and testing line by line. as it turns out, the error is not with the socket creation, but the socket listen. i also had my sysadmin turn up the level of error reporting. this is my error:

            Warning: socket_listen() unable to listen on socket [95]: Operation not supported in /var/www/socktest.php on line 41

            here is the code in socktest.php

            <?
            
            $listen_addr = '199.227.90.72';
            $listen_port = 1234;
            
            define('STATE_NICKNAME', 1);
            define('STATE_WAITING', 2);
            define('STATE_CHALLENGE', 3);
            define('STATE_BOXING', 4);
            
            
            
            /* display error message */
            function myerror() {
              echo '[error]: ' . socket_strerror(socket_last_error()) . "\n";
            }
            
            /* display error message and die */
            function myerror_d() {
              myerror();
              die();
            }
            
            
            if (!($s_listen = socket_create(AF_INET, SOCK_DGRAM, getprotobyname("udp")))) 
              myerror_d(); 
            
            // reuse listening socket address
            if (!socket_set_option($s_listen, SOL_SOCKET, SO_REUSEADDR, 1))
              myerror_d();
            
            // set socket to non-blocking
            if (!socket_set_nonblock($s_listen))
              myerror_d();
            
            /* bind listening socket to specific address/port */
            if (!socket_bind($s_listen, $listen_addr, $listen_port))
              myerror_d();
            
            /* listen on listening socket */
            if (!socket_listen($s_listen))
              myerror_d();
            
            
            
            ?>
            

              Totally off the wall probbably not helpful post here.

              Trying to listen on a post that is in use?

              A slew of troans, data miners, infoseek type apps use port 1234, check your netstat just to be sure.

                thanks for info...don't want to be confused with those folks. does anyone have a 'map' of what ports are for what uses? is there any general protocol? still trying to get my head around the idea of a port...does using a less-used port mean your packets get through faster?

                as for my problem, just found in the PHP documentation this helpful tidbit:

                "socket_listen() is applicable only to sockets of type SOCK_STREAM or SOCK_SEQPACKET. "

                what the heck? so how do you listen with a UDP socket?? do you just do a recv or read at random and deal with any data? polling or something? seems kinda odd to have your script spazzing out trying to listen for packets all the time that might not come.

                  does anyone have a 'map' of what ports are for what uses?

                  http://www.iana.org/assignments/port-numbers

                  It occurs to me that UDP is (generally) connectionless.
                  I've never studied networking, but doesnt that mean that it doesnt make sense to use listen?

                  EDIT:
                  Could look at [man]socket_recvfrom/man and [man]socket_sendto/man instead.
                  Beej's guide to socket programming in C had an example using revcfrom() and sendto(), so I suppose those 2 are the PHP equivalents.

                    My question would by why are u chosing SOCKDGRAM instead of SOCKSTREAM ... whats the Difference ... I understand the basics of programming with berkley sockets in c ... and this doesnt seem to that much different in php ... I would say ... change to SOCK_STREAM .... I believe that defaults to a udp connection...

                      I would say ... change to SOCK_STREAM .... I believe that defaults to a udp connection...

                      But datagram sockets use UDP, while stream sockets should use TCP, isnt it?

                      So it doesnt really make sense to use SOCK_STREAM when trying to use UDP, IMO.

                        only other thing I can think of ... based on my limitted knowledge of this is to try AF_INET6 ... unless u are sure ur machines are running IP version 4 instead of 6 ... just an idea

                          thanks for the help! and yes...SOCK_DGRAM is UDP, SOCK_STREAM is TCP.

                          All the information I've been able to acquire indicates that UDP is the way to go for game servers. apparently TCP has this issue that the socket will block waiting for acks/missing packets to be sent and all the other packets get trapped in the meantime.

                          i've been checking into socket_recvfrom and socket_sendto but i'm confused about how to organize the various clients who might connect. i'm starting to suspect that because UDP is connectionless or whatever that I'm going to have to build some kind of protocol from scratch. the socket_listen() and socket_accept() commands were so useful because socket_accept() returns a resource id to help me distinguish the different connections and keep their data straight.

                          i'm also a bit confused about the blocking/looping/polling thing. right now i have an endless loop....i'm sure i can figure out how to terminate the script when there are no clients connected, but I'm concerned about making sure my socket server is as responsive as possible. i'm not doing much processing on each message--mostly just bouncing 5 byte messages between clients--but the socket_select command still confuses me a bit.

                          anybody have any suggestions?

                            it occurred to me that posting my code might be helpful...here's the essential part that works as a tcp socket server:

                            /* assign listening socket */
                            if (!($s_listen = socket_create(AF_INET, SOCK_STREAM, getprotobyname("tcp"))))
                              myerror_d();
                            
                            // reuse listening socket address
                            if (!socket_set_option($s_listen, SOL_SOCKET, SO_REUSEADDR, 1))
                              myerror_d();
                            
                            // set socket to non-blocking
                            if (!socket_set_nonblock($s_listen))
                              myerror_d();
                            
                            /* bind listening socket to specific address/port */
                            if (!socket_bind($s_listen, $listen_addr, $listen_port))
                              myerror_d();
                            
                            /* listen on listening socket */
                            if (!socket_listen($s_listen))
                              myerror_d();
                            
                            /* set initial vars and loop until $abort is set to true */
                            $s_clients = Array();
                            $abort = false;
                            
                            while (!$abort) {
                              /* sockets we want to pay attention to */
                              $set = array_merge($s_listen, $s_clients);
                            
                              if (socket_select($set, $set_w = NULL, $set_e = NULL, 1, 0) > 0) {
                                /* loop through sockets */
                                foreach ($set as $sock) {
                                  /* listening socket has a connection, deal with it */
                                  if ($sock == $s_listen) {
                                    if (!($this = socket_accept($s_listen)))
                                      myerror();
                                    else {
                                      /* add socket to client list and announce connection */
                                      $s_clients[$this] = $this;
                                      socket_getpeername($this, $addr);
                                      $cdata[$this]['addr']  = $addr;
                                      $cdata[$this]['buf']   = '';
                                      $cdata[$this]['state'] = STATE_NICKNAME;
                            
                                  echo "[connection]: $addr\n";
                                  send_single($this, 'N');
                                }
                              }
                              else {
                                /* client socket has incoming data */
                                if (($read = socket_read($sock, 1024)) === false || $read == '') {
                                  if ($read != '')
                                    myerror();
                                  else /* no error, but connection was closed, so tell everyone */
                                    on_quit($sock);
                            	/* remove client from arrays */
                            	unset($s_clients[$sock]);
                            	unset($cdata[$sock]);
                            	list_waiting();
                                }
                                else {
                                  /* if data does not contain a null char, put in the buffer */
                                  if (strchr($read, "\0") === false)
                                    $cdata[$sock]['buf'] .= $read;
                                  else
                            	// handle it
                                    handle_data($sock, $read);
                                }
                              }
                            }
                              }
                            }
                            
                            echo "[end]\n";
                            

                            the socket_listen() command is the one that causes the error....i need to find a way to distinguish folks who connect.

                              alrighty!

                              after much research (google search, reading man pages, etc.), i have some more info for anybody who's interested.

                              with UDP sockets, you apparently don't use socket_listen or socket_accept. As best I can tell, UDP sockets are pretty raw and messages must be parsed to determine where they came from and what they are saying--at least it seems that way from the C code i've seen...lots of structs, etc.

                              anyways, I did find something from PHPFREAKS.COM...which i'm currently looking into...a TCP/UDP server/client class. its socket LISTEN function doesn't appear to properly handle UDP sockets (it tries to listen on them anyway) but i think it might be useful. it is attached.

                              anyways, this sure would be a lot easier if the PHP functions were documented. i've been to php.net and almost NONE of these UDP functions have any documentation at all. if anybody knows where to find more info, i would be eternally grateful.

                              in the meantime, i think i'm going to just start testing these function and see what i can come up with.

                                ok so i've taken a stab at writing a UDP socket server...unfortunately i can't connect with a FLASH client or TELNET. both fail...telnet says:

                                $ telnet 199.227.90.72 1234
                                Trying 199.227.90.72...
                                telnet: Unable to connect to remote host: Connection refused/QUOTE]

                                flash just fails. this is not surprising...they probably only support TCP connections. i therefore need to write a client PHP script that will send a UDP message to the listening socket...if anybody has tips, i'd love to hear them.

                                for your reference, here's my test script:

                                <?
                                // note that the UDP functions might require
                                // an IP address for host...if so use gethostbyname($host)
                                $host = '199.227.90.72';
                                $port = 1234;
                                
                                echo "running UDP_SOCKET.PHP\n";
                                echo "HOST is $host\n";
                                echo "PORT is $port\n";
                                
                                // DEBUG FUNCTIONS==================
                                // these output info 
                                
                                function SpitOutArray($arrArg, $nameofarr, $depth=0) {
                                	$strIndent = str_repeat("\t", $depth);
                                	if ($depth==0) {
                                		echo $strIndent . "spitting out array '$nameofarr'\n";
                                	}
                                	if (!is_array($arrArg)) {
                                		if(is_object($arrArg)) {
                                			echo $strIndent . $nameofarr . " is an object...\n";
                                			PrintProperties($arrArg, $nameofarr, $depth+1);
                                		} else {
                                			$stroutput = $strIndent . $nameofarr . "=" . $arrArg . "\n";
                                			echo $stroutput;
                                		}
                                	} else {
                                		$stroutput = $strIndent . $nameofarr . " is an array...\n";
                                		echo $stroutput;
                                		foreach($arrArg as $key =>$value) {
                                			SpitOutArray($value, $nameofarr . "." . $key, $depth + 1);
                                		}
                                	}
                                
                                }
                                
                                function PrintProperties($obj, $obj_name, $depth=0) {
                                	$strIndent = str_repeat("\t", $depth);
                                	echo $strIndent . "printing properties of " . $obj_name . "\n";
                                	$arr = get_object_vars($obj);
                                	while (list($prop, $val) = each($arr))
                                		if (is_array($val)) {
                                			SpitOutArray($val, $prop, $depth+1);
                                		} else {
                                			echo $strIndent . "$prop = $val\n";
                                		}
                                }
                                
                                //=====================
                                
                                // SOCKET STUFF================
                                
                                function jtasockerror()
                                {
                                	global $mysock;
                                	return "[error]:" . socket_strerror(socket_last_error($mysock)) . "\n";
                                
                                }
                                
                                function Send($string, $host, $port = null) // Send a packet. Use this if you are using UDP.
                                {
                                	global $mysock, $host, $port;
                                	socket_sendto($mysock, $string, strlen($string), 0, $host, $port) or die(jtasockerror());
                                }
                                
                                function Recv($len) // Recieve from a socket. Use this if you are using UDP.
                                {
                                	global $mysock;
                                
                                $buf = null;
                                $name = null;
                                $portarg = null;
                                socket_recvfrom($mysock, $buf, $len, 0, $name, $portarg) or die(jtasockerror());
                                return array($buf, $name, $portarg);
                                }
                                
                                echo "preparing to create socket\n";
                                // create the socket
                                if (!($mysock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP)))
                                	die(jtasockerror());
                                
                                echo "preparing to bind socket\n";
                                // connect the socket to the port
                                if (!socket_bind($mysock, $host, $port))
                                	die('Cannot bind to ' . $host . ':' . $port . '. Reason: ' . jtasockerror());
                                
                                //echo "socket connected...preparing to set reuse\n");
                                //if (!socket_set_option($mysock, SOL_SOCKET, SO_REUSEADDR, 1))
                                //  myerror_d();
                                
                                
                                echo "setting socket to blocking\n";
                                // set blocking?
                                socket_set_block($mysock) or die(jtasockerror());
                                // set NONBLOCKING?
                                //socket_set_nonblock($mysock) or die(jtasockerror());
                                echo "ok, socket set to block\n";
                                
                                $arr_sockets_to_watch = Array($mysock);
                                SpitOutArray($arr_sockets_to_watch, "sockets to watch");	
                                
                                while (1) {
                                	// wait for the socket to change
                                	// socket_select(&$read, &$write, &$exception, timeout_sec, timeout_usec)
                                	// NOTE that these arrays of sockets are passed by reference and will be
                                	// modified by the select function.
                                	$changed_socks = socket_select($arr_sockets_to_watch, $set_w = NULL, $set_e = NULL, 0, 100);
                                //	echo "changed socks returned $changed_socks\n";
                                	if ($changed_socks > 0) {
                                		// data to be read!
                                		echo "there is data to be read...select returned $changed_socks\n";
                                		foreach($arr_sockets_to_watch as $sock) {
                                			if ($sock = $mysock) {
                                				// our original socket has changed...read the data
                                				echo "select found a changed socket...running Recv...\n";
                                				$result = Recv(1024);
                                				// for debugging...we need to see null chars.
                                				$result = str_replace("\0", "<NULLCHAR>\n", $result);
                                				SpitOutArray($result);
                                			} else {
                                				// a new sock?? currently shouldn't happen.
                                				echo "Unrecognized socket returned by select\n";
                                				die(jtasockerror());
                                			}
                                		}
                                	} elseif ($changed_socks === false) {
                                		// socket_select failed!
                                		die(jtasockerror());
                                	} else {
                                		// no sockets have data....just keep looping
                                	}
                                
                                }
                                
                                
                                socket_close($mysock) or die(jtasockerror());
                                
                                ?>

                                  Just a question, why are you trying to write a socket server in PHP? Due to its lack of anything even resembling threads it becomes horribly ineffective if the number of clients increases over about, well one.

                                    Regarding PHP having process control, you are mistaken...

                                    check this link:
                                    http://www.php.net/manual/en/ref.pcntl.php

                                    You're also wrong about the number of clients....I've already written a very lightweight TCP socket server in PHP that supports 2-4 clients effectively for a 2-player boxing game I've written. This possible because the server is just processing a few bytes per message....and really just forwarding most of them.

                                    I will admit that it's a little bit odd to be writing a UDP server in PHP, but the functions are pretty high level. The C functions (which are likely to be much faster and more effective) have all kinds of struct manipulation and byte sequence issues which are a bit beyond me at the moment. I have to walk before I run.

                                    If you know of any effective tutorials on UDP socket management, I would love to see them.

                                      Write a Reply...