用 go 实现 socket ,帮忙看看问题处在哪里

2021-04-06 22:50:06 +08:00
 awanganddong
package main

import (
	"bytes"
	"fmt"
	"net"
	"time"
)

func main() {
	listener, err := net.Listen("tcp", "127.0.0.1:9527")
	defer listener.Close()
	if err != nil {
		fmt.Printf("server err %v\n", err)
	} else {
		for {
			conn, err := listener.Accept()
			if err == nil {
				go handleConn(conn)
			}
		}
	}
}
func Read(conn net.Conn) (string, error) {
	readBytes := make([]byte, 1)
	var buf bytes.Buffer
	for {
		_, err := conn.Read(readBytes)
		if err != nil {
			return "", err
		}
		readByte := readBytes[0]
		if readByte == '\t' {
			break
		}
	}
	return buf.String(), nil
}
func Write(conn net.Conn, content string) (int, error) {
	var buf bytes.Buffer
	buf.WriteString(content)
	buf.WriteByte('\t')
	return conn.Write(buf.Bytes())
}

func handleConn(conn net.Conn) {
	for {
		conn.SetReadDeadline(time.Now().Add(2))
		if str, err := Read(conn); err == nil {
			fmt.Printf("收到的数据:%v\n", str)
			Write(conn, "server got:"+str)
		}else{
			fmt.Printf("read err: %v\n",err)
		}
	}
}

现在用 telnet 发送消息,然后报错 read err: read tcp 127.0.0.1:9527->127.0.0.1:56508: i/o timeout

6858 次点击
所在节点    Go 编程语言
14 条回复
codehz
2021-04-06 22:55:28 +08:00
time 的 add 默认单位是纳秒(
awanganddong
2021-04-06 23:04:07 +08:00
设置为以下还是同样报错
conn.SetReadDeadline(time.Now().Add(10 * time.Second))
codehz
2021-04-06 23:07:42 +08:00
所以你发送的内容有没有包含制表符呢
awanganddong
2021-04-06 23:09:24 +08:00
@codehz 我把制表符剔除试下
djoiwhud
2021-04-07 01:44:10 +08:00
我看了两分钟也没看出你这个 read 里面定义的 buf 是什么用途。
每次读一个字节的操作看起来是学习练手的。看得出你没认真读过计算机网络卷一。

另外 read 的 len 返回值务必处理。
writesome6
2021-04-07 09:43:13 +08:00
其实就是你设置的超时时间有问题
1000172
2021-04-07 10:45:53 +08:00
我之前用框架写时遇到连不通是因为跨域的问题(因为我用网页测试,框架内默认进行跨域验证,我重写了跨域验证方法后就好了),你这个没太仔细看,只是送点参考意见
bruce0
2021-04-07 10:52:24 +08:00
```
func Read(conn net.Conn) (string, error) {
readBytes := make([]byte, 1)
var buf bytes.Buffer
for {
_, err := conn.Read(readBytes)
if err != nil {
return "", err
}
readByte := readBytes[0]
if readByte == '\t' {
break
}
}
return buf.String(), nil
}
```
readBytes := make([]byte, 1) 这里你创建的这个切片,长度是 1, 一般没有这样设置的. 一般都是客户端和服务端约定一个包最大长度,比如 1024, 每次客户端和服务端发的数据都不会超过这个最大长度,

n, err := conn.Read(readBytes) 通过这个函数读的时候, 返回的 n 是这次读取的长度


而你现在传了一个长度为 1 的切片, 假设这次客户端发来的数据长度为 10 因为你的切片长度为 1 就只能读到第位 后面的都丢了
awanganddong
2021-04-07 12:55:35 +08:00
以上是我参照别人 demo 写的,里边逻辑确实有问题。
skiy
2021-04-07 12:56:14 +08:00
你的 buf.String() 永远是""
crescentBLADE
2021-04-08 18:11:26 +08:00
你这是意识流
awanganddong
2021-04-08 19:40:51 +08:00
属于瞎几把写,我再重新修改修改,里边逻辑不太对
awanganddong
2021-04-30 11:01:37 +08:00
socket 属于流的模式
这个要搞明白
以下是修改的代码

```
package main

import (
"fmt"
"io"
"net"
)

func main() {
listener, err := net.Listen("tcp", "127.0.0.1:9527")
if err != nil {
fmt.Printf("server err %v\n", err)
}
defer listener.Close()
for {
conn, err := listener.Accept()
if err == nil {
go handleConn(conn)
}
}

}

func handleConn(conn net.Conn) {

for {
readBytes := make([]byte, 1)
n, err := conn.Read(readBytes)
if err != nil && err != io.EOF {
fmt.Printf("read err:%v\n", err)
break
}
fmt.Printf("read content:%v", readBytes[:n])
_, err = conn.Write(readBytes[:n])
if err != nil {
fmt.Printf("write err:%v\n", err)
break
}
}
}

```
who1996
2021-05-06 17:42:10 +08:00
tcp 没有跨域,,跨域是因为 client 端的安全策略!!!

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/768514

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX