Beispiel #1
0
// NewClientWithConnection returns a new Client to handle requests to the
// set of services at the other end of the connection.
// An existing connection in the form of a zmq socket together with the zmq
// context they were created with is used
func NewClientWithConnection(ctx *zmq.Context, conn *zmq.Socket) *Client {
	// A router socket is the middle-man between client requests and actually sending/receiving on the wire
	router, err := ctx.NewSocket(zmq.ROUTER)
	if err != nil {
		glog.Fatal(err)
	}
	if err := router.Bind(RouterURL); err != nil {
		glog.Fatal(err)
	}

	client := &Client{
		conn: conn,
		endpoints: endpoints{
			socket: conn,
		},
		router: router,
		ctx:    ctx,
	}

	// Start the proxy in an own routine since it is blocking
	go func() {
		if err := zmq.Proxy(conn, router, nil); err != nil {
			switch zmq.AsErrno(err) {
			case zmq.Errno(zmq.ETERM):
				glog.Info(err)
			case zmq.Errno(syscall.EINTR):
				glog.Info(err)
			default:
				glog.Info(zmq.AsErrno(err))
				glog.Info(err)
			}
			client.Close()
		}
	}()

	// Socket monitor for connect event
	monitorURL := "inproc://monitor"
	if err := conn.Monitor(monitorURL, zmq.EVENT_CONNECTED|zmq.EVENT_DISCONNECTED); err != nil {
		client.Close()
		glog.Fatal(err)
	}
	go client.monitor(monitorURL)

	return client
}
/******************************************************************************
* 概述:    订阅退订
* 函数名:    dealCmd
* 返回值:
* 参数列表:  参数名          参数类型      取值范围     描述
*
*******************************************************************************/
func (this *ZmqSocket) dealCmd(cmdSocket *zmq4.Socket) (int, error) {
	log4.Debug("start deal cmd...")
	for { //半包处理
		cmdsStr, err0 := cmdSocket.Recv(zmq4.DONTWAIT)

		if err0 != nil {
			errno1 := zmq4.AsErrno(err0)
			switch errno1 {
			case zmq4.Errno(syscall.EAGAIN):
				return 0, nil
			case zmq4.Errno(syscall.EINTR):
				continue
			default:
				log4.Debug("zmq req Get err %v, %d!", errno1, errno1)
			}
		}
		if len(cmdsStr) == 0 {
			log4.Debug("deal cmd return")
			return 0, nil
		}
		ss := strings.Split(cmdsStr, " ")
		log4.Debug("recv cmd %s", cmdsStr)
		for i := 0; i < len(ss); i++ {
			if len(ss[i]) == 0 {
				continue
			}
			if ss[i] == "stop" {
				//				log4.Debug("recv cmd will stop %s %s", this.mreqUrl, this.msubUrl)
				cmdSocket.Send("0", 0)
				return 1, nil
			}
			if !this.mChoose {
				//				log4.Debug("recv cmd ,but notChoose so return")
				return 0, nil
			}
			if ss[i][0] == 'r' {
				if err := this.msubSocket.SetSubscribe(ss[i][1:]); err != nil {
					log4.Error("SetSubscribe(%s) falied, %s", ss[i][1:], err.Error())
					return 0, err
				}
				log4.Debug("setSubscribe ok %s", ss[i][1:])
				continue
			}
			if ss[i][0] == 'u' {
				if err := this.msubSocket.SetUnsubscribe(ss[i][1:]); err != nil {
					log4.Error("SetUnSubscribe(%s) falied, %s", ss[i][1:], err.Error())
					return 0, err
				}
				log4.Debug("setUnSubscribe ok %s", ss[i][1:])
				continue
			}
		}
	}
	return 0, nil
}
Beispiel #3
0
func handleGeneralError(err error) {
	switch err {
	case zmq.ErrorSocketClosed, zmq.ErrorContextClosed:
		return
	}

	switch zmq.AsErrno(err) {
	case zmq.ETERM:
		return
	}

	panic(err)
}
Beispiel #4
0
func IsEINTR(err error) bool {
	switch err.(type) {
	case syscall.Errno:
		if err == syscall.EINTR {
			return true
		}
		return false
	case zmq.Errno:
		if zmq.AsErrno(err) == zmq.Errno(syscall.EINTR) {
			return true
		}
		return false
	}
	return false
}
Beispiel #5
0
func handleIOError(err error) bool {
	switch err {
	case zmq.ErrorSocketClosed, zmq.ErrorContextClosed:
		return false
	}

	switch zmq.AsErrno(err) {
	case zmq.Errno(syscall.EAGAIN):
		return true

	case zmq.ETERM:
		return false
	}

	panic(err)
}
/******************************************************************************
* 概述:     Zmq关闭
* 函数名:    Close
* 返回值:
* 参数列表:  参数名          参数类型      取值范围     描述
*
*******************************************************************************/
func (this *Zmq) Close() bool {
	if this.Mcontext != nil {
		if err := this.Mcontext.Term(); err != nil {
			switch zmq4.AsErrno(err) {
			case zmq4.Errno(syscall.EINTR):
				this.Mcontext = nil
				return false
			case zmq4.ETERM:
				this.Mcontext = nil
				return true
			case zmq4.Errno(syscall.EFAULT):
				this.Mcontext = nil
				return true
			}
		}
		this.Mcontext = nil
	}
	log4.Info("conetxt term ok")
	return true
}
Beispiel #7
0
func (client *Client) monitor(addr string) {
	s, err := client.ctx.NewSocket(zmq.PAIR)
	if err != nil {
		glog.Fatal(err)
	}
	defer s.Close()

	if err := s.Connect(addr); err != nil {
		glog.Fatal(err)
	}

	for {
		evtType, addr, _, err := s.RecvEvent(0)
		if err != nil {
			switch zmq.AsErrno(err) {
			case zmq.Errno(zmq.ETERM):
				glog.Info(err)
			case zmq.Errno(syscall.EINTR):
				glog.Info(err)
			default:
				glog.Error(err)
			}
			break
		}

		// Only care about events for our added endpoints
		if end, ok := client.endpoints.get(addr); ok {
			switch evtType {
			case zmq.EVENT_CONNECTED:
				// Flag endpoint as connected
				if !end.alive {
					close(end.connected)
				} else {
					glog.Info("zrpc: reconnected to ", end.address)
				}
			case zmq.EVENT_DISCONNECTED:
				glog.Infof("zrpc: %s disconnected ", end.address)
			}
		}
	}
}
Beispiel #8
0
func main() {
	//  Socket to talk to server
	fmt.Println("Connecting to hello world server...")
	client, _ := zmq.NewSocket(zmq.REQ)
	defer client.Close()
	client.Connect("tcp://localhost:5555")

	// Without signal handling, Go will exit on signal, even if the signal was caught by ZeroMQ
	chSignal := make(chan os.Signal, 1)
	signal.Notify(chSignal, syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM)

LOOP:
	for {
		client.Send("HELLO", 0)
		fmt.Println("Sent: HELLO")
		reply, err := client.Recv(0)
		if err != nil {
			if zmq.AsErrno(err) == zmq.Errno(syscall.EINTR) {
				// signal was caught by 0MQ
				log.Println("Client Recv:", err)
				break
			} else {
				// some error occurred
				log.Panicln(err)
			}
		}

		fmt.Println("Received:", reply)
		time.Sleep(time.Second)

		select {
		case sig := <-chSignal:
			// signal was caught by Go
			log.Println("Signal:", sig)
			break LOOP
		default:
		}
	}
}
/******************************************************************************
* 概述:     事件处理
* 函数名:    dealMonitorEvent
* 返回值:    error
* 参数列表:  参数名          参数类型      取值范围     描述
*            isReq          bool                     是否为req事件
*
*******************************************************************************/
func (this *ZmqSocket) dealMonitorEvent(s *zmq4.Socket, isReq bool) error {
	log4.Debug("start dealMonitorEvent...")
	for {
		a, b, c, err := s.RecvEvent(0)
		//if runtime.GOOS == "windows" && len(b) == 0 && c == 0 {
		//	log4.Debug("monitor eagan windows")
		//	return nil
		//}
		if err != nil {
			errno1 := zmq4.AsErrno(err)
			switch errno1 {
			case zmq4.Errno(syscall.EAGAIN):
				log4.Debug("monitor eagan ")
				return nil
			case zmq4.Errno(syscall.EINTR):
				log4.Debug("monitor EINTR")
				continue
			default:
				log4.Debug("zmq req Get err %v, %d!", errno1, errno1)
			}
		}
		if a == 0 {
			//			log4.Debug("monitor return")
			return nil
		}
		switch a {
		case zmq4.EVENT_CONNECTED:
			log4.Info("sub or req monitor event CONNECTED, url:%s %s", this.mreqUrl, this.mreqUrl)
			this.mchooseMutex.Lock()
			defer this.mchooseMutex.Unlock()
			if isReq {
				this.mreqOK = true
			} else {
				this.msubOK = true
			}
			if this.mstateChFlag && this.mreqOK && this.msubOK {
				this.mstateChFlag = false
				select {
				case this.mstateCh <- true:
				default:
				}
			}
			//			this.mok++
		case zmq4.EVENT_DISCONNECTED:
			log4.Error("sub or req monitor event DISCONNECTED, url:%s %s", this.mreqUrl, this.mreqUrl)
			this.mchooseMutex.Lock()
			defer this.mchooseMutex.Unlock()
			if isReq {
				this.mreqOK = false
			} else {
				this.msubOK = false
			}
			//			this.mok--
			if this.mChoose {
				this.mChoose = false
				topics := this.mzmq.MdataCache.GetSdsTopic()
				for i := 0; i < len(*topics); i++ {
					if err := this.msubSocket.SetUnsubscribe((*topics)[i]); err != nil {
						log4.Error("SetUnSubscribe(%s) falied, %s", (*topics)[i], err.Error())
					}
				}
				this.mzmq.Mevent.UpdateWorkSocket()
			}
		case zmq4.EVENT_CLOSED:
			//			this.mchooseMutex.Lock()
			//			this.mok
			//			if this.mChoose{
			//				this.mChoose = false
			//				this.mevent.UpdateWorkSocket()
			//			log4.Error("sdssdk zmqreq monitor event CLOSED", b, c)
			//			}
			//			this.mchooseMutex.UnLock()
		default:
			log4.Debug("zmqreq monitor unknow event err", a, b, c, err)
		}
	}
	return nil

}
/******************************************************************************
* 概述:    接收处理推送信息
* 函数名:    dealSub
* 返回值:
* 参数列表:  参数名          参数类型      取值范围     描述
*
*******************************************************************************/
func (this *ZmqSocket) dealSub(soc *zmq4.Socket, msgHeadFlag *bool) error {
	//	log4.Debug("start deal sub0...")
	//	this.mchooseMutex.RLocker()
	if !this.mChoose {
		//	this.mchooseMutex.RUnlock()
		return nil
	}
	log4.Debug("start deal sub...")
	//	this.mchooseMutex.RUnlock()
	for {
		if *msgHeadFlag {
			topic, err := soc.Recv(zmq4.DONTWAIT)
			if err != nil {
				errno1 := zmq4.AsErrno(err)
				switch errno1 {
				case zmq4.Errno(syscall.EAGAIN):
					return nil
				case zmq4.Errno(syscall.EINTR):
					continue
				default:
					log4.Debug("zmq req Get err %v, %d!", errno1, errno1)
				}
			}
			if len(topic) == 0 {
				//				log4.Debug("sub return1")
				return nil
			}
			//			log4.Debug("recv sub head =", topic)
			*msgHeadFlag = false
		} else {
			stream, err2 := soc.RecvBytes(zmq4.DONTWAIT)
			if err2 != nil {
				errno1 := zmq4.AsErrno(err2)
				switch errno1 {
				case zmq4.Errno(syscall.EAGAIN):
					return nil
				case zmq4.Errno(syscall.EINTR):
					continue
				default:
					log4.Debug("zmq req Get err %v, %d!", errno1, errno1)
				}
			}
			if len(stream) == 0 {
				//				log4.Debug("sub return2")
				return nil
			}
			*msgHeadFlag = true

			frm, err3 := common.UnwrapBaseProto(stream)
			if err3 != nil {
				log4.Error("UnwrapBaseProto falied, %s", err3.Error())
				return err3
			}

			mid := common.UnOffset(*frm.GetBody().Mid, 4)
			if mid[4-1] == 200 {
				log4.Error("sdssdk zmqsub get mid == 200 err")
				continue
			}
			res, err4 := common.UnwrapResponse(frm.GetBody().Mdata)
			if err4 != nil {
				log4.Error("sdssdk sub UnwrapResponse error:", err4)
				continue
			}
			this.mzmq.MdataCache.UpdatePoints(res)
		}
	}
	return nil
}
Beispiel #11
0
// Start registers a zmq endpoint at passed address answering requests for registered services
func (server *Server) Start(addr string) {
	// Don't use the global context to avoid package level confusion
	ctx, err := zmq.NewContext()
	if err != nil {
		glog.Fatal(err)
	}
	// A router socket handles the actual connection
	sock, _ := ctx.NewSocket(zmq.ROUTER)
	server.conn = sock

	// If no prefix is passed, default to tcp
	if !strings.HasPrefix(addr, "tcp://") {
		addr = "tcp://" + addr
	}
	server.conn.Bind(addr)
	glog.Info("Server listening on ", addr)

	// Socket monitor
	monitorURL := "inproc://monitor"
	if err := server.conn.Monitor(monitorURL, zmq.EVENT_ACCEPTED|zmq.EVENT_DISCONNECTED); err != nil {
		glog.Fatal(err)
	}
	go server.monitor(ctx, monitorURL)

	// A dealer socket multiplexes requests to workers
	mux, _ := ctx.NewSocket(zmq.DEALER)
	defer mux.Close()
	mux.Bind("inproc://mux")

	// Start backing worker processes
	for i := 0; i < server.numWorkers; i++ {
		go func(i int) {
			worker, _ := ctx.NewSocket(zmq.REP)
			defer worker.Close()
			worker.Connect("inproc://mux")
			glog.V(2).Infof("Started worker #%d", i)

			for {
				if server.closing {
					glog.Warning(ErrShutdown)
					break
				}
				reqBytes, err := worker.RecvBytes(0)
				if err != nil {
					switch zmq.AsErrno(err) {
					// If was interrupted there is no need to log as an error
					case zmq.Errno(zmq.ETERM):
						glog.Info(err)
					default:
						// Error receiving is usually fatal
						glog.Error(err)
					}
					break
				}

				// Decode the request envelope
				req := &Request{}
				if err := proto.Unmarshal(reqBytes, req); err != nil {
					glog.Error(err)
					sendError(worker, nil, err)
					continue
				}

				// Make sure it's not expired on arrival
				if req.Expires != nil {
					if time.Unix(*req.Expires, 0).Before(time.Now()) {
						glog.Infof("discarding expired message: '%s'", req.UUID)
						sendError(worker, req, NewExpiredError("message expired on arrival"))
						continue
					}
				}

				serviceName := path.Dir(strings.TrimPrefix(req.GetPath(), "zrpc://"))
				methodName := path.Base(req.GetPath())

				// Make sure a handler for this request exists
				server.mu.RLock()
				service, ok := server.serviceMap[serviceName]
				server.mu.RUnlock()
				if !ok {
					err := fmt.Sprintf("service '%s' is not served", serviceName)
					if serviceName == "." {
						err = "no service name passed"
					}
					glog.Warning(err)
					sendError(worker, req, errors.New(err))
					continue
				}

				// Make sure the message is registered for this server
				if mType, ok := service.method[methodName]; ok {
					// Decode the incoming request message
					var argv reflect.Value
					argIsValue := false // if true, need to indirect before calling.
					if mType.ArgType.Kind() == reflect.Ptr {
						argv = reflect.New(mType.ArgType.Elem())
					} else {
						argv = reflect.New(mType.ArgType)
						argIsValue = true
					}

					// argv guaranteed to be a pointer now.
					if err := proto.Unmarshal(req.Payload, argv.Interface().(proto.Message)); err != nil {
						glog.Error(err)
						sendError(worker, req, err)
						continue
					}

					if argIsValue {
						argv = reflect.Indirect(argv)
					}

					glog.V(3).Infof("Received '%s' (%s)", argv.Type().Elem(), req.UUID)

					// Invoke the method, providing a new value for the reply (if expected)
					var (
						returnValues []reflect.Value
						replyv       reflect.Value
					)
					if mType.ReplyType != nil {
						replyv = reflect.New(mType.ReplyType.Elem())
						returnValues = mType.method.Func.Call([]reflect.Value{service.rcvr, argv, replyv})
					} else {
						returnValues = mType.method.Func.Call([]reflect.Value{service.rcvr, argv})
					}
					// The return value for the method is an error.
					errInter := returnValues[0].Interface()
					if errInter != nil {
						err := errInter.(error)
						sendError(worker, req, err)
						continue
					}

					// Envelope the response message
					envelope := &Response{
						Path: req.Path,
						UUID: req.UUID,
					}

					// Marshal the response message (if exists)
					if mType.ReplyType != nil {
						replyBytes, err := proto.Marshal(replyv.Interface().(proto.Message))
						if err != nil {
							glog.Error(err)
							sendError(worker, req, err)
							continue
						}
						envelope.Payload = replyBytes
					}

					// Marshal the envelope
					envBytes, err := proto.Marshal(envelope)
					if err != nil {
						glog.Error(err)
						sendError(worker, req, err)
						continue
					}

					// Send the response
					if _, err := worker.SendBytes(envBytes, 0); err != nil {
						// Since we could not send, we could not send an error either, just log
						glog.Error(err)
					}
					if mType.ReplyType != nil {
						glog.V(3).Infof("Replied '%s' (%s)", mType.ReplyType.Elem(), envelope.UUID)
					} else {
						glog.V(3).Infof("Replied nil (%s)", envelope.UUID)
					}
				} else {
					// If reached here, the message was not handled by the server
					glog.V(1).Infof("message '%s' is not handled by this service", methodName)
					sendError(worker, req, fmt.Errorf("message '%s' is not handled by this service", methodName))
				}
			}

			glog.Infof("Closing worker #%d", i)
		}(i + 1)
	}

	// This is blocking so we put it last
	if err := zmq.Proxy(sock, mux, nil); err != nil {
		switch zmq.AsErrno(err) {
		// If was interrupted there is no need to log as an error
		case zmq.Errno(syscall.EINTR):
			glog.Info(err)
		case zmq.Errno(zmq.ETERM):
			glog.Info(err)
		default:
			glog.Error(err)
		}
	}

	// Since it was blocking we could safely close the server if reached here
	server.Close()
}