【问题标题】:PHP Socket with androidPHP Socket 与 android
【发布时间】:2015-05-23 10:31:53
【问题描述】:

我想问一下如何创建一个能够实时接收来自android手机的请求的PHP套接字?现在,我完成了这部分代码并能够使用 telnet 对其进行测试。但是,当安卓手机尝试连接时,它无法接收或发送任何内容到服务器。

if (!defined('SOCKET_ADDRESS')) {
    define('SOCKET_ADDRESS', '192.168.1.4');
}

if (!defined('SOCKET_PORT')) {
    define('SOCKET_PORT', '5888');
}

if (!defined('MAX_CLIENTS')) {
    define('MAX_CLIENTS', '10');
}
set_time_limit(0);

$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);
socket_bind($socket, SOCKET_ADDRESS, SOCKET_PORT) or die('Could not bind to address ' . SOCKET_ADDRESS . ' on port ' . SOCKET_PORT . "!\n");
socket_listen($socket, MAX_CLIENTS) or die("Could not setup socket listener!\n");

// setup read socket array
$read = array();

// client array w/ default initial socket
$clients = array('0' => array('socket' => $socket));

// force debug at first run..
$debug = true;
$time = time();
printf('Time: %d%s', $time, "\n");
$status = true;
while ($status) {

    if (time() - $time >= 10) {
        $time = time();
        printf('Time: %d%s', $time, "\n");
        $debug = true;
    }
    if ($debug === true) {
        printf('Debug: %s%s', $debug, "\n");
    }
    // $read[0] = $socket;
    if ($debug) {
        var_dump($read);
    }

    // Handle clients
    for ($i = 0; $i < count($clients); $i++) {
        if (isset($clients[$i]['socket'])) {
            if ($debug === true) {
                printf('Setting socket %d to client %d%s', $i, $i, "\n");
            }
            $read[$i] = $clients[$i]['socket'];
        }
    }
    if ($debug) {
        var_dump($read);
    }
    // Any changed sockets?
    // $write and $except are only placeholders
    $changed_sockets = socket_select($read, $write = NULL, $except = NULL, 0);
    if ($debug === true) {
        printf('Changed sockets: %d%s', $changed_sockets, "\n");
    }
    // Handle new connections
    if (in_array($socket, $read)) {
        for ($i = 0; $i < MAX_CLIENTS; $i++) {
            if (!isset($clients[$i])) {
                $clients[$i]['socket'] = socket_accept($socket);
                socket_getpeername($clients[$i]['socket'], $ip);
                $clients[$i]['ip'] = $ip;
                printf('Accepting connection into client %d from %s%s', $i, $ip, "\n");
                break;
            }
            // } elseif($i == MAX_CLIENTS - 1) {
            // echo 'Too many clients connected!', "\n";
            // }
            if ($changed_sockets < 1) {
                continue;
            }
        }
    }
    if ($debug) {
        var_dump($clients);
    }

    for ($i = 0; $i < count($clients); $i++) {
        $client = $clients[$i];
        // Has our client socket seen any changes?
        if (in_array($client['socket'], $read)) {
            printf('Client %d has changed! Reading...%s', $i, "\n");
            $data = socket_read($client['socket'], 1024);
            if ($data === false) {
                $error = socket_strerror(socket_last_error());
                printf('An error occured...%s%s', $error, "\n");
            }
            printf("Read raw data %s from client %i%s", $data, $i, "\n");
            if ($data === null) {
                // disconnected
                unset($clients[$i]);
            }

            $data = trim($data);
            if ($data == 'Q') {
                printf('Received exit command from client%s', "\n");
                socket_close($clients[$i]['socket']);
                $status = false;
            } elseif ($data) {
                // Strip whitespace
                printf('Received data: %s from client %d%s', $data, $i, "\n");
                $output = sprintf('%s%s%s', $data, "\n", chr(0));
                socket_write($client['socket'], $output);
            }
        }
    }

    // reset debug
    $debug = false;
}

socket_close($socket);

【问题讨论】:

    标签: php android sockets


    【解决方案1】:

    如果你想跳过我写的内容,这里有一个完整的 PHP 套接字服务器和 Android 套接字客户端的下载(包含所有源代码):https://developersfound.com/PHP_SocketServer_Android_SocketClient.zip

    或者有关您可能会发现有用的信息,请阅读 ....

    这里的一个重要经验法则是了解“HTTP 请求/响应模型”和 TCP 模型之间的区别。 TCP 优于 HTTP 的优点是您可以对消息进行排队并利用全双工(双向同时通信),而且开放的 TCP 连接响应速度更快。除非您的解决方案绝对需要排队和/或从全双工中受益,否则您实际上应该使用 RPC over HTTP 或 REST。 HTTP 在移动设备上更容易实现并且更可靠。在移动设备上长距离移动,往往会中断 TCP 连接,当连接中断时,您会失去任何排队,必须重新连接。重新连接也会占用更多的电池电量,并且可能会挂起客户端系统。另一个缺点是实时系统最终可能会产生大量实时连接,从而显着降低服务器速度;比繁忙的 HTTP 服务器更重要。

    但是,如果您的解决方案需要 TCP 或受益于 TCP 的优势,请继续阅读 ....

    这个代码库(在上面的链接中)有一个功能齐全的(自包含的)PHP 服务器和一个功能齐全的 Android 套接字客户端。该代码库应该为在 Android 中实现客户端套接字提供强有力的参考。此代码库是根据 Android 最佳实践实现的,并且可作为实现长时间运行流程以实现稳定性的有力参考。

    值得注意的是,Android 文档建议使用服务来实现套接字,因为无法解析套接字。出于这个原因,单例类型的模型是必要的。您会注意到此代码库使用 AIDL 与服务通信并使用广播来更新 UI。这是最佳实践,因为必须保护套接字免受垃圾收集和活动重新创建,这通常会破坏套接字连接。通过 AIDL 和 Thread Executors 绑定的服务都与长期运行流程稳定性的最佳实践相关联。

    希望这会有所帮助。

    【讨论】:

    • 如何改变你的来源,让客户端一直监听而不需要向服务器发送响应(消息)。当数据库更新时,我在服务器上进行了一些更改以写入消息。当我向客户端写消息时,我需要按下按钮(发送出站消息)然后我收到最后发送的消息。就像消息卡在某个地方(在缓冲区或......)我不太了解 java :(
    • 我还没有仔细研究这个问题,但是尝试在 php.net 上尝试这篇文章:php.net/manual/en/function.flush.php。您应该能够将此代码与传输中的字符标志结合起来,以发出套接字进程结束的信号。如果这有效,请告诉我。否则我会花一些空闲时间来解决这个问题。
    • 您好,该链接目前已失效。你移动代码了吗?请提供新位置。
    【解决方案2】:

    在 build.gradle 中添加这个库。

       compile "org.java-websocket:Java-WebSocket:1.3.0"
    

    连接:

     private void connectWebSocket() {
        URI uri;
        try {
            uri = new URI("ws://websockethost:8080");
        } catch (URISyntaxException e) {
            e.printStackTrace();
            return;
        }
    
        mWebSocketClient = new WebSocketClient(uri) {
            @Override
            public void onOpen(ServerHandshake serverHandshake) {
                Log.i("Websocket", "Opened");
                mWebSocketClient.send("Hello from " + Build.MANUFACTURER + " " + Build.MODEL);
            }
    
            @Override
            public void onMessage(String s) {
                final String message = s;
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        TextView textView = (TextView)findViewById(R.id.messages);
                        textView.setText(textView.getText() + "\n" + message);
                    }
                });
            }
    
            @Override
            public void onClose(int i, String s, boolean b) {
                Log.i("Websocket", "Closed " + s);
            }
    
            @Override
            public void onError(Exception e) {
                Log.i("Websocket", "Error " + e.getMessage());
            }
        };
        mWebSocketClient.connect();
    }
    

    发送消息:

    public void sendMessage(String message) {
        mWebSocketClient.send(message);
    }
    

    参考:https://github.com/elabs/mobile-websocket-example

    【讨论】:

    • 我可以使用android将xml文件发送到php吗?
    • 是的,您可以作为字符串发送。
    猜你喜欢
    • 2013-10-08
    • 1970-01-01
    • 1970-01-01
    • 2013-01-28
    • 2012-03-28
    • 2012-05-17
    • 2013-09-09
    • 2019-03-25
    • 1970-01-01
    相关资源
    最近更新 更多