最近在看GO语言,跟着教程一步一步手敲代码,拼出了个聊天室程序。其中涉及到了go语言中的go,defer,make,chan,select。了解了go中的变量类型以及部分的类型操作。同时,go语言的语言结构和逻辑控制也有了大概的初步认识。而且,也用到了go特有的语言性质。
断断续续那么长时间学习go了,今天才第一次写出个像样的程序。总是感觉程序大都一个样,真正上手才是王道。
创建一个聊天室服务端,chatroom_client.go
package main
import (
"fmt"
"net"
"strings"
)
//创建基于链接的哈希map,方便知道链接对应的端口号
var onlineConns = make(map[string]net.Conn)
//创建一个频道,长度1000.用来存储信息
var messageQueue = make(chan string, 1000)
//创建一个返回布尔值的频道,用来应对没有信息的情况
var quitChan = make(chan bool)
//检查错误,通用方法
func CheckError(err error) {
if err != nil {
panic(err)
}
}
//将消息存进频道中
func ProcessInfo(conn net.Conn){
buf := make([]byte , 1024) 创建个1024字节的字节流
defer conn.Close() //程序运行完毕时关闭链接
//循环体
for{
//从信息流读出消息
numOfBytes,err:= conn.Read(buf)
if err != nil{
panic(err)
}
//如果字节不等于零,就把消息字符化发到消息频道中
if numOfBytes != 0{
message := string(buf[0:numOfBytes])
messageQueue <- message
}
}
}
//消费消息
func ConsumeMessage(){
for{
//select是配合频道使用的,选择进哪个通信操作
select{
case message:=<-messageQueue:
//对消息进行解析
doProcessMessage(message)
case <- quitChan:
//空消息,什么都不做~
break
}
}
}
//对消息进行解析
func doProcessMessage(message string){
//将消息以“#”分开,如 127.0.0.1:3389#你好
//就把这个消息分成两段,一段为127.0.0.1:3389,一段为你好
//这里面没有考虑消息体里面包括#好的情况
contents := strings.Split(message,"#")
if len(contents) >1 {
addr := contents[0]
sendMessage := contents[1]
//将消息体格式化
addr =strings.Trim(addr, " ")
//判断哈希map中这个地址存不存在,存在就往这个链接里写消息体
if conn,ok := onlineConns[addr]; ok{
_,err := conn.Write([]byte(sendMessage))
if err != nil{
//不存在就写发送失败
fmt.Println("online conns send failure!!!!")
}
}
}
}
//主函数
func main(){
//监听127.0.0.1:8080端口。
listen_socket , err := net.Listen("tcp","127.0.0.1:8080")
CheckError(err)
//程序退出后监听关闭
defer listen_socket.Close()
//增加用户体验,让用户知道程序在运行中
fmt.Println("server is waitting...")
//开启协程来消费消息
go ConsumeMessage()
//无限循环,来监听消息并处理消息
for{
conn,err := listen_socket.Accept()
CheckError(err)
//打印出连接过来的远端地址
addr := fmt.Sprintf("%s", conn.RemoteAddr())
//将这个连接并存储到hashmap
onlineConns[addr] = conn
//循环hashmap,打印连接上来的连接
for i := range onlineConns{
fmt.Println(i)
}
//运行协程,将连接存到频道中。程序不停,此过程不断
go ProcessInfo(conn)
}
}
再创建一个客户端文件,chatroom_client.go
package main
import (
"bufio"
"fmt"
"net"
"os"
"strings"
)
func CheckError(err error) {
if err != nil {
panic(err)
}
}
//发送消息
func MessageSend(conn net.Conn) {
var input string
//无限循环,发送消息
for {
//监听输入将键入的信息记下来
reader := bufio.NewReader(os.Stdin)
//将记下来的消息以每行开始读
data, _, _ := reader.ReadLine()
//将data字符化存入到input
input = string(data)
//如果input为exit就退出,结束连接
if strings.ToUpper(input) == "EXIT" {
conn.Close()
break
} else {
//否则,往这个连接中写入字节流
_, err := conn.Write([]byte (input))
if err != nil {
conn.Close()
fmt.Println("client connect failure" + err.Error())
}
}
}
}
func main() {
//连接8080端口
conn, err := net.Dial("tcp", "127.0.0.1:8080")
CheckError(err)
defer conn.Close()
//开启协程发送消息,无限循环的
go MessageSend(conn)
//创建1024长度的字节流
buf := make([]byte, 1024)
//无限循环,读取字节流信息并打印
for {
_, err := conn.Read(buf)
CheckError(err)
fmt.Println("server receive message content: " + string(buf))
}
fmt.Println("client program done")
}
以上程序可以运行起来了。先go run chatroom_server.go。之后再起两个client。server中能看到连接上来的两个ip:port。在client中输入ip:port#文字。就可以在对应的client看到发送过来的信息了。