func (self *Client) chgESTABLISHED(pb *pushproto.Talk) { fun := "Client.chgESTABLISHED" self.state_lock.Lock() defer self.state_lock.Unlock() if self.state == State_ESTABLISHED { // 已经建立了连接,当前状态是ESTABLISHED,可能是客户端没有收到synack // 重新回执synack slog.Warnf("%s client:%s is already:%s", fun, self, State_ESTABLISHED) self.sendSYNACK(self.client_id) return } appid := pb.GetAppid() installid := pb.GetInstallid() sec := "9b0319bc5c05055283cee2533abab270" h := sha1.Sum([]byte(appid + installid + sec)) self.client_id = fmt.Sprintf("%x", h) old_state := self.state self.state = State_ESTABLISHED slog.Infof("%s change client:%s %s:%s", fun, self, old_state, self.state) self.sendSYNACK(self.client_id) self.manager.addClient(self) }
func (self *Client) dochgCLOSED(isRmManager bool) { fun := "Client.dochgCLOSED" self.state_lock.Lock() defer self.state_lock.Unlock() if self.state == State_CLOSED { slog.Warnf("%s client:%s is already:%s", fun, self, State_CLOSED) return } if isRmManager && self.state == State_ESTABLISHED { self.manager.delClient(self.client_id, self.remoteaddr) } if err := self.conn.Close(); err != nil { slog.Warnf("%s client:%s Close net.Conn err: %s", fun, self, err) } for k, v := range self.bussmsg { select { case v <- false: default: slog.Warnf("%s client:%s msgid:%d no wait notify", fun, self, k) } } old_state := self.state self.state = State_CLOSED slog.Infof("%s change client:%s %s:%s", fun, self, old_state, self.state) }
func (self *ConnectionManager) Loop(addr string) { fun := "ConnectionManager.Loop" tcpAddr, error := net.ResolveTCPAddr("tcp", addr) if error != nil { slog.Fatalf("%s Error: Could not resolve address %s", fun, error) panic("resolve address") } netListen, error := net.Listen(tcpAddr.Network(), tcpAddr.String()) if error != nil { slog.Fatalf("%s Error: Could not Listen %s", fun, error) panic("listen address") } defer netListen.Close() //go self.req() //go self.trans() for { slog.Infof("%s Waiting for clients", fun) connection, error := netListen.Accept() if error != nil { slog.Warnf("%s Client error: ", fun, error) } else { NewClient(self, connection) } } }
func (self *Client) SendBussiness(ziptype int32, datatype int32, data []byte) (uint64, string) { fun := "Client.SendBussiness" msgid, err := self.manager.Msgid() if err != nil { slog.Errorf("%s get msgid error:%s", fun, err) return 0, self.remoteaddr } buss := &pushproto.Talk{ Type: pushproto.Talk_BUSSINESS.Enum(), Msgid: proto.Uint64(msgid), Ziptype: proto.Int32(ziptype), Datatype: proto.Int32(datatype), Bussdata: data, } spb, err := proto.Marshal(buss) if err != nil { slog.Errorf("%s marshaling error: ", fun, err) return 0, self.remoteaddr } p := util.Packdata(spb) self.sendBussRetry(msgid, p) slog.Infof("%s client:%s send msgid:%d", fun, self, msgid) self.Send(p) return msgid, self.remoteaddr }
func (self *Client) sendBussRetry(msgid uint64, pb []byte) { fun := "Client.sendBussRetry" ack_notify := make(chan bool) self.addBussmsg(msgid, ack_notify) retry_intv := 2 retry_time := 3 go func() { defer self.rmBussmsg(msgid) for i := 1; i <= retry_time+1; i++ { select { case v := <-ack_notify: if v { slog.Infof("%s client:%s recv ack msgid:%d", fun, self, msgid) } else { slog.Infof("%s client:%s close not recv ack msgid:%d", fun, self, msgid) } return case <-time.After(time.Second * time.Duration(retry_intv)): if i <= retry_time { slog.Infof("%s client:%s retry msgid:%d times:%d", fun, self, msgid, i) self.Send(pb) } else { // 最后一次发送已经超时 slog.Infof("%s client:%s send timeout msgid:%d", fun, self, msgid) // 断开连接 self.chgCLOSED() return } } retry_intv = retry_intv << 1 } }() }
func (self *ConnectionManager) addClient(cli *Client) { fun := "ConnectionManager.addClient" client_id := cli.client_id if v, ok := self.clients[client_id]; ok { v.errNotifyCLOSED("dup client add client") delete(self.clients, client_id) slog.Warnf("%s dup client add client_id %s", fun, client_id) } self.clients[client_id] = cli slog.Infof("%s Add %s %d", fun, cli, len(self.clients)) }
// Method: POST // Uri: /push/CLIENT_ID/ZIPTYPE/DATATYPE // Data: push data func push(w http.ResponseWriter, r *http.Request) { fun := "rest.push" //debug_show_request(r) if r.Method != "POST" { writeRestErr(w, "method err") return } slog.Infof("%s %s", fun, r.URL.Path) path := strings.Split(r.URL.Path, "/") //slog.Info("%q", path) if len(path) != 5 { writeRestErr(w, "uri err") return } // path[0] "", path[1] push clientid := path[2] ziptype, err := strconv.Atoi(path[3]) if err != nil { writeRestErr(w, "ziptype err") return } datatype, err := strconv.Atoi(path[4]) if err != nil { writeRestErr(w, "datatype err") return } data, err := ioutil.ReadAll(r.Body) if err != nil { writeRestErr(w, "data err") return } if len(data) == 0 { writeRestErr(w, "data empty") return } msgid, link := connman.Send(clientid, int32(ziptype), int32(datatype), data) slog.Debugf("%s msgid:%d link:%s", fun, msgid, link) js, _ := json.Marshal(&RestReturn{Code: 0, Msgid: msgid, Link: link}) fmt.Fprintf(w, "%s", js) }
func (self *ConnectionManager) delClient(client_id string, addr string) { fun := "ConnectionManager.delClient" if v, ok := self.clients[client_id]; ok { if v.remoteaddr == addr { delete(self.clients, client_id) slog.Infof("%s Remove %s %d", fun, v, len(self.clients)) } else { slog.Warnf("%s delete client %s not same %s", fun, v, addr) } } else { slog.Warnf("%s delete client_id %s not fond", fun, client_id) } }
func main() { cfg := config{ServId: 0, HttpServ: ":9091", ConnServ: ":9989"} js, _ := json.Marshal(&cfg) slog.Init(os.Stdout) slog.Infof("%s", js) conn_man := connection.NewConnectionManager() httpport := ":9091" connection.StartHttp(conn_man, httpport) service := ":9989" conn_man.Loop(service) }
// goroutine func (self *Client) sendData(s []byte, isclose bool) { fun := "Client.sendData" //slog.Debug("sendData %s %d", s, isclose) self.send_lock.Lock() defer self.send_lock.Unlock() self.conn.SetWriteDeadline(time.Now().Add(time.Duration(5) * time.Second)) a, err := self.conn.Write(s) slog.Infof("%s client:%s Send Write rv %d", fun, self, a) if err != nil { slog.Warnf("%s client:%s write error:%s ", fun, self, err) self.chgCLOSED() return } if isclose { self.chgCLOSED() } }
func (self *Client) chgCLOSED2TCP_READY(c net.Conn) { fun := "Client.chgCLOSED2TCP_READY" self.state_lock.Lock() defer self.state_lock.Unlock() if self.state == State_TCP_READY { slog.Warnf("%s client:%s is already:%s", fun, self, State_TCP_READY) return } self.client_id = "NULL" self.conn = c self.remoteaddr = c.RemoteAddr().String() self.bussmsg = make(map[uint64]chan bool) old_state := self.state self.state = State_TCP_READY slog.Infof("%s change client:%s %s:%s", fun, self, old_state, self.state) go self.Recv() }
// goroutine func (self *Client) Recv() { fun := "Client.Recv" buffer := make([]byte, 2048) packBuff := make([]byte, 0) var bufLen uint64 = 0 conn := self.conn errmsg := "" defer self.deferErrNotifyCLOSED(&errmsg) for { conn.SetReadDeadline(time.Now().Add(time.Duration(60*10) * time.Second)) bytesRead, error := conn.Read(buffer) if error != nil { slog.Infof("%s client:%s conn error: %s", fun, self, error) return } packBuff = append(packBuff, buffer[:bytesRead]...) bufLen += uint64(bytesRead) slog.Infof("%s client:%s Recv: %d %d %d", fun, self, bytesRead, packBuff, bufLen) for { if bufLen > 0 { pacLen, sz := binary.Uvarint(packBuff[:bufLen]) if sz < 0 { slog.Warnf("%s client:%s package head error:%s", fun, self, packBuff[:bufLen]) return } else if sz == 0 { break } slog.Debugf("%s pacLen %d", fun, pacLen) // must < 5K if pacLen > 1024*5 { slog.Warnf("%s client:%s package too long error:%s", fun, self, packBuff[:bufLen]) errmsg = "package too long" return } else if pacLen == 0 { errmsg = "package len 0" return } apacLen := uint64(sz) + pacLen + 1 if bufLen >= apacLen { pad := packBuff[apacLen-1] if pad != 0 { slog.Warnf("%s client:%s package pad error:%s", fun, self, packBuff[:bufLen]) errmsg = "package pad error" return } self.proto(packBuff[sz : apacLen-1]) packBuff = packBuff[apacLen:] bufLen -= apacLen } else { break } } else { break } } } }