为防止粘包使用了16位的标志位来进行分包
php做客户端使用的同步的tcp
$client = new swoole_client(SWOOLE_SOCK_TCP);
if (!$client->connect('127.0.0.1', 3333, -1)){
exit("connect failed. Error: {$client->errCode}\n");
}
$context = "hello world 1";
$len = pack("n", strlen($context));
$send = $len . $context;
$context = "hello world 2";
$len = pack("n", strlen($context));
$send .= $len . $context;
$client->send($send);
echo $client->recv();
go做服务端
package main
import (
"bufio"
"bytes"
"encoding/binary"
"errors"
"fmt"
"net"
)
func main() {
fmt.Println("服务端启动")
ln, err := net.Listen("tcp", "0.0.0.0:3333")
if err != nil {
fmt.Println("TCP监听错误", err)
}
for {
conn, err := ln.Accept()
if err != nil {
fmt.Println("TCP接收数据错误", err)
}
go handler(conn)
}
}
func handler(conn net.Conn) {
defer conn.Close()
reader := bufio.NewReader(conn)
for {
msg, err := unpack(reader)
if err!=nil {
fmt.Println("解包失败", err)
return
}
fmt.Println("接收到数据:", string(msg))
_, err = conn.Write([]byte("我是服务器\n"))
if err != nil {
fmt.Println("写入数据失败", err)
return
}
}
}
func unpack(reader *bufio.Reader) (string, error) {
lenByte, _ := reader.Peek(2)
lengthBuff := bytes.NewBuffer(lenByte)
var length int16
err := binary.Read(lengthBuff, binary.BigEndian, &length)
if err != nil {
return "", err
}
if int16(reader.Buffered()) < length+2 {
return "", errors.New("数据异常")
}
pack := make([]byte, int(length+2))
_, err = reader.Read(pack)
if err != nil {
return "", err
}
return string(pack[2:]), nil
}
补充一个go版本client
package main
import (
"bytes"
"encoding/binary"
"fmt"
"net"
"strconv"
"time"
)
func main() {
conn, err := net.Dial("tcp", ":3333")
if err != nil {
fmt.Println("err", err)
return
}
fmt.Println("go客户端建立连接成功")
defer conn.Close()
var data []byte
for i := 0; i < 3; i++ {
msg := "我是client" + strconv.Itoa(i)
length := int32(len(msg))
var buffer bytes.Buffer
_ = binary.Write(&buffer, binary.BigEndian, &length)
data = append(data, append(buffer.Bytes(), []byte(msg)...)...)
}
conn.Write(data)
n, _ := conn.Read(data[:])
fmt.Println(string(data[:n]))
time.Sleep(1e9)
}
|