2012-10-24 182 views
10

我有一个GPS追踪器,通过GPRS连接将数据连接并发送到定义的公共服务器:端口。如何使用PHP侦听TCP端口?

我可以定义IP:GPS设备的端口

我的问题是,我可以只是在我的服务器上打开一个端口,侦听/保存数据使用PHP收到?

谢谢。

+1

http://php.net/manual/en/function.socket-listen.php? –

+0

什么使GPS跟踪器的型号?我知道的大部分也支持HTTP GET – Baba

+0

什么阻碍你试用它?你遇到了哪些具体错误? – hakre

回答

8

编辑/更新2017年8月16日: 用户和图书馆作者< @Navarr>评论说,他已经发布了我原来的答复代码是基于从库中的一个新的,更新的版本。链接到new code on his github here。随意探索新的代码,并参考这里的原始示例以获取洞察(我没有亲自探究/使用过新代码)。


下面的代码将使用此处找到的SocketServer.class.php文件。它意味着作为一个独立的进程运行,这意味着在Linux下我必须使文件可执行,然后使用“php my_server.php”从命令行运行它。 有关命令行运行PHP脚本的详细信息: http://www.funphp.com/?p=33

首先抢SocketServer.class.php文件位置: http://www.phpclasses.org/browse/file/31975.html

尝试使用此方法使用它,然后调整它来处理收到您的根据需要拥有传入的数据。希望能帮助到你。

<?php 

require_once("SocketServer.class.php"); // Include the File 
$server = new SocketServer("192.168.1.6",31337); // Create a Server binding to the given ip address and listen to port 31337 for connections 
$server->max_clients = 10; // Allow no more than 10 people to connect at a time 
$server->hook("CONNECT","handle_connect"); // Run handle_connect every time someone connects 
$server->hook("INPUT","handle_input"); // Run handle_input whenever text is sent to the server 
$server->infinite_loop(); // Run Server Code Until Process is terminated. 


function handle_connect(&$server,&$client,$input) 
{ 
    SocketServer::socket_write_smart($client->socket,"String? ",""); 
} 
function handle_input(&$server,&$client,$input) 
{ 
    // You probably want to sanitize your inputs here 
    $trim = trim($input); // Trim the input, Remove Line Endings and Extra Whitespace. 

    if(strtolower($trim) == "quit") // User Wants to quit the server 
    { 
     SocketServer::socket_write_smart($client->socket,"Oh... Goodbye..."); // Give the user a sad goodbye message, meany! 
     $server->disconnect($client->server_clients_index); // Disconnect this client. 
     return; // Ends the function 
    } 

    $output = strrev($trim); // Reverse the String 

    SocketServer::socket_write_smart($client->socket,$output); // Send the Client back the String 
    SocketServer::socket_write_smart($client->socket,"String? ",""); // Request Another String 
} 

编辑:在保持事物有关及功能这个答案,我发现最好不要继续依赖代码可能不总是保持可用(或在提供给定的URL外部源我的链接)。因此,为了方便起见,我在下面添加了与本文顶部链接的SocketServer.class.php文件相对应的代码。 (对于长度和复制/粘贴时可能缺少缩进/格式的道歉,我不是下面的代码的作者)。

<?php 
    /*! @class SocketServer 
    @author Navarr Barnier 
    @abstract A Framework for creating a multi-client server using the PHP language. 
    */ 
    class SocketServer 
    { 
    /*! @var config 
    @abstract Array - an array of configuration information used by the server. 
    */ 
    protected $config; 

    /*! @var hooks 
    @abstract Array - a dictionary of hooks and the callbacks attached to them. 
    */ 
    protected $hooks; 

    /*! @var master_socket 
    @abstract resource - The master socket used by the server. 
    */ 
    protected $master_socket; 

    /*! @var max_clients 
    @abstract unsigned int - The maximum number of clients allowed to connect. 
    */ 
    public $max_clients = 10; 

    /*! @var max_read 
    @abstract unsigned int - The maximum number of bytes to read from a socket at a single time. 
    */ 
    public $max_read = 1024; 

    /*! @var clients 
    @abstract Array - an array of connected clients. 
    */ 
    public $clients; 

    /*! @function __construct 
    @abstract Creates the socket and starts listening to it. 
    @param string - IP Address to bind to, NULL for default. 
    @param int - Port to bind to 
    @result void 
    */ 
    public function __construct($bind_ip,$port) 
    { 
    set_time_limit(0); 
    $this->hooks = array(); 

    $this->config["ip"] = $bind_ip; 
    $this->config["port"] = $port; 

    $this->master_socket = socket_create(AF_INET, SOCK_STREAM, 0); 
    socket_bind($this->master_socket,$this->config["ip"],$this->config["port"]) or die("Issue Binding"); 
    socket_getsockname($this->master_socket,$bind_ip,$port); 
    socket_listen($this->master_socket); 
    SocketServer::debug("Listenting for connections on {$bind_ip}:{$port}"); 
    } 

    /*! @function hook 
    @abstract Adds a function to be called whenever a certain action happens. Can be extended in your implementation. 
    @param string - Command 
    @param callback- Function to Call. 
    @see unhook 
    @see trigger_hooks 
    @result void 
    */ 
    public function hook($command,$function) 
    { 
    $command = strtoupper($command); 
    if(!isset($this->hooks[$command])) { $this->hooks[$command] = array(); } 
    $k = array_search($function,$this->hooks[$command]); 
    if($k === FALSE) 
    { 
    $this->hooks[$command][] = $function; 
    } 
    } 

    /*! @function unhook 
    @abstract Deletes a function from the call list for a certain action. Can be extended in your implementation. 
    @param string - Command 
    @param callback- Function to Delete from Call List 
    @see hook 
    @see trigger_hooks 
    @result void 
    */ 
    public function unhook($command = NULL,$function) 
    { 
    $command = strtoupper($command); 
    if($command !== NULL) 
    { 
    $k = array_search($function,$this->hooks[$command]); 
    if($k !== FALSE) 
    { 
    unset($this->hooks[$command][$k]); 
    } 
    } else { 
    $k = array_search($this->user_funcs,$function); 
    if($k !== FALSE) 
    { 
    unset($this->user_funcs[$k]); 
    } 
    } 
    } 

    /*! @function loop_once 
    @abstract Runs the class's actions once. 
    @discussion Should only be used if you want to run additional checks during server operation. Otherwise, use infinite_loop() 
    @param void 
    @see infinite_loop 
    @result bool - True 
    */ 
    public function loop_once() 
    { 
    // Setup Clients Listen Socket For Reading 
    $read[0] = $this->master_socket; 
    for($i = 0; $i < $this->max_clients; $i++) 
    { 
    if(isset($this->clients[$i])) 
    { 
    $read[$i + 1] = $this->clients[$i]->socket; 
    } 
    } 

    // Set up a blocking call to socket_select 
    if(socket_select($read,$write = NULL, $except = NULL, $tv_sec = 5) < 1) 
    { 
    // SocketServer::debug("Problem blocking socket_select?"); 
    return true; 
    } 

    // Handle new Connections 
    if(in_array($this->master_socket, $read)) 
    { 
    for($i = 0; $i < $this->max_clients; $i++) 
    { 
    if(empty($this->clients[$i])) 
    { 
    $temp_sock = $this->master_socket; 
    $this->clients[$i] = new SocketServerClient($this->master_socket,$i); 
    $this->trigger_hooks("CONNECT",$this->clients[$i],""); 
    break; 
    } 
    elseif($i == ($this->max_clients-1)) 
    { 
    SocketServer::debug("Too many clients... :("); 
    } 
    } 

    } 

    // Handle Input 
    for($i = 0; $i < $this->max_clients; $i++) // for each client 
    { 
    if(isset($this->clients[$i])) 
    { 
    if(in_array($this->clients[$i]->socket, $read)) 
    { 
    $input = socket_read($this->clients[$i]->socket, $this->max_read); 
    if($input == null) 
    { 
    $this->disconnect($i); 
    } 
    else 
    { 
    SocketServer::debug("{$i}@{$this->clients[$i]->ip} --> {$input}"); 
    $this->trigger_hooks("INPUT",$this->clients[$i],$input); 
    } 
    } 
    } 
    } 
    return true; 
    } 

    /*! @function disconnect 
    @abstract Disconnects a client from the server. 
    @param int - Index of the client to disconnect. 
    @param string - Message to send to the hooks 
    @result void 
    */ 
    public function disconnect($client_index,$message = "") 
    { 
    $i = $client_index; 
    SocketServer::debug("Client {$i} from {$this->clients[$i]->ip} Disconnecting"); 
    $this->trigger_hooks("DISCONNECT",$this->clients[$i],$message); 
    $this->clients[$i]->destroy(); 
    unset($this->clients[$i]); 
    } 

    /*! @function trigger_hooks 
    @abstract Triggers Hooks for a certain command. 
    @param string - Command who's hooks you want to trigger. 
    @param object - The client who activated this command. 
    @param string - The input from the client, or a message to be sent to the hooks. 
    @result void 
    */ 
    public function trigger_hooks($command,&$client,$input) 
    { 
    if(isset($this->hooks[$command])) 
    { 
    foreach($this->hooks[$command] as $function) 
    { 
    SocketServer::debug("Triggering Hook '{$function}' for '{$command}'"); 
    $continue = call_user_func($function,$this,$client,$input); 
    if($continue === FALSE) { break; } 
    } 
    } 
    } 

    /*! @function infinite_loop 
    @abstract Runs the server code until the server is shut down. 
    @see loop_once 
    @param void 
    @result void 
    */ 
    public function infinite_loop() 
    { 
    $test = true; 
    do 
    { 
    $test = $this->loop_once(); 
    } 
    while($test); 
    } 

    /*! @function debug 
    @static 
    @abstract Outputs Text directly. 
    @discussion Yeah, should probably make a way to turn this off. 
    @param string - Text to Output 
    @result void 
    */ 
    public static function debug($text) 
    { 
    echo("{$text}\r\n"); 
    } 

    /*! @function socket_write_smart 
    @static 
    @abstract Writes data to the socket, including the length of the data, and ends it with a CRLF unless specified. 
    @discussion It is perfectly valid for socket_write_smart to return zero which means no bytes have been written. Be sure to use the === operator to check for FALSE in case of an error. 
    @param resource- Socket Instance 
    @param string - Data to write to the socket. 
    @param string - Data to end the line with. Specify a "" if you don't want a line end sent. 
    @result mixed - Returns the number of bytes successfully written to the socket or FALSE on failure. The error code can be retrieved with socket_last_error(). This code may be passed to socket_strerror() to get a textual explanation of the error. 
    */ 
    public static function socket_write_smart(&$sock,$string,$crlf = "\r\n") 
    { 
    SocketServer::debug("<-- {$string}"); 
    if($crlf) { $string = "{$string}{$crlf}"; } 
    return socket_write($sock,$string,strlen($string)); 
    } 

    /*! @function __get 
    @abstract Magic Method used for allowing the reading of protected variables. 
    @discussion You never need to use this method, simply calling $server->variable works because of this method's existence. 
    @param string - Variable to retrieve 
    @result mixed - Returns the reference to the variable called. 
    */ 
    function &__get($name) 
    { 
    return $this->{$name}; 
    } 
    } 

    /*! @class SocketServerClient 
    @author Navarr Barnier 
    @abstract A Client Instance for use with SocketServer 
    */ 
    class SocketServerClient 
    { 
    /*! @var socket 
    @abstract resource - The client's socket resource, for sending and receiving data with. 
    */ 
    protected $socket; 

    /*! @var ip 
    @abstract string - The client's IP address, as seen by the server. 
    */ 
    protected $ip; 

    /*! @var hostname 
    @abstract string - The client's hostname, as seen by the server. 
    @discussion This variable is only set after calling lookup_hostname, as hostname lookups can take up a decent amount of time. 
    @see lookup_hostname 
    */ 
    protected $hostname; 

    /*! @var server_clients_index 
    @abstract int - The index of this client in the SocketServer's client array. 
    */ 
    protected $server_clients_index; 

    /*! @function __construct 
    @param resource- The resource of the socket the client is connecting by, generally the master socket. 
    @param int - The Index in the Server's client array. 
    @result void 
    */ 
    public function __construct(&$socket,$i) 
    { 
    $this->server_clients_index = $i; 
    $this->socket = socket_accept($socket) or die("Failed to Accept"); 
    SocketServer::debug("New Client Connected"); 
    socket_getpeername($this->socket,$ip); 
    $this->ip = $ip; 
    } 

    /*! @function lookup_hostname 
    @abstract Searches for the user's hostname and stores the result to hostname. 
    @see hostname 
    @param void 
    @result string - The hostname on success or the IP address on failure. 
    */ 
    public function lookup_hostname() 
    { 
    $this->hostname = gethostbyaddr($this->ip); 
    return $this->hostname; 
    } 

    /*! @function destroy 
    @abstract Closes the socket. Thats pretty much it. 
    @param void 
    @result void 
    */ 
    public function destroy() 
    { 
    socket_close($this->socket); 
    } 

    function &__get($name) 
    { 
    return $this->{$name}; 
    } 

    function __isset($name) 
    { 
    return isset($this->{$name}); 
    } 
} 
+0

此脚本必须在同一台服务器上运行,对不对? – gustyaquino

+0

是的。我在我的Linux服务器上运行它。将这个脚本放在一个名为“my_server.php”的文件中,并将它与SocketServer.class.php一起放到它们自己的文件夹中。切换到该目录,使文件可执行(“chmod a + x my_server.php”)并从命令行运行“php my_server.php”。 –

+0

好的,试过了。获取错误,“无法绑定地址。地址已在使用中”。这是什么意思? – gustyaquino

9

是的,使用socket_createsocket_bindsocket_listen,和socket_accept

http://www.php.net/manual/en/function.socket-create.php

http://www.php.net/manual/en/function.socket-bind.php

http://www.php.net/manual/en/function.socket-listen.php

http://www.php.net/manual/en/function.socket-accept.php

有在这些页面上有很多关于如何使用它们的例子。

+1

服务器是否有任何操作?打开一个端口? – gustyaquino

+0

是的,你可以用你的'socket_bind'调用指定。 – hexist