Golang——23_网络编程实战

23 网络编程实战(并发服务器)
23.1 仅实现服务端 简单版并发服务器的实现。
package mainimport ( "fmt" "net" "strings" )func main(){ //监听 listener,err:=net.Listen("tcp","127.0.0.1:8000") if err != nil{ fmt.Println("err = ",err) return } defer listener.Close() //接收多个用户 for ; ; { conn,err:=listener.Accept() if err!=nil { fmt.Println("err = ",err) continue }//处理用户请求,为每个用户新建一个协程 go HandleConn(conn) } }func HandleConn(conn net.Conn){ //函数调用完毕,自动关闭conn defer conn.Close() //获取客户端的网络地址信息 addr:=conn.RemoteAddr().String() fmt.Println("Connects successfully.\n") buf := make([]byte,2048) //读取用户数据 n,err:=conn.Read(buf) if err!=nil { fmt.Println("err = ",err) return } fmt.Printf("[%s]: %s",addr,string(buf[:n])) conn.Write([]byte(strings.ToUpper(string(buf[:n]))))}

客户端(netcat版):
Golang——23_网络编程实战
文章图片


发送一句话就结束了!

服务端:
Golang——23_网络编程实战
文章图片


服务端等待其他用户连接。

改进:
一次连接要能发送多次消息。
package mainimport ( "fmt" "net" "strings" )func main(){ //监听 listener,err:=net.Listen("tcp","127.0.0.1:8000") if err != nil{ fmt.Println("err = ",err) return } defer listener.Close() //接收多个用户 for ; ; { conn,err:=listener.Accept() if err!=nil { fmt.Println("err = ",err) continue }//处理用户请求,为每个用户新建一个协程 go HandleConn(conn) } }func HandleConn(conn net.Conn){ //函数调用完毕,自动关闭conn defer conn.Close() //获取客户端的网络地址信息 addr:=conn.RemoteAddr().String() fmt.Println("Connects successfully.\n") buf := make([]byte,2048) for ; ; { //读取用户数据 n,err:=conn.Read(buf) if err!=nil { fmt.Println("err = ",err) return } fmt.Printf("[%s]: %s",addr,string(buf[:n]))conn.Write([]byte(strings.ToUpper(string(buf[:n])))) } }

客户端(netcat):
Golang——23_网络编程实战
文章图片


服务端:
Golang——23_网络编程实战
文章图片


停不下来了......

客户端2(netcat):
Golang——23_网络编程实战
文章图片


服务端:

Golang——23_网络编程实战
文章图片


多用户(并发)连接实现了!

改进:
客户端可以选择退出来。

package mainimport ( "fmt" "net" "strings" )func main(){ //监听 listener,err:=net.Listen("tcp","127.0.0.1:8000") if err != nil{ fmt.Println("err = ",err) return } defer listener.Close() //接收多个用户 for ; ; { conn,err:=listener.Accept() if err!=nil { fmt.Println("err = ",err) continue }//处理用户请求,为每个用户新建一个协程 go HandleConn(conn) } }func HandleConn(conn net.Conn){ //函数调用完毕,自动关闭conn defer conn.Close() //获取客户端的网络地址信息 addr:=conn.RemoteAddr().String() fmt.Println("Connects successfully.\n") buf := make([]byte,2048) for ; ; { //读取用户数据 n,err:=conn.Read(buf) if err!=nil { fmt.Println("err = ",err) return } fmt.Printf("[%s]: %s",addr,string(buf[:n]))if "exit"==string(buf[:n]) { fmt.Println(addr," exits.") return }conn.Write([]byte(strings.ToUpper(string(buf[:n])))) }}

客户端(netcat):
Golang——23_网络编程实战
文章图片


服务端:

Golang——23_网络编程实战
文章图片


没退出来!怎么回事?
改进:
package mainimport ( "fmt" "net" "strings" )func main(){ //监听 listener,err:=net.Listen("tcp","127.0.0.1:8000") if err != nil{ fmt.Println("err = ",err) return } defer listener.Close() //接收多个用户 for ; ; { conn,err:=listener.Accept() if err!=nil { fmt.Println("err = ",err) continue }//处理用户请求,为每个用户新建一个协程 go HandleConn(conn) } }func HandleConn(conn net.Conn){ //函数调用完毕,自动关闭conn defer conn.Close() //获取客户端的网络地址信息 addr:=conn.RemoteAddr().String() fmt.Println("Connects successfully.\n") buf := make([]byte,2048) for ; ; { //读取用户数据 n,err:=conn.Read(buf) if err!=nil { fmt.Println("err = ",err) return } fmt.Printf("[%s]: %s",addr,string(buf[:n]))if "exit"==string(buf[:n-1]) { fmt.Println(addr," exits.") return }conn.Write([]byte(strings.ToUpper(string(buf[:n])))) }}

客户端(netcat):
Golang——23_网络编程实战
文章图片


服务端:
Golang——23_网络编程实战
文章图片




23.2 自己写客户端和服务端 服务端:
package mainimport ( "fmt" "net" "strings" )func main(){ //监听 listener,err:=net.Listen("tcp","127.0.0.1:8000") if err != nil{ fmt.Println("net.Listen err = ",err) return } defer listener.Close() //接收多个用户 for ; ; { conn,err:=listener.Accept() if err!=nil { fmt.Println("listener.Accept err = ",err) continue } //处理用户请求,为每个用户新建一个协程 go HandleConn(conn) } }func HandleConn(conn net.Conn){ //函数调用完毕,自动关闭conn defer conn.Close() //获取客户端的网络地址信息 addr:=conn.RemoteAddr().String() fmt.Println("Connect successfully.") buf := make([]byte,1024) for ; ; { //读取用户数据 n,err:=conn.Read(buf) if err!=nil { fmt.Println("conn.Read err = ",err) return } fmt.Printf("[%s]: %s\n",addr,string(buf[:n]))if "exit"==string(buf[:n-1]) { //nc测试时 //if "exit"==string(buf[:n]) { fmt.Println(addr," exits.") return } conn.Write([]byte(strings.ToUpper(string(buf[:n])))) }}

客户端:
package mainimport ( "fmt" "net" "os" "bufio" )func main(){ //主动连接服务器 conn,err:=net.Dial("tcp","127.0.0.1:8000") if err!=nil{ fmt.Println("net.Dial err : ",err) return } //main调用完,关闭连接 defer conn.Close() //接收服务器回复的数据 go func() { buf:=make([]byte,1024) for ; ; { n,err:=conn.Read(buf) //接收服务器的请求 if err!=nil { fmt.Println("conn.Read err = ",err) return } fmt.Printf("msg : %s",string(buf[:n])) //打印接收到的内容 } }() //从键盘输入内容,给服务器发送数据 //str := make([]byte,1024) for ; ; { //n,err:=os.Stdin.Read(str) //从键盘读取内容,放在str //fmt.Println("for test,n:",n) inputReader := bufio.NewReader(os.Stdin)//创建一个读取器,并将其与标准输入绑定 fmt.Printf("Please input: ") theInput, err := inputReader.ReadString('\n') //读取器对象提供一个方法 ReadString(delim byte) ,该方法从输入中读取内容,直到碰到 delim 指定的字符,然后将读取到的内容连同 delim 字符一起放到缓冲区。 //fmt.Println(len(theInput)) if err!=nil { fmt.Println("os.Stdin.Read err : ",err) continue } if theInput=="exit\n" { break } //把输入的内容发送给服务器 conn.Write([]byte(theInput)) }}


第二个版本
服务器:
package mainimport ( "fmt" "net" "strings" )func main(){ //监听 listener,err:=net.Listen("tcp","127.0.0.1:8000") if err != nil{ fmt.Println("net.Listen err = ",err) return } defer listener.Close() //接收多个用户 for ; ; { conn,err:=listener.Accept() if err!=nil { fmt.Println("listener.Accept err = ",err) continue } //处理用户请求,为每个用户新建一个协程 go HandleConn(conn) } }func HandleConn(conn net.Conn){ //函数调用完毕,自动关闭conn defer conn.Close() //获取客户端的网络地址信息 addr:=conn.RemoteAddr().String() fmt.Println("Connect successfully.") buf := make([]byte,1024) for ; ; { //读取用户数据 n,err:=conn.Read(buf) if err!=nil { fmt.Println("conn.Read err = ",err) return } fmt.Printf("[%s]: %s\n",addr,string(buf[:n]))if "exit"==string(buf[:n-2]) { //nc测试时 //if "exit"==string(buf[:n]) { fmt.Println(addr," exits.") return } conn.Write([]byte(strings.ToUpper(string(buf[:n])))) }}

客户端:
package mainimport ( "fmt" "net" "os" )func main() { //主动连接服务器 conn, err := net.Dial("tcp", "127.0.0.1:8000") if err != nil { fmt.Println("net.Dial err : ", err) return } //main调用完,关闭连接 defer conn.Close() //接收服务器回复的数据 go func() {for ; ; { //从键盘输入内容,给服务器发送数据 str := make([]byte,1024) n,err:=os.Stdin.Read(str) //从键盘读取内容,放在str fmt.Println("for test,n:",n) //inputReader := bufio.NewReader(os.Stdin) //创建一个读取器,并将其与标准输入绑定 //fmt.Printf("Please input: ") //theInput, err := inputReader.ReadString('\n') //读取器对象提供一个方法 ReadString(delim byte) ,该方法从输入中读取内容,直到碰到 delim 指定的字符,然后将读取到的内容连同 delim 字符一起放到缓冲区。 //fmt.Println(len(theInput)) if err != nil { fmt.Println("os.Stdin.Read err : ", err) return } //把输入的内容发送给服务器 conn.Write([]byte(str[:n])) } }() buf := make([]byte, 1024) for ; ; { n, err := conn.Read(buf) //接收服务器的请求 if err != nil { fmt.Println("conn.Read err = ", err) return } fmt.Printf("msg : %s", string(buf[:n])) //打印接收到的内容 }}

这次尝试在cmd端打开:
Golang——23_网络编程实战
文章图片




注:在windows平台,回车键是"\r\n",是两个字符。




新浪微博:古老医麦

【Golang——23_网络编程实战】技术交流论坛:http://www.yinchengxueyuan.com/forum.php

    推荐阅读