Golang练手------简单聊天系统

为了看Fabric的源码,前几天开始学了Go语言,看得是《Go语言圣经》,基本看了一遍,感觉还是比较容易上手,不过因为grpc和一些Go的库我都还不熟悉,现在看源码还是有点费劲,到现在也没怎么看。
不过Go语言学了就得练一下,不写代码估计过几天就跟没学一样了,(就像前几天学的js一样=_=||
所以今天找时间做了个聊天系统,比较简单,主要拿来熟悉一下Go语言…
过几天有空会试着用grpc写一下,再把文件改成数据库试试~

Created with Raphaël 2.1.2 client client server server register(注册) login(登录) logoff(注销登录) exit(退出系统) add(添加好友) delete(删除好友) list(获取好友列表) sendTo(向好友发消息) sendAll(群发消息)

客户端:client.go

package main

import (
    "bufio"
    "fmt"
    "io"
    "log"
    "net"
    "os"
)

func main() {

    //cinq := bufio.NewScanner(os.Stdin)
    //if cinq.Scan() {
    //  fmt.Printf(cinq.Text())
    //}
    //if cinq.Scan() {
    //  fmt.Printf(cinq.Text())
    //}
    //if cinq.Scan() {
    //  fmt.Printf(cinq.Text())
    //}

    conn, err := net.Dial("tcp", "localhost:8000")
    defer conn.Close()
    if err != nil {
        log.Fatal(err)
    }
    done := make(chan struct{})
    go func() {
        io.Copy(os.Stdout, conn) // NOTE: ignoring errors
        log.Println("done")
        done <- struct{}{} // signal the main goroutine
    }()
    ch := make(chan string)
    go clientWriter(conn, ch)
    cin := bufio.NewScanner(os.Stdin)
    for cin.Scan() {
        switch cin.Text() {
        case "register":
            ch <- "register"
            var userName, password, tel string
            fmt.Print("请输入用户名:")
            if cin.Scan() {
                userName = cin.Text()
            }
            fmt.Print("请输入密码:")
            if cin.Scan() {
                password = cin.Text()
            }
            fmt.Print("请输入手机号:")
            if cin.Scan() {
                tel = cin.Text()
            }
            ch <- userName
            ch <- password
            ch <- tel
        case "login":
            ch <- "login"
            var userName, password string
            fmt.Print("请输入用户名:")
            if cin.Scan() {
                userName = cin.Text()
            }
            fmt.Print("请输入密码:")
            if cin.Scan() {
                password = cin.Text()
            }
            ch <- userName
            ch <- password
        case "logoff":
            ch <- "logoff"
        case "exit":
            os.Exit(0)
        case "add":
            var userName string
            fmt.Print("请输入要添加好友的用户名:")
            if cin.Scan() {
                userName = cin.Text()
            }
            ch <- "add"
            ch <- userName
        case "delete":
            fmt.Print("请输入要删除好友的用户名:")
            var userName string
            if cin.Scan() {
                userName = cin.Text()
            }
            ch <- "delete"
            ch <- userName
        case "list":
            ch <- "list"
        case "sendTo":
            var userName, content string
            fmt.Print("请输入好友用户名:")
            if cin.Scan() {
                userName = cin.Text()
            }
            fmt.Print("请输入消息:")
            if cin.Scan() {
                content = cin.Text()
            }
            ch <- "sendTo"
            ch <- userName
            ch <- content
        case "sendAll":
            var content string
            fmt.Print("请输入消息:")
            if cin.Scan() {
                content = cin.Text()
            }
            ch <- "sendAll"
            ch <- content
        default:
            ch <- "none"
        }

    }
    //conn.Close() //前面用了defer
    <-done // wait for background goroutine to finish
}
func mustCopy(conn net.Conn, src io.Reader) {
    if _, err := io.Copy(conn, src); err != nil {
        log.Fatal(err)
    }
}

func clientWriter(conn net.Conn, ch <-chan string) {
    for msg := range ch {
        fmt.Fprintln(conn, msg)
    }
}

服务器端:server.go

package main

import (
    "bufio"
    "fmt"
    "io/ioutil"
    "log"
    "net"
    "os"
    "time"
)

func help() string {
    return (`
    please choose options:
        - register : 注册。            格式:"register"
        - login    : 登录。            格式:"login"
        - logoff   : 注销登录。         格式:"logoff"
        - exit     : 退出系统。         格式:"exit"
        - add      : 添加好友。         格式:"add"
        - delete   : 删除好友。         格式:"delete"
        - list     : 查看好友列表。      格式:"list"
        - sendTo   : 给某位好友发送消息。 格式:"sendTo"
        - sendAll  : 给全部好友发送消息。 格式:"sendAll"
        `)
}

/*
Client is a demo
*/
type Client struct {
    userName string
}
type userCH chan<- string

var (
    messages = make(chan string)
    entering = make(chan userCH)
    leaving  = make(chan userCH)
    clients  = make(map[string]userCH)
)

func main() {
    file, _ := os.OpenFile("user.txt", os.O_CREATE|os.O_RDWR, 0666)
    file.Close()
    listener, err := net.Listen("tcp", "localhost:8000")
    if err != nil {
        log.Fatal(err)
    }
    for {
        conn, err := listener.Accept()
        if err != nil {
            log.Print(err)
            continue
        }
        go handle(conn)
    }
}

func handle(conn net.Conn) {
    var client *Client
    ch := make(chan string)
    go clientWriter(conn, ch)
    who := conn.RemoteAddr().String()
    ch <- "welcome! " + who
    ch <- help()
    ch <- ">>"
    input := bufio.NewScanner(conn)
    for input.Scan() {
        var op = input.Text()
        fmt.Println(op)
        switch op {
        case "register":
            //register
            ok := register(input)
            if !ok {
                ch <- "Fail register=_=||\nmaybe your userName or phoneNumber is invalid"
            } else {
                ch <- "Success register!"
            }
        case "login":
            //login
            client = login(input)
            if client != nil {
                clients[client.userName] = ch
                ch <- "Success login!\n" + "Your new messages:" 
                client.toRead(ch)
            } else {
                ch <- "Fail login=_=||maybe your userName or password is wrong,please check them carefully:)"
            }
        case "logoff":
            if client == nil {
                ch <- "Please login first:)"
            } else {
                ch <- "you logoff successfully!"
                clients[client.userName] = nil
                client = nil
            }
        case "add":
            var userName string
            if input.Scan() {
                userName = input.Text()
            }
            if client == nil {
                ch <- "Please login first:)"
            } else {
                ok := client.addFriend(userName)
                if ok {
                    ch <- "add successfully!"
                } else {
                    ch <- "maybe no such user=_=||"
                }
            }
        case "delete":
            var userName string
            if input.Scan() {
                userName = input.Text()
            }
            if client == nil {
                ch <- "Please login first:)"
            } else {
                ok := client.deleteFriend(userName)
                if ok {
                    ch <- "delete successfully!"
                } else {
                    ch <- "maybe no such user=_=||"
                }
            }
        case "list":
            if client == nil {
                ch <- "Please login first:)"
            } else {
                ch <- client.list()
            }
        case "sendTo":
            if client == nil {
                ch <- "Please login first:)"
            } else {
                var userName, content string
                if input.Scan() {
                    userName = input.Text()
                }
                if input.Scan() {
                    content = input.Text()
                }
                ok := client.sendTo(userName, content)
                if ok {
                    ch <- "发送成功"
                } else {
                    ch <- "发送失败,可能你没有这个好友:)"
                }
            }
        case "sendAll":
            if client == nil {
                ch <- "Please login first:)"
            } else {
                var content string
                if input.Scan() {
                    content = input.Text()
                }
                client.sendAll(content)
            }
        default:
            ch <- "无法识别的命令=_=||请重新输入正确的命令:)"
            ch <- help()
        }
        ch <- ">>"
    }
    conn.Close()
}

func clientWriter(conn net.Conn, ch chan string) {
    for msg := range ch {
        fmt.Fprintln(conn, msg)
    }
}

//读取文件user.txt,判断手机号和用户名是否重复注册
//将注册信息写入user.txt
//如果成功就创建messages、logs、friends等.txt文件
func register(cin *bufio.Scanner) bool {
    var userName, password, tel string
    if cin.Scan() {
        userName = cin.Text()
    }
    if cin.Scan() {
        password = cin.Text()
    }
    if cin.Scan() {
        tel = cin.Text()
    }
    file, err := os.OpenFile("user.txt", os.O_RDWR, 0644)
    defer file.Close()
    if err != nil {
        fmt.Println("in func register: open user.txt")
    }
    for {
        var name, pwd, phone string
        _, err := fmt.Fscan(file, &name, &pwd, &phone) //读取三个string
        if err != nil {
            break
        }
        fmt.Println(userName, name, tel, phone)
        if userName == name && tel == phone {
            return false
        }
    }
    file.Write([]byte("\n" + userName + " " + password + " " + tel))
    createInfo(userName)
    return true
}

func createInfo(userName string) {
    file, err := os.OpenFile("friendsOf"+userName+".txt", os.O_CREATE, 0664)
    if err != nil {
        log.Fatalln("in func createInfo: ---")
    }
    file.Close()
    file, err = os.OpenFile("messagesOf"+userName+".txt", os.O_CREATE, 0664)
    file.Close()
    file, err = os.OpenFile("logsOf"+userName+".txt", os.O_CREATE, 0664)
    file.Close()
}

//读取user.txt,判断是否有这个用户以及密码是否正确
//上线后自动查看收件箱,显示未读消息
func login(cin *bufio.Scanner) *Client {
    var userName, password string
    if cin.Scan() {
        userName = cin.Text()
    }
    if cin.Scan() {
        password = cin.Text()
    }
    file, err := os.Open("user.txt")
    defer file.Close()
    if err != nil {
        fmt.Println("func register: open user.txt")
    }
    for {
        var name, pwd, phone string
        _, err := fmt.Fscan(file, &name, &pwd, &phone) //读取三个string
        if err != nil {
            fmt.Println(err)
            break
        }
        if userName == name && pwd == password {
            var client Client
            client.userName = userName
            //  client.ch = make(chan string)
            //  go clientWriter(conn, client.ch)
            //  clients[userName] = client.ch
            return &client
        }
    }
    return nil
}

func (c *Client) toRead(ch chan string) {
    messages := "messagesOf" + c.userName + ".txt"
    logs := "logsOf" + c.userName + ".txt"
    msgsfile, err := os.OpenFile(messages, os.O_RDWR, 0666) //读写
    defer msgsfile.Close()
    logsfile, err := os.OpenFile(logs, os.O_APPEND|os.O_WRONLY, 0666)
    defer logsfile.Close()
    if err != nil {
        log.Fatalln("func toRead, fail to open file")
    }
    for {
        //格式 : 时间、好友名字、信息内容
        var t, n, content string
        _, err := fmt.Fscan(msgsfile, &t, &n, &content)
        if err != nil {
            //log.Fatalln("messagesfuserName.txt went wrong! in to read")
            fmt.Println(err)
            break
        }
        temp := t + " " + n + " " + content
        //fmt.Println(temp)
        _, err = logsfile.Write([]byte("\n" + t + " " + n + " " + c.userName + " " + content))
        if err != nil {
            fmt.Println("write logs wrong! in func toRead")
        }
        ch <- temp
    }
    msgsfile.Seek(0, 0)  //second para: (0:begin) (1:cur) (2:end)
    msgsfile.Truncate(0) //清空未读消息
}

func (c *Client) addFriend(userName string) bool {
    userFile := "user.txt"
    file, err := os.Open(userFile)
    defer file.Close()
    if err != nil {
        log.Fatalln("in func addFriend: open user.txt")
    }
    var name, pwd, phone string
    for {
        _, err = fmt.Fscan(file, &name, &pwd, &phone)
        if err != nil { //EOF?? //TODO
            break
        }
        if name == userName {
            friendFile, err := os.OpenFile("friendsOf"+c.userName+".txt", os.O_APPEND|os.O_WRONLY, 0666)
            defer friendFile.Close()
            if err != nil {
                log.Fatalln("in func addFriend: open friendsOf" + c.userName + ".txt")
            }
            friendFile.Write([]byte("\n" + userName))
            return true
        }
    }
    return false
}
func (c *Client) deleteFriend(userName string) bool {
    friendFile, err := os.OpenFile("friendsOf"+c.userName+".txt", os.O_RDWR, 0666)
    defer friendFile.Close()
    if err != nil {
        log.Fatalln("in func deleteFriend: open friendsOf" + c.userName + ".txt")
    }
    var name, sum string
    var ok = false
    for {
        _, err := fmt.Fscan(friendFile, &name)
        if err != nil {
            break
        }
        if name == userName {
            ok = true
        } else {
            sum += "\n" + name
        }
    }
    if ok {
        friendFile.Seek(0, 0)
        friendFile.Truncate(0) //这里是截断是不是清除内容待验证 //TODO
        friendFile.Write([]byte(sum))
    }
    return ok
}
func (c *Client) list() string {
    filename := "friendsOf" + c.userName + ".txt"
    file, err := os.Open(filename)
    if err != nil {
        return ""
    }
    res, _ := ioutil.ReadAll(file)
    return string(res)
}
func (c *Client) sendTo(userName, content string) bool {
    msg := "\n" + time.Now().Format("2006-01-02_15:04:05") + " " + c.userName + " " + content
    msglog := "\n" + time.Now().Format("2006-01-02_15:04:05") + " " + c.userName + " " + userName + " " + content
    friendFile, err := os.OpenFile("friendsOf"+c.userName+".txt", os.O_RDONLY, 0666)
    if err != nil {
        log.Fatalln("in func sendAll: open friendsOf" + c.userName + ".txt")
    }
    var friend string
    var ok bool
    for {
        _, err := fmt.Fscan(friendFile, &friend)
        if err != nil {
            break
        }
        if friend == userName {
            ok = true
            break
        }
    }
    friendFile.Close()
    if ok {
        if clients[userName] != nil {
            clients[userName] <- msg
            logsFile, err := os.OpenFile("logsOf"+userName+".txt", os.O_APPEND|os.O_WRONLY, 0666)
            if err != nil {
                log.Fatalln("in func sendTo: open logsOf" + userName + ".txt")
            }
            logsFile.Write([]byte(msglog))
            logsFile.Close()
        } else {
            msgsFile, err := os.OpenFile("messagesOf"+userName+".txt", os.O_APPEND|os.O_WRONLY, 0666)
            if err != nil {
                log.Fatalln("in func sendTo: open messagesOf" + userName + ".txt")
            }
            msgsFile.Write([]byte(msg))
            msgsFile.Close()
        }
        logsFile, err := os.OpenFile("logsOf"+c.userName+".txt", os.O_APPEND|os.O_WRONLY, 0666)
        if err != nil {
            log.Fatalln("in func sendTo: open logsOf" + c.userName + ".txt")
        }
        logsFile.Write([]byte(msglog))
        logsFile.Close()
        return true
    }
    return false
}
func (c *Client) sendAll(content string) bool {
    msg := "\n" + time.Now().Format("2006-01-02_15:04:05") + " " + c.userName + " " + content
    friendFile, err := os.OpenFile("friendsOf"+c.userName+".txt", os.O_RDONLY, 0666)
    if err != nil {
        log.Fatalln("in func sendAll: open friendsOf" + c.userName + ".txt")
    }
    file, err := os.OpenFile("logsOf"+c.userName+".txt", os.O_APPEND|os.O_WRONLY, 0666)
    if err != nil {
        log.Fatalln("in func sendAll: open logsOf" + c.userName + ".txt")
    }
    defer file.Close()
    var userName, msglog string
    for {
        _, err := fmt.Fscan(friendFile, &userName)
        if err != nil {
            break
        }
        msglog = "\n" + time.Now().Format("2006-01-02_15:04:05") + " " + c.userName + " " + userName + " " + content
        if clients[userName] != nil {
            clients[userName] <- content
            logsFile, err := os.OpenFile("logsOf"+userName+".txt", os.O_APPEND|os.O_WRONLY, 0666)
            if err != nil {
                log.Fatalln("in func sendAll open logsOf" + userName + ".txt")
            }
            logsFile.Write([]byte(msglog))
            logsFile.Close()
        } else {
            msgsFile, err := os.OpenFile("messagesOf"+userName+".txt", os.O_APPEND|os.O_WRONLY, 0666)
            if err != nil {
                log.Fatalln("in func sendAll: open messagesOf" + userName + ".txt")
            }
            msgsFile.Write([]byte(msg))
            msgsFile.Close()
        }
        file.Write([]byte(msglog))
    }
    return true
}

/*
func readfile(filename string) string {
    //var res []string
    file, err := os.Open(filename)
    if err != nil {
        return ""
    }
    buf, _ := ioutil.ReadAll(file)
    //for {
    //  var name, pwd string
    //  _, err := fmt.Fscan(file, &name, &pwd)
    //  if err != nil {
    //      break
    //  }
    //  res = append(res, name)
    //  res = append(res, pwd)
    //}
    file.Close()
    //file, err = os.OpenFile("user.txt", os.O_APPEND|os.O_WRONLY, 0644)
    //if err != nil {
    //  return nil
    //}
    //name, pwd := "dsfa", "jag"
    //file.Write([]byte("\n" + name))
    //file.Write([]byte(" " + pwd))
    //file.Close()
    return string(buf)
}
*/

猜你喜欢

转载自blog.csdn.net/yijiull/article/details/81676961