網(wǎng)絡(luò)編程基礎(chǔ)(聊天室)

服務(wù)端

package main

import (
    "fmt"
    "net"
    "strings"
    "os"
    "log"
)


// 服務(wù)器只是中轉(zhuǎn)!

var msgQue = make(chan string, 1000) // 現(xiàn)在處理一個(gè)消息隊(duì)列
var quitChan = make(chan bool)   // 管理退出消息
var onlineConns = make(map[string]net.Conn)  // 管理連接
var logfile *os.File
var logger *log.Logger
func ProcessInfo(conn net.Conn) {
    buf := make([]byte, 1024)
    defer func(conn net.Conn) {
        addr := fmt.Sprintf("%s",conn.RemoteAddr())
        delete(onlineConns,addr) // 把斷開的鏈接從字典中去掉
        conn.Close()
        for i := range onlineConns{  // 打印一下
            fmt.Println("online"+i)
        }
        }(conn)
    for {
        numofbyte, err := conn.Read(buf) // 讀數(shù)據(jù)并賦值
        if err != nil {
            break // 報(bào)錯(cuò)退出
        }
        if numofbyte != 0 { // 讀到了數(shù)據(jù)長度如果不等于0

            msg := string(buf[:numofbyte]) //打印數(shù)據(jù),注意之前發(fā)的數(shù)據(jù)因?yàn)楦牡氖荹]byte,存在未被覆蓋的字節(jié)信息,所以這里切一下
            msgQue <- msg   // 這里放到channel中
        }
    }
}

func Checkerror1(err error) {
    if err != nil {
        panic(err)
    }
}

func doProcessMessage(mesa string){
    content := strings.Split(mesa,"#")  // 把字符串ip序號#消息進(jìn)行分割
    if len(content) >1 {   //如果有消息
        addr := content[0]
        sendMessage := strings.Join(content[1:],"#")  // 這里為了防止消息中有另外的#
        if conn,ok := onlineConns[addr]; ok{    // 看是前面的ip否在消息隊(duì)列中
            _, err := conn.Write([]byte(sendMessage))   //如果在的話寫入
            if err != nil{
                fmt.Println("wrong")
            }
        }
    }
}

func ConsumeMessage() {  // 這個(gè)consume用select用來監(jiān)控兩個(gè)channel如果quitchan有消息就退出,如果不是就處理消息進(jìn)行分發(fā)
    for {
        select {
        case mssage := <-msgQue: //解析
            doProcessMessage(mssage) // 消息處理,并進(jìn)行分發(fā)
        case <-quitChan:
            break
        }
    }
}

func main() {
    logfile, err := os.OpenFile("LOG_DIRECORY", os.O_RDWR|os.O_CREATE,0) // 打開文件
    if err != nil{
        fmt.Println("log file create failure!")
        os.Exit(-1)
    }
    defer logfile.Close()
    logger = log.New(logfile,"\r\n",log.Ldate|log.Ltime|log.Llongfile)

    logger.Println("llkjklj") // 輸入log

    listen_s, err := net.Listen("tcp", "127.0.0.1:8080") // 開啟一個(gè)socket
    Checkerror1(err)
    defer listen_s.Close() // 結(jié)束關(guān)socket

    fmt.Println("server is waiting..")
    go ConsumeMessage()
    for {
        conn, err := listen_s.Accept() // socket 接鏈接
        Checkerror1(err)
        addr := fmt.Sprintf("%s",conn.RemoteAddr()) // 把這個(gè)轉(zhuǎn)換一下到string中
        onlineConns[addr] = conn
        go ProcessInfo(conn) // 處理數(shù)據(jù)
    }

}

 

 

package main
import (
    "fmt"
    "net"
    "bufio"
    "os"
    "strings"
)

func MessageSend(conn net.Conn)  {
    var input string
    for {
        reader := bufio.NewReader(os.Stdin)  // 標(biāo)準(zhǔn)輸入
        data, _,_ := reader.ReadLine()   // 讀到數(shù)據(jù)到data
        input = string(data)
        if strings.ToUpper(input) == "EXIT" {   // 如果寫的是exit就退出
            conn.Close()
            break
        }
        _, err := conn.Write([]byte(input))   // 發(fā)消息
        if err != nil {    // 報(bào)錯(cuò)退出
            conn.Close()
            fmt.Println("Clinet connect fail")
            break
        }
    }
}

func Checkerror( err error){
    if err != nil {
        panic(err)
    }
}

func main(){
    conn, err := net.Dial("tcp","127.0.0.1:8080") // 連接socket
    Checkerror(err)
    defer conn.Close()
    MessageSend(conn)   // 發(fā)消息
    buf := make([]byte,1024)
    for {
        _, err := conn.Read(buf)   // 讀消息
        if err != nil{
            fmt.Println("exit")
            os.Exit(0)  // 正常退出
        }
        fmt.Println(string(buf))
    }
}
客戶端