github.com/gogf/gf/v2@v2.7.4/os/gproc/gproc_comm_receive.go (about) 1 // Copyright GoFrame Author(https://goframe.org). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/gogf/gf. 6 7 package gproc 8 9 import ( 10 "context" 11 "fmt" 12 "net" 13 14 "github.com/gogf/gf/v2/container/gqueue" 15 "github.com/gogf/gf/v2/container/gtype" 16 "github.com/gogf/gf/v2/errors/gerror" 17 "github.com/gogf/gf/v2/internal/json" 18 "github.com/gogf/gf/v2/net/gtcp" 19 "github.com/gogf/gf/v2/os/gfile" 20 "github.com/gogf/gf/v2/os/glog" 21 "github.com/gogf/gf/v2/util/gconv" 22 ) 23 24 var ( 25 // tcpListened marks whether the receiving listening service started. 26 tcpListened = gtype.NewBool() 27 ) 28 29 // Receive blocks and receives message from other process using local TCP listening. 30 // Note that, it only enables the TCP listening service when this function called. 31 func Receive(group ...string) *MsgRequest { 32 // Use atomic operations to guarantee only one receiver goroutine listening. 33 if tcpListened.Cas(false, true) { 34 go receiveTcpListening() 35 } 36 var groupName string 37 if len(group) > 0 { 38 groupName = group[0] 39 } else { 40 groupName = defaultGroupNameForProcComm 41 } 42 queue := commReceiveQueues.GetOrSetFuncLock(groupName, func() interface{} { 43 return gqueue.New(maxLengthForProcMsgQueue) 44 }).(*gqueue.Queue) 45 46 // Blocking receiving. 47 if v := queue.Pop(); v != nil { 48 return v.(*MsgRequest) 49 } 50 return nil 51 } 52 53 // receiveTcpListening scans local for available port and starts listening. 54 func receiveTcpListening() { 55 var ( 56 listen *net.TCPListener 57 conn net.Conn 58 port = gtcp.MustGetFreePort() 59 address = fmt.Sprintf("127.0.0.1:%d", port) 60 ) 61 tcpAddress, err := net.ResolveTCPAddr("tcp", address) 62 if err != nil { 63 panic(gerror.Wrap(err, `net.ResolveTCPAddr failed`)) 64 } 65 listen, err = net.ListenTCP("tcp", tcpAddress) 66 if err != nil { 67 panic(gerror.Wrapf(err, `net.ListenTCP failed for address "%s"`, address)) 68 } 69 // Save the port to the pid file. 70 if err = gfile.PutContents(getCommFilePath(Pid()), gconv.String(port)); err != nil { 71 panic(err) 72 } 73 // Start listening. 74 for { 75 if conn, err = listen.Accept(); err != nil { 76 glog.Error(context.TODO(), err) 77 } else if conn != nil { 78 go receiveTcpHandler(gtcp.NewConnByNetConn(conn)) 79 } 80 } 81 } 82 83 // receiveTcpHandler is the connection handler for receiving data. 84 func receiveTcpHandler(conn *gtcp.Conn) { 85 var ( 86 ctx = context.TODO() 87 result []byte 88 response MsgResponse 89 ) 90 for { 91 response.Code = 0 92 response.Message = "" 93 response.Data = nil 94 buffer, err := conn.RecvPkg() 95 if len(buffer) > 0 { 96 // Package decoding. 97 msg := new(MsgRequest) 98 if err = json.UnmarshalUseNumber(buffer, msg); err != nil { 99 continue 100 } 101 if msg.ReceiverPid != Pid() { 102 // Not mine package. 103 response.Message = fmt.Sprintf( 104 "receiver pid not match, target: %d, current: %d", 105 msg.ReceiverPid, Pid(), 106 ) 107 } else if v := commReceiveQueues.Get(msg.Group); v == nil { 108 // Group check. 109 response.Message = fmt.Sprintf("group [%s] does not exist", msg.Group) 110 } else { 111 // Push to buffer queue. 112 response.Code = 1 113 v.(*gqueue.Queue).Push(msg) 114 } 115 } else { 116 // Empty package. 117 response.Message = "empty package" 118 } 119 if err == nil { 120 result, err = json.Marshal(response) 121 if err != nil { 122 glog.Error(ctx, err) 123 } 124 if err = conn.SendPkg(result); err != nil { 125 glog.Error(ctx, err) 126 } 127 } else { 128 // Just close the connection if any error occurs. 129 if err = conn.Close(); err != nil { 130 glog.Error(ctx, err) 131 } 132 break 133 } 134 } 135 }