此項目參照韓順平老師教程,特此感謝。
項目結構如下:
client,server分別是客戶端和服務端代碼包,common爲公共文件函數包;
main,model,processf分別存放主程序文件,結構體文件和方法文件,其中server下model中的Dao.go是redis連接池配置文件,引用了redis的git代碼包地址:https://github.com/gomodule/redigo,下載後按說明引用。
運行項目:
1.開啓服務端
2.開啓客戶端(一個或多個)
3.註冊並登錄後顯示
4.再登陸幾個客戶端,就可以互相發送消息和傳送文件以及其他用戶上下線服務端消息提醒了
代碼如下:
server端:
main/main.go:
package main
import (
"learn/chatroom/server/mainProcess"
"learn/chatroom/server/model"
"time"
)
func main() {
//初始化連接池得到全局連接池變量pool
model.PoolInit(8, 0, time.Second * 100, "tcp", "localhost:6379")
//啓動服務端進程
mainProcess.GetMainProcess().OnlyProcess()
}
mainProcess/mainProcess.go:
package mainProcess
import (
"fmt"
"net"
"learn/chatroom/common/utils"
"learn/chatroom/common/message"
"learn/chatroom/server/process"
)
type MainProcess struct {
Conn net.Conn
}
func GetMainProcess() *MainProcess {
return &MainProcess{}
}
func (this *MainProcess) OnlyProcess() {
fmt.Println("server開始監聽。。。")
listen, err := net.Listen("tcp", "0.0.0.0:9999")
if err != nil {
fmt.Println("listen err=", err)
return
}
defer listen.Close()
for {
fmt.Println("等待客戶端連接。。。")
//等待並返回下一個連接到該接口的連接
conn, err_accp := listen.Accept()
this.Conn = conn
if err_accp != nil {
fmt.Println("err_accp=", err_accp)
} else {
fmt.Printf("客戶端network=%v,ip=%v連接成功\n", conn.RemoteAddr().Network(), conn.RemoteAddr().String())
//協程處理多個連接
go this.process(conn)
}
}
}
//登錄後處理其他業務
func (this *MainProcess) process(conn net.Conn) {
user := process.GetUserProcess(conn)
defer conn.Close()
defer func (){//匿名函數處理用戶下線業務
var uid int
loggedUser := process.GetLoggedUser()
//獲取當前用戶id
for i, mp := range *loggedUser {
for id, co := range mp {
if co == conn {
uid = id
//去掉當前下線用戶
*loggedUser = append((*loggedUser)[:i], (*loggedUser)[i + 1:]...)
}
}
}
//fmt.Println("unline uid=", uid)
//說明未獲取當前用戶id
if uid == 0 {
return
}
//通知其他線上用戶
for _, mp := range *loggedUser {
for _, co := range mp {
if co == conn {
continue
}
user.NotifyOtherUsers(uid, co, 0)
}
}
}()
var mes, mes_back message.Message
var resmes message.ResMes
for {
err := utils.ReceiveMsg(conn, &mes)
if err != nil {
fmt.Println("服務器接受信息失敗")
return
}
switch mes.Type {
case 1 ://登錄類型請求
user.DoLogin(mes, mes_back, resmes)
case 2 ://註冊類型請求
user.DoRegister(mes, mes_back, resmes)
case 3 ://顯示在線用戶
user.ShowUserOnline(mes_back)
case 4 ://用戶發送消息
user.SendMes(mes, mes_back)
case 6 ://查看消息
user.SearchMesList(mes, mes_back)
case 7 ://發送文件
user.SendFile(mes, mes_back)
}
}
}
model/Dao.go:
package model
import (
"github.com/garyburd/redigo/redis"
"time"
)
var pool *redis.Pool
func PoolInit(maxIdle int, maxActive int, idleTimeout time.Duration, network string, address string) {
//初始化連接池
pool = &redis.Pool{
MaxIdle : maxIdle,
MaxActive : maxActive,
IdleTimeout : idleTimeout,
Dial : func() (redis.Conn, error){
return redis.Dial(network, address)
},
}
}
model/user.go:
package model
type User struct {
UserId int `json:"id"`
UserName string `json:"name"`
UserPwd string `json:"pwd"`
}
model/userDao.go:
package model
import (
"github.com/garyburd/redigo/redis"
"fmt"
"encoding/json"
"learn/chatroom/common/message"
"time"
)
type UserDao struct {
Con redis.Conn
}
func NewUserDao() *UserDao {
return &UserDao{pool.Get()}
}
//根據id獲取user
func (this *UserDao) GetUserById(id int, user *User) error {
user2, err := redis.String(this.Con.Do("hget", "users", id))
if err != nil {
fmt.Println("redis.String err=", err)
return err
}
err = json.Unmarshal([]byte(user2), user)
if err != nil {
fmt.Println("json.Unmarshal err=", err)
return err
}
return nil
}
//新增user
func (this *UserDao) AddUser(mes message.LoginMes) error {
//先檢查用戶id是否重複
user_old, _ := redis.String(this.Con.Do("hget", "users", mes.UserId))
fmt.Println("user_old=", user_old)
if user_old != "" {
fmt.Println("用戶已存在!!!")
return fmt.Errorf("用戶已存在!!!")
}
user := User{UserId : mes.UserId, UserName : mes.UserName, UserPwd : mes.UserPwd}
userJson, err := json.Marshal(user)
if err != nil {
fmt.Println("userJson, err=", err)
return err
}
_, err = this.Con.Do("hset", "users", mes.UserId, string(userJson))
if err != nil {
fmt.Println("hset user err=", err)
return err
}
return nil
}
//保存消息
func (this *UserDao) SaveMes(uid int, toUid int, content string) error {
str := fmt.Sprintf("%dto%d", uid, toUid)
_, err := this.Con.Do("hset", str, time.Now().UnixNano(), content)
if err != nil {
fmt.Println("SaveMes hset err=", err)
return err
}
return nil
}
//用戶查看消息記錄,由於redis包識別不了hgetall指令,姑只取一條作示例
func (this *UserDao) SearchMesList(idToId string) string {
data, err := redis.String(this.Con.Do("hget", idToId, "1576641743776366500"))
if err != nil {
fmt.Println("hgetall idToId err=", err)
return ""
}
return data
}
process/userManage.go:
package process
//已上線用戶管理
import (
"net"
)
type AllLoggedUser struct {
LoggedUser []map[int]net.Conn
}
var (
allLoggedUser AllLoggedUser
)
func GetLoggedUser() *[]map[int]net.Conn {
return &allLoggedUser.LoggedUser
}
//已上線變量添加用戶
func (this *AllLoggedUser) AddUser(id int, conn net.Conn) {
mp := make(map[int]net.Conn)
mp[id] = conn
this.LoggedUser = append(this.LoggedUser, mp)
}
//已上線變量刪除下線用戶
func (this *AllLoggedUser) DelUser(id int) {
for i, val := range this.LoggedUser {
for uid, _ := range val {
if uid == id {
this.LoggedUser = append(this.LoggedUser[:i], this.LoggedUser[i + 1 :]...)
}
}
}
}
process/userProcess.go:
package process
import (
"learn/chatroom/common/message"
"learn/chatroom/common/utils"
"learn/chatroom/server/model"
"encoding/json"
"net"
"fmt"
)
type UserProcess struct {
Conn net.Conn
}
func GetUserProcess(conn net.Conn) *UserProcess {
return &UserProcess{conn}
}
//登錄
func (this *UserProcess) DoLogin(mes message.Message, mes_back message.Message, resmes message.ResMes) {
var data_login message.LoginMes
var user model.User
mes_back.Type = -1
json.Unmarshal([]byte(mes.Data), &data_login)
err := model.NewUserDao().GetUserById(data_login.UserId, &user)
if err !=nil {
resmes.Code = 300
resmes.Msg = "未註冊!!!"
} else if data_login.UserPwd == user.UserPwd {
resmes.Code = 200
resmes.Msg = "服務端驗證成功!!!"
//通知其他線上用戶
for _, mp := range allLoggedUser.LoggedUser {
for id, conn := range mp {
if id == user.UserId {
continue //跳過自己
}
this.NotifyOtherUsers(data_login.UserId, conn, 1)
}
}
//新增已登錄用戶到變量LoggedUser
allLoggedUser.AddUser(user.UserId, this.Conn)
} else {
resmes.Code = 300
resmes.Msg = "服務端驗證失敗!!!"
}
mesres_json, err := json.Marshal(resmes)
mes_back.Data = string(mesres_json)
err = utils.SendMsg(this.Conn, mes_back)
if err != nil {
fmt.Println("服務器反饋信息失敗")
}
}
//註冊
func (this *UserProcess) DoRegister(mes message.Message, mes_back message.Message, resmes message.ResMes) {
var data_login message.LoginMes
mes_back.Type = -2
json.Unmarshal([]byte(mes.Data), &data_login)
err := model.NewUserDao().AddUser(data_login)
if err !=nil {
resmes.Code = 300
resmes.Msg = "服務端新增用戶失敗!!!"
} else {
resmes.Code = 200
resmes.Msg = "服務端新增用戶成功!!!"
}
mesres_json, err := json.Marshal(resmes)
mes_back.Data = string(mesres_json)
err = utils.SendMsg(this.Conn, mes_back)
if err != nil {
fmt.Println("服務器反饋新增信息失敗")
}
}
//顯示在線用戶
func (this *UserProcess) ShowUserOnline(mes_back message.Message) {
mes_back.Type = -3
users := make([]model.User, 10)
for _, mp := range allLoggedUser.LoggedUser {
for id, _ := range mp {
var user model.User
model.NewUserDao().GetUserById(id, &user)
users[id] = user
}
}
loggedUserJson, err := json.Marshal(users)
mes_back.Data = string(loggedUserJson)
err = utils.SendMsg(this.Conn, mes_back)
if err != nil {
fmt.Println("服務器反饋在線用戶信息失敗")
}
}
//用戶向其他用戶發送消息
func (this *UserProcess) SendMes(mes message.Message, mes_back message.Message) {
var sendmes message.SendMes
mes_back.Type = -4
err := json.Unmarshal([]byte(mes.Data), &sendmes)
if err != nil {
fmt.Println("服務端反序列化sendmes失敗!!!")
return
}
last_content := fmt.Sprintf("%d said to %d:%s\n",sendmes.Uid, sendmes.ToUid, sendmes.Content)
mes_back.Data = last_content
//保存消息到redis
err = model.NewUserDao().SaveMes(sendmes.Uid, sendmes.ToUid, last_content)
if err != nil {
return
}
//用以判斷目標客戶是否在線
isOnline := false
//發送消息到對應的用戶
for _, mp := range allLoggedUser.LoggedUser {
for id, conn := range mp {
if id == sendmes.ToUid {
isOnline = true
err = utils.SendMsg(conn, mes_back)
}
}
}
if isOnline == false {//離線時,起一個攜程監聽客戶上線再發送
go this.WatchUserIsOnline(sendmes.ToUid, mes_back)
}
}
//離線發送消息
func (this *UserProcess) WatchUserIsOnline(toUid int, mes_back message.Message) {
boo := true
for boo{
for _, mp := range allLoggedUser.LoggedUser {
for id, conn := range mp {
if id == toUid {
err := utils.SendMsg(conn, mes_back)
if err != nil {
fmt.Println("服務端離線發送消息失敗!!!")
}
boo = false
}
}
}
}
}
//通知其他用戶上線 onlineOrUnline=1->上線,否則下線
func (this *UserProcess) NotifyOtherUsers(currentId int, conn net.Conn, onlineOrUnline int) {
var mes message.Message
var str string
mes.Type = -5
if onlineOrUnline == 1 {
str = fmt.Sprintf("id爲%d的用戶已上線", currentId)
} else {
str = fmt.Sprintf("id爲%d的用戶已下線", currentId)
}
mes.Data = str
err := utils.SendMsg(conn, mes)
if err != nil {
fmt.Println("服務端推送消息失敗")
}
}
//用戶查看消息記錄
func (this *UserProcess) SearchMesList(mes message.Message, mes_back message.Message) {
content := model.NewUserDao().SearchMesList(mes.Data)
mes_back.Type = -6
mes_back.Data = content
err := utils.SendMsg(this.Conn, mes_back)
if err != nil {
fmt.Println("服務端查詢消息列表失敗")
}
}
//發送文件
func (this *UserProcess) SendFile(mes message.Message, mes_back message.Message) {
var fileMes message.FileMes
json.Unmarshal([]byte(mes.Data), &fileMes)
mes_back.Type = -7
mes_back.Data = mes.Data
for _, mp := range allLoggedUser.LoggedUser {
for id, conn := range mp {
if id == fileMes.ToUid {
err := utils.SendMsg(conn, mes_back)
if err != nil {
fmt.Println("服務端發送文件失敗!!!")
}
}
}
}
}
---------------------------------------------------------------------------分界線------------------------------------------------------------------------------------
client:
main/main.go:
package main
import (
"fmt"
"learn/chatroom/client/process"
"net"
"os"
)
func main() {
var key int
var loop = true
var uid int
var name string
var pwd string
conn := GetConn()
for {
mainMenu(&loop, &key)
switch key {
case 1 :
toLogin(&uid, &pwd, conn)
//登錄後顯示菜單
process.ShowMenu(conn, uid)
case 2 :
toRegister(&uid, &name, &pwd, conn)
case 3 :
os.Exit(0)
}
}
}
func GetConn() net.Conn {
//建立連接
conn, err_conn := net.Dial("tcp", "192.168.2.149:9999")
if err_conn != nil {
fmt.Println("conn err =", err_conn)
}
return conn
}
func toLogin(uid *int, pwd *string, conn net.Conn){
for {
fmt.Println("請輸入用戶id")
fmt.Scanln(uid)
fmt.Println("請輸入用戶密碼")
fmt.Scanln(pwd)
userProcess := process.GetUserProcess(conn)
err_login := userProcess.DoLogin(uid, pwd)
if err_login != nil {
fmt.Println("用戶名或密碼錯誤,請重新輸入")
} else {
break
}
}
}
func toRegister(uid *int, name *string, pwd *string, conn net.Conn) {
for {
fmt.Println("請輸入用戶id")
fmt.Scanln(uid)
fmt.Println("請輸入用戶暱稱")
fmt.Scanln(name)
fmt.Println("請輸入用戶密碼")
fmt.Scanln(pwd)
userProcess := process.GetUserProcess(conn)
err := userProcess.DoRegister(uid, name, pwd)
if err != nil {
fmt.Println("註冊失敗,請重新輸入")
} else {
break
}
}
}
func mainMenu(loop *bool, key *int) {
for *loop {
fmt.Println("------------------------歡迎使用多人聊天系統----------------------------")
fmt.Println("\t\t\t 1 登錄聊天室 ")
fmt.Println("\t\t\t 2 註冊用戶 ")
fmt.Println("\t\t\t 3 退出系統 ")
fmt.Println("\t\t\t 請選擇 1-3 ")
fmt.Scanln(key)
switch *key {
case 1 :
fmt.Println(" 登錄聊天室 ")
*loop = false
case 2 :
fmt.Println(" 註冊用戶 ")
*loop = false
case 3 :
fmt.Println(" 退出系統 ")
*loop = false
default :
fmt.Println(" 輸入錯誤,請重新輸入 ")
}
}
}
model/user.go:
package model
type User struct {
UserId int `json:"id"`
UserName string `json:"name"`
UserPwd string `json:"pwd"`
}
process/server.go:
package process
import (
"fmt"
"os"
"net"
"learn/chatroom/common/utils"
"learn/chatroom/common/message"
"learn/chatroom/client/model"
"encoding/json"
"io/ioutil"
)
//登錄後菜單
func ShowMenu(conn net.Conn, uid int) {
fmt.Println("-------------------恭喜xxx登陸成功----------------------")
var num int
up := GetUserProcess(conn)
for {
fmt.Println(" 1.顯示在線用戶 ")
fmt.Println(" 2.發送消息")
fmt.Println(" 3.信息列表")
fmt.Println(" 4.發送文件")
fmt.Println(" 5.退出系統")
fmt.Println("請選擇1-4")
fmt.Scanln(&num)
switch num {
case 1 :
up.ShowUserOnline()
case 2 :
up.SendMes(uid)
case 3 :
up.SearchMesList(uid)
case 4 :
up.SendFile(uid)
case 5 :
fmt.Println("退出系統")
os.Exit(0)
default :
fmt.Println("輸入錯誤,請重新輸入")
}
}
}
//監聽服務端推送消息
func ServerProcessMes(conn net.Conn) {
//fmt.Println("ServerProcessMes 等待服務器消息")
for {
var mes message.Message
err := utils.ReceiveMsg(conn, &mes)
if err != nil {
fmt.Println("ServerProcessMes utils.ReceiveMsg fail")
return
}
//fmt.Println("ServerProcessMes 獲取的mes=", mes)
switch mes.Type {
case -3 :
users := make([]model.User, 10)
json.Unmarshal([]byte(mes.Data), &users)
fmt.Println("在線用戶如下:")
for _, user := range users {
if user.UserId > 0 {
fmt.Printf("用戶id=%d\tname=%s\tpwd=%s\n", user.UserId, user.UserName, user.UserPwd)
}
}
case -4, -5, -6:
fmt.Println(mes.Data)
case -7 :
ReceiveFile(mes)
default :
fmt.Println("ServerProcessMes mes", mes)
}
}
}
//接受文件
func ReceiveFile(mes message.Message) {
var fileMes message.FileMes
json.Unmarshal([]byte(mes.Data), &fileMes)
var path string
path = fmt.Sprintf("d:/ctfiles/%s", fileMes.FileName)
err := ioutil.WriteFile(path, fileMes.Content, 0666)
if err != nil {
fmt.Println("write err=", err)
} else {
str := fmt.Sprintf("接收用戶id=%d的文件%s成功!!!", fileMes.Uid, fileMes.FileName)
fmt.Println(str)
}
}
process/userProcess.go:
package process
//客戶端用戶業務
import (
"fmt"
"learn/chatroom/common/message"
"learn/chatroom/common/utils"
"net"
"encoding/json"
"io/ioutil"
"strings"
)
type UserProcess struct {
Conn net.Conn
}
//實例化
func GetUserProcess(conn net.Conn) *UserProcess {
return &UserProcess{Conn : conn}
}
//登錄請求
func (this *UserProcess) DoLogin(uid *int, pwd *string ) error {
//mes爲發送到服務端信息,mes_back爲服務端反饋信息
var mes, mes_back message.Message
logmes := message.LoginMes{UserId : *uid, UserPwd : *pwd}
mes.Type = 1
loginJson, err := json.Marshal(logmes)
if err != nil {
fmt.Println("logindata marshal err=", err)
return err
}
mes.Data = string(loginJson)
err_send := utils.SendMsg(this.Conn, mes)
if err_send != nil {
return err_send
}
err_receive := utils.ReceiveMsg(this.Conn, &mes_back)
if err_receive != nil {
fmt.Println("客戶端接收反饋信息失敗")
return err_receive
}
//resmes爲服務端反饋的具體信息
var resmes message.ResMes
json.Unmarshal([]byte(mes_back.Data), &resmes)
//反饋登陸成功
if mes_back.Type == -1 && resmes.Code == 200 {
fmt.Println(resmes)
//監聽服務端的消息,如好友上線,發來消息等
go ServerProcessMes(this.Conn)
return nil
}
return fmt.Errorf("客戶端接收反饋信息錯誤")
}
//註冊請求
func (this *UserProcess) DoRegister(uid *int, name *string, pwd *string) (err error) {
//mes爲發送到服務端信息,mes_back爲服務端反饋信息
var mes, mes_back message.Message
logmes := message.LoginMes{UserId : *uid, UserName : *name, UserPwd : *pwd}
mes.Type = 2
registerJson, err := json.Marshal(logmes)
if err != nil {
fmt.Println("register-data marshal err=", err)
return
}
mes.Data = string(registerJson)
err = utils.SendMsg(this.Conn, mes)
if err != nil {
return
}
err = utils.ReceiveMsg(this.Conn, &mes_back)
if err != nil {
fmt.Println("客戶端接收反饋信息失敗")
return
}
//resmes爲服務端反饋的具體信息
var resmes message.ResMes
json.Unmarshal([]byte(mes_back.Data), &resmes)
//反饋註冊成功
if mes_back.Type == -2 && resmes.Code == 200 {
fmt.Println(resmes.Msg)
err = nil
return
}
err = fmt.Errorf("客戶端接收反饋信息錯誤")
return
}
//顯示在線用戶
func (this *UserProcess) ShowUserOnline() {
var mes message.Message
mes.Type = 3
err := utils.SendMsg(this.Conn, mes)
if err != nil {
fmt.Println("客戶端發送反饋信息失敗")
return
}
}
//用戶發送消息
func (this *UserProcess) SendMes(uid int) {
var toUid int
var content string
fmt.Println("請輸入想聊天對象的id:")
fmt.Scanln(&toUid)
fmt.Println("請輸入聊天內容:")
fmt.Scanln(&content)
fmt.Printf("%d said to %d: %s\n", uid, toUid, content)
var mes message.Message
mes.Type = 4
var dataSend message.SendMes
dataSend.Uid = uid
dataSend.ToUid = toUid
dataSend.Content = content
dataJson, err := json.Marshal(dataSend)
mes.Data= string(dataJson)
if err != nil {
fmt.Println("json.Marshal(data)失敗")
return
}
err = utils.SendMsg(this.Conn, mes)
if err != nil {
fmt.Println("客戶端發送信息失敗")
return
}
}
//查看消息列表
func (this *UserProcess) SearchMesList(uid int) {
var toid int
var mes message.Message
fmt.Println("請輸入目標用戶的id")
fmt.Scanln(&toid)
content := fmt.Sprintf("%dto%d", uid, toid)
mes.Type = 6
mes.Data = content
err := utils.SendMsg(this.Conn, mes)
if err != nil {
fmt.Println("查看消息列表失敗")
}
}
//發送文件
func (this *UserProcess) SendFile(uid int) {
var filePath string
var toUid int
var fileName string
var mes message.Message
var fileMes message.FileMes
fmt.Println("請輸入文件地址:")
fmt.Scanln(&filePath)
fmt.Println("請輸入接收對象id:")
fmt.Scanln(&toUid)
//判斷文件是否存在
ok, _ := utils.PathExists(filePath)
if !ok {
fmt.Println("文件夾不存在!!!")
return
}
//獲取文件名和內容
strs := strings.Split(filePath, "/")
fileName = strs[len(strs) - 1]
content, err_cont := ioutil.ReadFile(filePath)
if err_cont != nil {
fmt.Println("讀取文件內容失敗!!!")
return
}
//封裝消息體
fileMes.Uid = uid
fileMes.ToUid = toUid
fileMes.FileName = fileName
fileMes.Content = content
fileJson, _ := json.Marshal(fileMes)
mes.Type = 7
mes.Data = string(fileJson)
err := utils.SendMsg(this.Conn, mes)
if err != nil {
fmt.Println("發送文件失敗!!!")
}
fmt.Println("發送文件成功!!!")
}
--------------------------------------------------------------------------------------分界線-------------------------------------------------------------------------
common:
message/message.go:
package message
type Message struct {
//類型 1-登錄-1-登陸反饋 2-註冊 -2 -註冊反饋 3-顯示在線用戶 -3,-顯示在線用戶反饋 4-用戶向用戶發送信息 -4,反饋 -5,-服務器推送消息
//6-用戶查看消息列表 -6,反饋 7-用戶發送文件 -7,反饋
Type int
Data string //數據
}
type LoginMes struct {
UserId int `json:"id"`
UserPwd string `json:"pwd"`
UserName string `json:"name"`
}
type ResMes struct {
Code int //返回狀態碼 100-未註冊 200-成功 300-失敗
Msg string //信息
}
type SendMes struct {
Uid int `json:"uid"`
ToUid int `json:"touid"`
Content string `json:"content"`
}
type FileMes struct {
Uid int
ToUid int
FileName string
Content []byte
}
utils/cli_to_ser.go:
package utils
//客戶端和服務端相互推送消息
import (
"net"
"learn/chatroom/common/message"
"encoding/json"
"encoding/binary"
"fmt"
"os"
)
func SendMsg(conn net.Conn, mes message.Message) error {
mesJson, err_mesJson := json.Marshal(mes)
if err_mesJson != nil {
fmt.Println("mes marshal err=", err_mesJson)
return err_mesJson
}
//定義傳輸字節長度
meslen := uint32(len(mesJson))
buf := make([]byte, 4)
//uint32轉成[]byte,以便conn.Write()
binary.BigEndian.PutUint32(buf[:4], meslen)
//發送數據長度
n, err_write := conn.Write(buf[:4])
if err_write !=nil || n != 4 {
fmt.Println("mes-length write err=", err_write)
return err_write
}
//fmt.Printf("發送了%v個字節\n", len(mesJson))
//fmt.Println("發送的data=", string(mesJson))
//發送登錄數據
_, err_write = conn.Write(mesJson)
if err_write !=nil {
fmt.Println("mes-data write err=", err_write)
return err_write
}
return nil
}
func ReceiveMsg(conn net.Conn, mes *message.Message) (error){
//定義接收字節變量
buf := make([]byte, 8192)
//conn.Read()等待客戶端發送消息,如果沒有write[發送],那麼協程阻塞在這裏
//讀取前四個字節,數據長度
n, err := conn.Read(buf[:4])
if err != nil || n != 4 {
fmt.Println("server read len err=", err)
fmt.Println("客戶端退出。。。")
return err
}
//獲取接受的數據長度。將[]byte轉成uint32
data_len := binary.BigEndian.Uint32(buf[:4])
//接收已知長度的數據
n, err = conn.Read(buf[:data_len])
if n != int(data_len) || err !=nil {
fmt.Println("server read data err=", err)
fmt.Println("客戶端退出。。。")
return err
}
//fmt.Println("接收到的data_len=", data_len)
//fmt.Println("接收到的data=", string(buf[:data_len]))
json.Unmarshal(buf[:data_len], mes)
return nil
}
//判斷文件文件是否存在
func PathExists(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil {
return true, nil
}
if os.IsNotExist(err) {
return false, nil
}
return false, err
}
以上就是全部