Server code analysis of Go mass chat room project

Keywords: Programming JSON Database Redis Go

The whole project uses MVC mode, CS architecture, transmission layer based on TCP protocol, application layer based on custom protocol, and developed with Go language. The project has strong expansibility.

Server master function

func main() {
	initPool("localhost:6379", 16, 0, 300*time.Second)
	initUserDao()
	fmt.Println("The server listens on the new 8889 port....")
	listen, err := net.Listen("tcp", "0.0.0.0:8889")
	defer listen.Close()
	if err != nil {
		fmt.Println("net.Listen err=", err)
		return
	}
	for {
		fmt.Println("Wait for client to link server.....")
		conn, err := listen.Accept()
		if err != nil {
			fmt.Println("listen.Accepe err=", err)
		}
		go process(conn)
	}

}

The main function initializes the database connection pool and the module UserDao, which deals with the interaction with the database.

func process(conn net.Conn) {
	defer conn.Close()

	processor := &Processor{
		Conn: conn,
	}
	processor.process2()
}

func initUserDao() {
	model.MyUserDao = model.NewUserDao(pool)
}

Each client corresponds to a process, and each process executes the process function.

Process establishes a processor function for each client to process business logic

func (this *Processor) process2() {
	for {
		tf := &utils.Transfer{
			Conn: this.Conn,
		}
		mes, err := tf.ReadPkg()
		if err != nil {
			if err == io.EOF {
				fmt.Println("process2()Error in")
				fmt.Println("Client exit, The server also exits..")
				return
			} else {
				fmt.Println("process2()Error in")
				fmt.Println("readPkg err=", err)
				return
			}
		}
		fmt.Println("mes=", mes)
		err = this.serverProcessMes(&mes)
		if err != nil {
			fmt.Println("serverProcessMes err")
			return
		}
	}
}

Then we can see that there are currently two server modules: login and registration.

func (this *Processor) serverProcessMes(mes *message.Message) (err error) {
	switch mes.Type {
	case message.LoginMesType:
		// Handling landing
		up := &process2.UserProcess{
			Conn: this.Conn,
		}
		err = up.ServerProcessLogin(mes)
	case message.RegisterMesType:
		// Processing registration
		up := &process2.UserProcess{
			Conn: this.Conn,
		}
		err = up.ServerProcessRegister(mes)
	default:
		fmt.Println("Message type does not exist, Unable to deal with...")
	}
	return
}

These two are processed through the UserProcess module.

There are functions to handle login and registration in UserProcess

Handling registered functions

func (this *UserProcess) ServerProcessRegister(mes *message.Message) (err error) {

	var registerMes message.RegisterMes
	err = json.Unmarshal([]byte(mes.Data), &registerMes)
	if err != nil {
		fmt.Println("json.Unmarshall fail err=", err)
		return
	}

	// A resMes
	var resMes message.Message
	resMes.Type = message.RegisterResMesType
	var registerResMes message.RegisterResMes
	err = model.MyUserDao.Register(&registerMes.User)
	if err != nil {
		if err == model.ERROR_USER_EXISTS {
			registerResMes.Code = 505
			registerResMes.Error = err.Error()
		} else {
			registerResMes.Code = 506
			registerResMes.Error = "Unknown error registering"
		}
	} else {
		registerResMes.Code = 200
	}
	// Serialize loginResMes
	data, err := json.Marshal(registerResMes)
	if err != nil {
		fmt.Println("json.Marshal fail", err)
		return
	}

	// Assign data to resMes
	resMes.Data = string(data)

	// Serialize resMes and prepare to send
	data, err = json.Marshal(resMes)
	if err != nil {
		fmt.Println("json.Marshal fail", err)
		return
	}
	tf := &utils.Transfer{
		Conn: this.Conn,
	}
	err = tf.WritePkg(data)
	return
}

Functions for handling login

func (this *UserProcess) ServerProcessLogin(mes *message.Message) (err error) {
	var loginMes message.LoginMes
	err = json.Unmarshal([]byte(mes.Data), &loginMes)
	if err != nil {
		fmt.Println("json.Unmarshall fail err=", err)
		return
	}

	// A resMes
	var resMes message.Message
	resMes.Type = message.LoginResMesType

	// Declaring a LoginResMes
	var loginResMes message.LoginResMes

	//fmt.Println(loginMes.UserId)

	user, err := model.MyUserDao.Login(loginMes.UserId, loginMes.UserPwd)
	if err != nil {
		if err == model.ERROR_USER_NOTEXISTS {
			loginResMes.Code = 500
			loginResMes.Error = err.Error()
		} else if err == model.ERROR_USER_PWD {
			loginResMes.Code = 403
			loginResMes.Error = err.Error()
		} else {
			loginResMes.Code = 505
			loginResMes.Error = "Server internal error..."
		}
	} else {
		loginResMes.Code = 200
		fmt.Println(user, "Landing successfully")
	}

	// Serialize loginResMes
	data, err := json.Marshal(loginResMes)
	if err != nil {
		fmt.Println("json.Marshal fail", err)
		return
	}

	// Assign data to resMes
	resMes.Data = string(data)

	// Serialize resMes and prepare to send
	data, err = json.Marshal(resMes)
	if err != nil {
		fmt.Println("json.Marshal fail", err)
		return
	}

	tf := &utils.Transfer{
		Conn: this.Conn,
	}

	err = tf.WritePkg(data)
	return

}

The interaction between data and database is completed through userDao.

Landing function

func (this *UserDao) Login(userId int, userPwd string) (user *User, err error) {

	conn := this.pool.Get()
	defer conn.Close()
	user, err = this.getUserById(conn, userId)
	//fmt.Println(string(user.UserId))
	if err != nil {
		return
	}
	if user.UserPwd != userPwd {
		err = ERROR_USER_PWD
		return
	}
	return
}

Register function

func (this *UserDao) Register(user *message.User) (err error) {

	conn := this.pool.Get()
	defer conn.Close()
	_, err = this.getUserById(conn, user.UserId)
	if err == nil {
		err = ERROR_USER_EXISTS
		return
	}

	// At this time, if the id is not in redis, you can complete the registration.
	data, err := json.Marshal(user)
	if err != nil {
		return
	}
	_, err = conn.Do("HSet", "users", user.UserId, string(data))
	if err != nil {
		fmt.Println("Error saving registered user err=", err)
		return
	}
	return
}

 

Posted by K3nnnn on Wed, 23 Oct 2019 09:28:51 -0700