PHP套接字,无法连接 - 循环?

标签 php sockets

您好,我正在尝试在 PHP 中学习和构建套接字脚本,这是我的代码:

客户:

include_once('server.php');

$host = "localhost"; 
$port    = 1025;

$message = "Hello Server";

// create socket
$socket = socket_create(AF_INET, SOCK_STREAM, 0);
if ($socket === false) { 
 echo "socket_create() failed: reason: " . socket_strerror(socket_last_error($socket)) . "\n";
 }
// connect to server
    socket_bind($socket, $host);
    if (socket_connect($socket, $host, $port) === false) { 
         echo "socket_connect() failed: reason: " . socket_strerror(socket_last_error($socket)) . "\n";
    }
    else { echo "Connected"; }

服务器:
// Variables 
$host = "localhost"; 
$port = 1025; 

// No timeout 
set_time_limit(0); 

// Create socket
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP) or die("Can't create socket..");

if ($socket === false) {
    echo "Unable to create socket. Error: {$errno} : {$errstr}\n"; 
    die();
}


// Bind Socket
if (socket_bind($socket, $host) === false) {
    echo "socket_listen() failed: reason: " . socket_strerror(socket_last_error($socket)) . "\n";
}
else { echo "Connected to {$host}:{$port}"; }

// Socket listen
if (socket_listen($socket, 5) === false) {
    echo "socket_listen() failed: reason: " . socket_strerror(socket_last_error($socket)) . "\n";
}

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



// Socket close
socket_close($socket);

但是我错过了一些我无法弄清楚并且我不知道是什么,当我尝试从客户端连接时它只是加载没有任何 react ,这里有人能指出我正确的方向并告诉我我做错了什么吗?

最佳答案

在您的客户端上,您不需要 socket_bind() 。那是为了打开连接以供其他系统连接;简而言之,成为服务器。

我们的客户端脚本:

<?php // client.php
$host = "127.0.0.1"; // connect _does_ do DNS lookups, unlike bind, which is mentioned below, but for simplicity of the example I'm explicitly naming the IP address.
$port    = 1025;
$message = "Hello Server";

// create socket
$socket = socket_create(AF_INET, SOCK_STREAM, 0);
if ($socket === false) {
    // Using die() here because we really don't want to continue on while in an error condition.
    die('socket_create() failed: reason: ' . socket_strerror(socket_last_error($socket));
}

// connect to server
if (socket_connect($socket, $host, $port) === false) { 
     die('socket_connect() failed: reason: ' . socket_strerror(socket_last_error($socket));
}

socket_write($socket, $message);
socket_close($socket);

在您的服务器中,您应该监听 0.0.0.0(或特定 IP 地址),而不是指定域名。 0.0.0.0 表示监听所有 IP 地址,任何特定 IP 地址表示仅监听为该地址配置的一个接口(interface)。

例如,如果您的服务器有 2 个 NIC,一个分配给公共(public)地址,例如 1.2.3.4 ,另一个分配给本地地址 192.168.0.2 。只需拥有 TCP/IP,您还可以免费获得环回 127.0.0.1

如果您想限制对您的服务器脚本的访问,仅限于您网络上的其他主机,您可以将监听地址设置为 192.169.0.2 。即使您的服务器可以通过 1.2.3.4 的公共(public) IP 访问,此脚本也不会监听任何该流量。

如果要将对服务器脚本的访问限制在该机器上运行的其他进程,则需要使用 127.0.0.1 。使用“localhost”不会阻止任何人,因为 bind 不执行任何 DNS 查找(并且 PHP 的 socket_bind() 只是围绕基于 BSD 套接字的系统调用 bind 的薄包装)。它甚至不查看主机文件。因此,任何非 IP 字符串都将被转换为整数,通常导致它变为 0,并且该 0 将转换为 0.0.0.0 ,这将允许从所有接口(interface)进行访问,尽管您认为您只是在监听本地主机流量.

当您接受连接时,它会创建一个新的套接字资源,我在下面的示例中将其命名为 $clientSocket。不要混淆新主机连接时创建的套接字和您的监听套接字;它们非常相似,但有一个非常重要的区别:当你的监听套接字有新消息时,它总是说有一个新的主机连接,所以你应该 accept 。如果它是客户端套接字,那么您将使用 readrecv 。 (我更喜欢 recv 因为更好的控制,但我在下面的示例中使用 read 来更清楚地显示过程,而不是通过引用来增加困惑......这也是我不打算显示 select 的原因。)

我们的服务器脚本:
<?php //server.php
$listen_address = "0.0.0.0";
$port = 1025; 
$maxBuffer = 1024; // bytes, not characters.

// No timeout 
//set_time_limit(0); // Shouldn't be necessary in CLI.

// Create socket
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

if ($socket === false) {
    die('Unable to create socket: ' . $socket_strerror(socket_last_error($socket)) . PHP_EOL);
}

// Bind Socket
if (socket_bind($socket, $listen_address, $port) === false) {
    die('socket_bind() failed: ' . socket_strerror(socket_last_error($socket)) . PHP_EOL);
}
else { 
    echo "Connected to {$listen_address}:{$port}\n"; 
}

// Accept our client connection

// Typically, this would be where we'd put a loop with socket_select,
// but for our example, since we'll be exiting as soon as we have our
// first packet, we'll listen, accept, read, then close.
if (socket_listen($socket) === false) {
    die('socket_listen() failed: ' . socket_strerror(socket_last_error($socket)) . PHP_EOL);
}

$clientSocket = socket_accept($socket);
if ($clientSocket === false) {
    die('socket_accept() failed: ' . socket_strerror(socket_last_error($socket)) . PHP_EOL);
}

// Because the contents of a packet could be longer than our
// buffer size, it's advisable to peek at the socket to see
// if it would block before saying that our message is complete.
// In our example, we're receiving 12 bytes out of our maximum 1024,
// so I leave handling large packets as an exercise for the developer.
$message = socket_read($clientSocket, $maxBuffer);

var_dump($message);

// Socket close
socket_close($clientSocket);
socket_close($socket);

最后,这是运行上述困惑的方法。

请注意,我将让服务器和客户端在同一个 TTY 中运行,我会让服务器作为后台进程运行(使用 & 修饰符),但我不会重定向它们的输出,所以两个脚本都会将他们的输出吐到同一个终端。
myhost.mydomain$ php ./server.php &
[8] 76399
Connected to 0.0.0.0:1025
myhost.mydomain$ php ./client.php
string(12) "Hello Server"
[8]+  Done                    php ./server.php

关于PHP套接字,无法连接 - 循环?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33655696/

相关文章:

php - 检查具有多个输入的数据库表

python - 测试来自 Python 套接字异常的特定错误号

java - Android LocalSocket 在阻塞读取时不会关闭

javascript - 使用node.js连接socket.io

javascript - 将php数组值循环到html数据属性

php - 文本框在 Firefox 3.6 中无法正确显示

php - $this->renderPartial() 和 $this->render() 使用 $this->layout=false 之间的区别

php - Slim Framework API - 如何为多个 .php 的存储 API 配置 .htaccess 文件

c - 如何在 C 中创建用于读取套接字数据的缓冲区

具有自定义类的 BufferedReader 的 java.lang.StackOverflowError