Sockets 通道的golang问题(缓冲与非缓冲)
我正在做一个个人项目,它将运行在一个树莓圆周率与一些传感器连接到它 它由两个程序组成:Sockets 通道的golang问题(缓冲与非缓冲),sockets,go,concurrency,channels,writing,Sockets,Go,Concurrency,Channels,Writing,我正在做一个个人项目,它将运行在一个树莓圆周率与一些传感器连接到它 它由两个程序组成: 每X秒从传感器读取数据的服务器 在sqlite数据库上保存数据并可以发送一些命令的客户端 服务器可以: 从传感器读取数据,将其写入套接字,以便客户端可以将其保存在数据库中 监听套接字,这样当客户端发送一些命令时,它就可以执行它并将响应发送回客户端 从传感器读取的函数和处理套接字连接的函数在不同的goroutine中执行,因此,为了在从传感器读取数据时在套接字上发送数据,我在main函数中创建了一个[]字节
- 从传感器读取数据,将其写入套接字,以便客户端可以将其保存在数据库中
- 监听套接字,这样当客户端发送一些命令时,它就可以执行它并将响应发送回客户端
package main
import (
"net"
"os"
"sync"
"time"
)
const socketName string = "./test_socket"
// create to the socket and launch the accept client routine
func launchServerUDS(ch chan []byte) {
if err := os.RemoveAll(socketName); err != nil {
return
}
l, err := net.Listen("unix", socketName)
if err != nil {
return
}
go acceptConnectionRoutine(l, ch)
}
// accept incoming connection on the socket and
// 1) launch the routine to handle commands from the client
// 2) launch the routine to send data when the server reads from the sensors
func acceptConnectionRoutine(l net.Listener, ch chan []byte) {
defer l.Close()
for {
conn, err := l.Accept()
if err != nil {
return
}
go commandsHandlerRoutine(conn, ch)
go autoSendRoutine(conn, ch)
}
}
// routine that sends data to the client
func autoSendRoutine(c net.Conn, ch chan []byte) {
for {
data := <-ch
if string(data) == "exit" {
return
}
c.Write(data)
}
}
// handle client connection and calls functions to execute commands
func commandsHandlerRoutine(c net.Conn, ch chan []byte) {
for {
buf := make([]byte, 1024)
n, err := c.Read(buf)
if err != nil {
ch <- []byte("exit")
break
}
// now, for sake of simplicity , only echo commands back to the client
_, err = c.Write(buf[:n])
if err != nil {
ch <- []byte("exit")
break
}
}
}
// write on the channel to the autosend routine so the data are written on the socket
func sendDataToClient(data []byte, ch chan []byte) {
select {
case ch <- data:
// if i put a little sleep here, no problems
// i i remove the sleep, only data1 is sent to the client
// time.Sleep(1 * time.Millisecond)
default:
}
}
func dummyReadDataRoutine(ch chan []byte) {
for {
// read data from the sensors every 5 seconds
time.Sleep(5 * time.Second)
// read first data and send it
sendDataToClient([]byte("dummy data1\n"), ch)
// read second data and send it
sendDataToClient([]byte("dummy data2\n"), ch)
// read third data and send it
sendDataToClient([]byte("dummy data3\n"), ch)
}
}
func main() {
ch := make(chan []byte)
wg := sync.WaitGroup{}
wg.Add(2)
go dummyReadDataRoutine(ch)
go launchServerUDS(ch)
wg.Wait()
}
主程序包
进口(
“净额”
“操作系统”
“同步”
“时间”
)
const socketName string=“./test_socket”
//创建套接字并启动接受客户端例程
func launchServerUDS(ch chan[]字节){
如果错误:=os.RemoveAll(socketName);错误!=nil{
返回
}
l、 err:=net.Listen(“unix”,socketName)
如果错误!=零{
返回
}
go AcceptConnection例行程序(l、ch)
}
//接受套接字上的传入连接,然后
//1)启动例程以处理来自客户端的命令
//2)当服务器从传感器读取数据时,启动例程发送数据
func acceptConnectionRoutine(l net.Listener,ch chan[]字节){
延迟l.关闭()
为了{
conn,err:=l.Accept()
如果错误!=零{
返回
}
go commandsHandlerRoutine(康涅狄格州,ch)
自动结束例行程序(连接,通道)
}
}
//向客户端发送数据的例程
func自动结束例程(c网络连接,通道[]字节){
为了{
资料:=JimB给出了一个很好的解释,所以我认为他的答案更好
我在这个答案中包含了我的部分解决方案
我认为我的代码是清晰和简化的,但正如Jim所说,我可以做得更简单和更清晰。我将我的旧代码发布,以便人们能够更好地理解如何发布更简单的代码,而不是像我那样做得一团糟
正如chmike所说,我的问题与我所想的套接字无关,只是与通道有关。在无缓冲通道上写入是问题之一。将无缓冲通道更改为缓冲通道后,问题得到了解决。无论如何,此代码不是“好代码”并且可以按照JimB在回答中所写的原则进行改进
下面是新代码:
package main
import (
"net"
"os"
"sync"
"time"
)
const socketName string = "./test_socket"
// create the socket and accept clients connections
func launchServerUDS(ch chan []byte, wg *sync.WaitGroup) {
defer wg.Done()
if err := os.RemoveAll(socketName); err != nil {
return
}
l, err := net.Listen("unix", socketName)
if err != nil {
return
}
defer l.Close()
for {
conn, err := l.Accept()
if err != nil {
return
}
// this goroutine are launched when a client is connected
// routine that listen and echo commands
go commandsHandlerRoutine(conn, ch)
// routine to send data read from the sensors to the client
go autoSendRoutine(conn, ch)
}
}
// routine that sends data to the client
func autoSendRoutine(c net.Conn, ch chan []byte) {
for {
data := <-ch
if string(data) == "exit" {
return
}
c.Write(data)
}
}
// handle commands received from the client
func commandsHandlerRoutine(c net.Conn, ch chan []byte) {
for {
buf := make([]byte, 1024)
n, err := c.Read(buf)
if err != nil {
// if i can't read send an exit command to autoSendRoutine and exit
ch <- []byte("exit")
break
}
// now, for sake of simplicity , only echo commands back to the client
_, err = c.Write(buf[:n])
if err != nil {
// if i can't write back send an exit command to autoSendRoutine and exit
ch <- []byte("exit")
break
}
}
}
// this goroutine reads from the sensors and write to the channel , so data are sent
// to the client if a client is connected
func dummyReadDataRoutine(ch chan []byte, wg *sync.WaitGroup) {
x := 0
for x < 100 {
// read data from the sensors every 5 seconds
time.Sleep(1 * time.Second)
// read first data and send it
ch <- []byte("data1\n")
// read second data and send it
ch <- []byte("data2\n")
// read third data and send it
ch <- []byte("data3\n")
x++
}
wg.Done()
}
func main() {
// create a BUFFERED CHANNEL
ch := make(chan []byte, 1)
wg := sync.WaitGroup{}
wg.Add(2)
// launch the goruotines that handle the socket connections
// and read data from the sensors
go dummyReadDataRoutine(ch, &wg)
go launchServerUDS(ch, &wg)
wg.Wait()
}
主程序包
进口(
“净额”
“操作系统”
“同步”
“时间”
)
const socketName string=“./test_socket”
//创建套接字并接受客户端连接
func launchServerUDS(ch chan[]字节,wg*sync.WaitGroup){
推迟工作组完成()
如果错误:=os.RemoveAll(socketName);错误!=nil{
返回
}
l、 err:=net.Listen(“unix”,socketName)
如果错误!=零{
返回
}
延迟l.关闭()
为了{
conn,err:=l.Accept()
如果错误!=零{
返回
}
//此goroutine在连接客户端时启动
//侦听和回显命令的例程
go commandsHandlerRoutine(康涅狄格州,ch)
//将从传感器读取的数据发送到客户端的例程
自动结束例行程序(连接,通道)
}
}
//向客户端发送数据的例程
func自动结束例程(c网络连接,通道[]字节){
为了{
资料:=JimB给出了一个很好的解释,所以我认为他的答案更好
我在这个答案中包含了我的部分解决方案
我认为我的代码是清晰和简化的,但正如Jim所说,我可以做得更简单和更清晰。我将我的旧代码发布,以便人们能够更好地理解如何发布更简单的代码,而不是像我那样做得一团糟
正如chmike所说,我的问题与我所想的套接字无关,只是与通道有关。在无缓冲通道上写入是问题之一。将无缓冲通道更改为缓冲通道后,问题得到了解决。无论如何,此代码不是“好代码”并且可以按照JimB在回答中所写的原则进行改进
下面是新代码:
package main
import (
"net"
"os"
"sync"
"time"
)
const socketName string = "./test_socket"
// create the socket and accept clients connections
func launchServerUDS(ch chan []byte, wg *sync.WaitGroup) {
defer wg.Done()
if err := os.RemoveAll(socketName); err != nil {
return
}
l, err := net.Listen("unix", socketName)
if err != nil {
return
}
defer l.Close()
for {
conn, err := l.Accept()
if err != nil {
return
}
// this goroutine are launched when a client is connected
// routine that listen and echo commands
go commandsHandlerRoutine(conn, ch)
// routine to send data read from the sensors to the client
go autoSendRoutine(conn, ch)
}
}
// routine that sends data to the client
func autoSendRoutine(c net.Conn, ch chan []byte) {
for {
data := <-ch
if string(data) == "exit" {
return
}
c.Write(data)
}
}
// handle commands received from the client
func commandsHandlerRoutine(c net.Conn, ch chan []byte) {
for {
buf := make([]byte, 1024)
n, err := c.Read(buf)
if err != nil {
// if i can't read send an exit command to autoSendRoutine and exit
ch <- []byte("exit")
break
}
// now, for sake of simplicity , only echo commands back to the client
_, err = c.Write(buf[:n])
if err != nil {
// if i can't write back send an exit command to autoSendRoutine and exit
ch <- []byte("exit")
break
}
}
}
// this goroutine reads from the sensors and write to the channel , so data are sent
// to the client if a client is connected
func dummyReadDataRoutine(ch chan []byte, wg *sync.WaitGroup) {
x := 0
for x < 100 {
// read data from the sensors every 5 seconds
time.Sleep(1 * time.Second)
// read first data and send it
ch <- []byte("data1\n")
// read second data and send it
ch <- []byte("data2\n")
// read third data and send it
ch <- []byte("data3\n")
x++
}
wg.Done()
}
func main() {
// create a BUFFERED CHANNEL
ch := make(chan []byte, 1)
wg := sync.WaitGroup{}
wg.Add(2)
// launch the goruotines that handle the socket connections
// and read data from the sensors
go dummyReadDataRoutine(ch, &wg)
go launchServerUDS(ch, &wg)
wg.Wait()
}
主程序包
进口(
“净额”
“操作系统”
“同步”
“时间”
)
const socketName string=“./test_socket”
//创建套接字并接受客户端连接
func launchServerUDS(ch chan[]字节,wg*sync.WaitGroup){
推迟工作组完成()
如果错误:=os.RemoveAll(socketName);错误!=nil{
返回
}
l、 err:=net.Listen(“unix”,socketName)
如果错误!=零{
返回
}
延迟l.关闭()
为了{
conn,err:=l.Accept()
如果错误!=零{
返回
}
//此goroutine在连接客户端时启动
//侦听和回显命令的例程
go commandsHandlerRoutine(康涅狄格州,ch)
//将从传感器读取的数据发送到客户端的例程
自动结束例行程序(连接,通道)
}
}
//向客户端发送数据的例程
func自动结束例程(c网络连接,通道[]字节){
为了{
数据:=主要问题在于功能:
func sendDataToClient(data []byte, ch chan []byte) {
select {
case ch <- data:
// if I put a little sleep here, no problems
// if I remove the sleep, only data1 is sent to the client
// time.Sleep(1 * time.Millisecond)
default:
}
您还应该小心地在通道上传递切片,因为很容易忘记哪个逻辑进程拥有所有权,并将修改备份阵列