github.com/zhongdalu/gf@v1.0.0/g/os/gproc/gproc_comm_receive.go (about)

     1  // Copyright 2018 gf Author(https://github.com/zhongdalu/gf). 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/zhongdalu/gf.
     6  
     7  // "不要通过共享内存来通信,而应该通过通信来共享内存"
     8  
     9  package gproc
    10  
    11  import (
    12  	"encoding/json"
    13  	"fmt"
    14  	"github.com/zhongdalu/gf/g/container/gqueue"
    15  	"github.com/zhongdalu/gf/g/container/gtype"
    16  	"github.com/zhongdalu/gf/g/net/gtcp"
    17  	"github.com/zhongdalu/gf/g/os/gfile"
    18  	"github.com/zhongdalu/gf/g/os/glog"
    19  	"github.com/zhongdalu/gf/g/util/gconv"
    20  	"net"
    21  )
    22  
    23  const (
    24  	gPROC_DEFAULT_TCP_PORT     = 10000 // 默认开始监听的TCP端口号,如果占用则递增
    25  	gPROC_MSG_QUEUE_MAX_LENGTH = 10000 // 进程消息队列最大长度(每个分组)
    26  )
    27  
    28  var (
    29  	// 是否已开启TCP端口监听服务
    30  	tcpListened = gtype.NewBool()
    31  )
    32  
    33  // 获取其他进程传递到当前进程的消息包,阻塞执行。
    34  // 进程只有在执行该方法后才会打开请求端口,默认情况下不允许进程间通信。
    35  func Receive(group ...string) *Msg {
    36  	// 一个进程只能开启一个监听goroutine
    37  	if !tcpListened.Val() && tcpListened.Set(true) == false {
    38  		go startTcpListening()
    39  	}
    40  	queue := (*gqueue.Queue)(nil)
    41  	groupName := gPROC_COMM_DEAFULT_GRUOP_NAME
    42  	if len(group) > 0 {
    43  		groupName = group[0]
    44  	}
    45  	if v := commReceiveQueues.Get(groupName); v == nil {
    46  		commReceiveQueues.LockFunc(func(m map[string]interface{}) {
    47  			if v, ok := m[groupName]; ok {
    48  				queue = v.(*gqueue.Queue)
    49  			} else {
    50  				queue = gqueue.New(gPROC_MSG_QUEUE_MAX_LENGTH)
    51  				m[groupName] = queue
    52  			}
    53  		})
    54  	} else {
    55  		queue = v.(*gqueue.Queue)
    56  	}
    57  
    58  	if v := queue.Pop(); v != nil {
    59  		return v.(*Msg)
    60  	}
    61  	return nil
    62  }
    63  
    64  // 创建本地进程TCP通信服务
    65  func startTcpListening() {
    66  	var listen *net.TCPListener
    67  	for i := gPROC_DEFAULT_TCP_PORT; ; i++ {
    68  		addr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("127.0.0.1:%d", i))
    69  		if err != nil {
    70  			continue
    71  		}
    72  		listen, err = net.ListenTCP("tcp", addr)
    73  		if err != nil {
    74  			continue
    75  		}
    76  		// 将监听的端口保存到通信文件中(字符串类型存放)
    77  		if err := gfile.PutContents(getCommFilePath(Pid()), gconv.String(i)); err != nil {
    78  			glog.Error(err)
    79  		}
    80  		break
    81  	}
    82  	for {
    83  		if conn, err := listen.Accept(); err != nil {
    84  			glog.Error(err)
    85  		} else if conn != nil {
    86  			go tcpServiceHandler(gtcp.NewConnByNetConn(conn))
    87  		}
    88  	}
    89  }
    90  
    91  // TCP数据通信处理回调函数
    92  func tcpServiceHandler(conn *gtcp.Conn) {
    93  	option := gtcp.PkgOption{
    94  		Retry: gtcp.Retry{
    95  			Count:    3,
    96  			Interval: 10,
    97  		},
    98  	}
    99  	for {
   100  		var result []byte
   101  		buffer, err := conn.RecvPkg(option)
   102  		if len(buffer) > 0 {
   103  			msg := new(Msg)
   104  			if err := json.Unmarshal(buffer, msg); err != nil {
   105  				glog.Error(err)
   106  				continue
   107  			}
   108  			if v := commReceiveQueues.Get(msg.Group); v == nil {
   109  				result = []byte(fmt.Sprintf("group [%s] does not exist", msg.Group))
   110  				break
   111  			} else {
   112  				result = []byte("ok")
   113  				if v := commReceiveQueues.Get(msg.Group); v != nil {
   114  					v.(*gqueue.Queue).Push(msg)
   115  				}
   116  			}
   117  		}
   118  		if err == nil {
   119  			if err := conn.SendPkg(result, option); err != nil {
   120  				glog.Error(err)
   121  			}
   122  		} else {
   123  			if err := conn.Close(); err != nil {
   124  				glog.Error(err)
   125  			}
   126  			return
   127  		}
   128  	}
   129  }