2

嗨,我是这类东西的新手,但这就是我想做的。

我正在尝试实现一个聊天应用程序,用户将在其中从网站发送他们的查询,并且一旦网站用户发送消息。它将出现在将回答他们的查询的网站所有者的 android 移动应用程序中。简而言之,我想实现实时聊天。

现在我只是简单地尝试将消息从 android 应用程序发送到 php 服务器。但是,当我在 chrome 中从 Dreamweaver 运行我的 php 脚本时,浏览器会继续加载,并且在我从客户端发送消息时不显示任何输出。

有时,php脚本会显示一些我从android(客户端)发送的输出。但我不知道它何时有效,何时无效。

所以我想在我从客户端发送这些消息后立即在 php 脚本中显示这些消息,反之亦然(没有为客户端实现反之亦然,但我们将不胜感激)。

这是我到目前为止所做的。

php脚本:

 <?php

 set_time_limit (0);
 $address = '127.0.0.1';

 $port = 1234;

 $sock = socket_create(AF_INET, SOCK_STREAM, 0);
 socket_bind($sock, $address, $port) or die('Could not bind to address');
 socket_listen($sock);


 $client = socket_accept($sock);
 $welcome = "Roll up, roll up, to the greatest show on earth!\n? ";
 socket_write($client, $welcome,strlen($welcome)) or die("Could not send connect string\n");

do{
$input=socket_read($client,1024,1) or die("Could not read input\n");
echo "User Says:  \n\t\t\t".$input;

if (trim($input) != "")
    { 
    echo "Received input: $input\n";
    if(trim($input)=="END")
    {
        socket_close($spawn);
        break;
    }
}
else{

$output = strrev($input) . "\n"; 
socket_write($spawn, $output . "? ", strlen (($output)+2)) or die("Could not write output\n");              
echo "Sent output: " . trim($output) . "\n";

}
}
while(true);


socket_close($sock);
echo "Socket Terminated";
?>

安卓代码:

  public class ServerClientActivity extends Activity {
   private Button bt;
   private TextView tv;
   private Socket socket;
   private String serverIpAddress = "127.0.0.1";

   private static final int REDIRECTED_SERVERPORT = 1234;

   @Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    bt = (Button) findViewById(R.id.myButton);
    tv = (TextView) findViewById(R.id.myTextView);

    try
    {
        InetAddress serverAddr = InetAddress.getByName(serverIpAddress);
        socket = new Socket(serverAddr, REDIRECTED_SERVERPORT);
    } 
    catch (UnknownHostException e1) 
    {
        e1.printStackTrace();
    }
    catch (IOException e1)
    {
        e1.printStackTrace();
    }


    bt.setOnClickListener(new OnClickListener() {
        public void onClick(View v) {
           try
           {
              EditText et = (EditText) findViewById(R.id.EditText01);
              String str = et.getText().toString();
              PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true);
              out.println(str);
              Log.d("Client", "Client sent message");
           }
           catch (UnknownHostException e)
           {
              tv.setText(e.getMessage());
              e.printStackTrace();
           }
           catch (IOException e) 
           {
              tv.setText(e.getMessage());
              e.printStackTrace();
           }
           catch (Exception e) 
           {
              tv.setText(e.getMessage());
              e.printStackTrace();
           }
        }

     });       

   }
 }

我刚刚粘贴了 Android 的 onclick 按钮事件代码。编辑文本是我要输入文本的文本框。ip地址和端口与php脚本中的相同。

4

4 回答 4

1

我建议使用事件驱动框架来处理您的连接。

有一个相当不错的例子叫做React,但是它里面有很多其他的东西你可能想要去掉,这样你的应用程序就不会依赖数百个外部组件。

React 根据libevent您是否安装了消息循环使用消息循环stream_select

您使用闭包处理事件,例如:

    $client->on('read', function($data) use ($client) {
        $client->onRead($data);
    });

有了这个,您将能够处理大量同时连接,并且不会占用您所有的 CPU。

发生某些事情时,您的代码将被执行。

如果不出意外,看看它是如何工作的,你会更好地理解如何创建一个非阻塞事件驱动的套接字服务器。

于 2012-06-26T10:22:21.623 回答
1

首先 - 您的服务器一次只能处理一个客户端连接,这对聊天没有意义。

我看不到您如何处理 Android 端的套接字连接,但无论如何,只要您的脚本执行不会执行“ socket_accept() ”并等待连接,它就不会允许您再次连接。

您应该运行 1 个循环进程来获取新的客户端连接并将每个连接的客户端分叉到单独的进程中。

看看我在这里编写的基于相同原理的相同轻量级 PHP 服务器: https ://github.com/webdevbyjoss/Aaaaa---space-ships-combat-multiplayer-game/blob/master/server/server .php

忽略与 Websockets 相关的“ doHandshake() ”和“ WebSocketFrame::decode/WebSocketFrame::encode ”,但其余的应该没问题。

通常它运行循环

while (true) 

    if (($msgsock = socket_accept ( $sock )) === false) {
        echo "socket_accept() failed: reason: " . socket_strerror ( socket_last_error ( $sock ) ) . "\n";
    break;
    }

    // We got a client connected, lets process it in separate thread
    if (($pid = pcntl_fork()) === -1) {
        echo "pcntl_fork() failed. Make sure you are on Linux sustem, but not on Windows\n";
        break;
    }

    if (!$pid) { // client
        handleClient($msgsock);
        exit();
    }

    // parent server will wait to accept more clients connections in new loop
}

handleClient()函数中,您应该有一个单独的循环来与客户端通信。

while (true) {
    if (false === ($buf = socket_read ( $msgsock, 2048, PHP_BINARY_READ ))) {
        echo "socket_read() failed: reason: " . socket_strerror ( socket_last_error ( $msgsock ) ) . "\n";
        return;
    }

    if (empty($buf)) { // do disconnection check
        echo "Client disconnected\n";
        return;
    }

   // -------------------------------------------------------------
   // PUT YOUR BUSINESS LOGIC HERE
   // TO HANDLE MESSAGES OF THE CHAT AND GENERATE RESPONSE TO USER
   // I RECOMMEND TO USE SOMETHING LIKE MEMCACHE/REDIS/MONGO/MYSQL/TXT-FILES
   // FOR MULTIPROCESS DATA INTERCHANGE
   // -------------------------------------------------------------

// transfer data to client
    socket_write($msgsock, $returnText, strlen($returnFrame));
}

socket_close ( $msgsock );
于 2012-06-26T08:08:56.087 回答
0

您的地址 127.0.0.1 将解析为运行代码的机器。所以应用程序实际上会尝试连接到自身。在 MSDOS 控制台上键入ipconfig /all并改用该地址。

于 2013-05-05T03:40:25.527 回答
0

您是否尝试在发送到服务器之前将 '\r\n' 添加到 EditText 的值中?我认为问题不在于客户端和服务器之间的连接,因为连接失败时它不会显示错误。
也许在您的情况下,socket_read($client,1024,1) 必须在“\r\n”处停止读取。

更新:您的本地 ip 可能会导致连接错误。看看这个链接

于 2012-06-26T08:20:29.497 回答