使用Unix域套接字将PHP转换为Go

huangapple go评论76阅读模式
英文:

PHP to Go using Unix domain sockets

问题

我正在尝试使用Unix套接字让PHP向Go发送IPC消息。一切似乎都正常工作,除了PHP似乎一直在读取套接字的响应,不会放手。(浏览器的加载旋转器一直在转动,页面没有渲染。)我在PHP的socket_read()函数中使用了标志PHP_NORMAL_READ,并从Go中显式发送了"\n"。

在终端中观察Go进程,一切似乎在那一端都正常工作。

**编辑:**我认为这是浏览器缓存问题。如果我发送不同的数据让PHP回显,一切都按预期工作。我还切换到了fmt.Fprintln(),以确保我没有弄错换行符。

Go代码:

package main

import (
	"net"
	"fmt"
	"log"
	"os"
)

const socket_addr = "/tmp/odc_ws.sock"

func echoServer(c net.Conn){
	buf := make([]byte, 512)
	size, err := c.Read(buf)
	if err != nil {
		log.Fatal("Read error: ", err)
	}
	data := buf[0:size]		
	fmt.Println("Server received: ", string(data))
	
    // 新代码
    t := time.Now()
    retMsg := fmt.Sprintf("OK+ at %s", t)
    size, err = fmt.Fprintln(c, retMsg)    

    //size, err = c.Write(ok)

	if err == nil{
		fmt.Println("Wrote this many bytes: ", size)
	} else {
		log.Fatal("Write error: ", err)
	}
}

func main(){
	l, err := net.Listen("unix", socket_addr)
	if err != nil{
		fmt.Println("On noes: %s", err)
		return
	}
	defer l.Close()
	for{
		fd, err := l.Accept()
		if err != nil{
			log.Fatal("Accept error", err)
		}
		go echoServer(fd)
	}
	
}

PHP代码:

ob_implicit_flush();
$socket_file = "/tmp/odc_ws.sock";

if (($socket = socket_create(AF_UNIX, SOCK_STREAM, 0)) === false) {
    echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "<br>";
}
if (socket_connect($socket, $socket_file) === false) {
    echo "socket_connect() failed: reason: " . socket_strerror(socket_last_error($sock)) . "<br>";
}

$msg = 'PHP sent Go a message at ' . date('H:i:s');
$write_res = socket_write($socket, $msg, $msg_len = strlen($msg));
if($write_res != $msg_len){
	echo '<div>Socket write error: ' . socket_strerror( socket_last_error($socket) ) . '</div>';
}

while($read = socket_read($socket, 512, PHP_NORMAL_READ)){
	echo "<div>Server says: $read</div>";
}
socket_close($socket);

以上是你提供的代码的翻译。

英文:

I'm trying to use a Unix socket to have PHP send IPC messages to Go. Everything seems to work, except that PHP seems to keep reading the response from the socket, and won't let go. (The browser load-spinner keeps going, and there's no page render.) I'm using flag PHP_NORMAL_READ in the PHP:socket_read() function, and explicitly sending "\n" from Go.

Watching the Go process in the terminal, everything appears to work correctly on that end.

Edit: I think it was a browser caching issue. If I send different data back for PHP to echo, everything works as expected. I also switched to fmt.Fprintln() to make sure I wasn't getting the newline wrong.

Go:

package main

import (
	&quot;net&quot;
	&quot;fmt&quot;
	&quot;log&quot;
	&quot;os&quot;
)

const socket_addr = &quot;/tmp/odc_ws.sock&quot;

func echoServer(c net.Conn){
	buf := make([]byte, 512)
	size, err := c.Read(buf)
	if err != nil {
		log.Fatal(&quot;Read error: &quot;, err)
	}
	data := buf[0:size]		
	fmt.Println(&quot;Server received: &quot;, string(data))
	
    // NEW CODE
    t := time.Now()
    retMsg := fmt.Sprintf(&quot;OK+ at %s&quot;, t)
    size, err = fmt.Fprintln(c, retMsg)    	

    //size, err = c.Write(ok)

	if err == nil{
		fmt.Println(&quot;Wrote this many bytes: &quot;, size)
	} else {
		log.Fatal(&quot;Write error: &quot;, err)
	}
}

func main(){
	l, err := net.Listen(&quot;unix&quot;, socket_addr)
	if err != nil{
		fmt.Println(&quot;On noes: %s&quot;, err)
		return
	}
	defer l.Close()
	for{
		fd, err := l.Accept()
		if err != nil{
			log.Fatal(&quot;Accept error&quot;, err)
		}
		go echoServer(fd)
	}
	
}

PHP:

ob_implicit_flush();
$socket_file = &quot;/tmp/odc_ws.sock&quot;;

if (($socket = socket_create(AF_UNIX, SOCK_STREAM, 0)) === false) {
    echo &quot;socket_create() failed: reason: &quot; . socket_strerror(socket_last_error()) . &quot;&lt;br&gt;&quot;;
}
if (socket_connect($socket, $socket_file) === false) {
    echo &quot;socket_connect() failed: reason: &quot; . socket_strerror(socket_last_error($sock)) . &quot;&lt;br&gt;&quot;;
}

$msg = &#39;PHP sent Go a message at &#39; . date(&#39;H:i:s&#39;);
$write_res = socket_write($socket, $msg, $msg_len = strlen($msg));
if($write_res != $msg_len){
	echo &#39;&lt;div&gt;Socket write error: &#39; . socket_strerror( socket_last_error($socket) ) . &#39;&lt;/div&gt;&#39;;
}

while($read = socket_read($socket, 512, PHP_NORMAL_READ)){
	echo &quot;&lt;div&gt;Server says: $read&lt;/div&gt;&quot;;
}
socket_close($socket);

答案1

得分: 1

这不是一个PHP的问题;你没有关闭服务器连接,所以PHP会继续等待更多的数据。添加defer c.Close()

func echoServer(c net.Conn){
    defer c.Close()

    buf := make([]byte, 512)
    size, err := c.Read(buf)
    if err != nil {

PHP_NORMAL_READ是用来强制socket_read读取文本行而不是二进制流的。

根据PHP文档中关于socket_read的说明(我加了重点):

> socket_read()在成功时返回数据字符串,出错时返回FALSE(包括远程主机关闭连接的情况)

英文:

It is not a PHP issue; you are not closing the server connection, so PHP continues to wait for more data. Add a defer c.Close():

func echoServer(c net.Conn){
    defer c.Close()

    buf := make([]byte, 512)
    size, err := c.Read(buf)
    if err != nil {

PHP_NORMAL_READ is to force socket_read to read lines of text rather than binary streams.

From the PHP docs on socket_read (emphasis mine)

> socket_read() returns the data as a string on success, or FALSE on error (including if the remote host has closed the connection)

huangapple
  • 本文由 发表于 2013年8月24日 01:16:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/18408364.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定