23.1 仅实现服务端 简单版并发服务器的实现。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) //读取用户数据
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版):
文章图片
发送一句话就结束了!
服务端:
文章图片
服务端等待其他用户连接。
改进:
一次连接要能发送多次消息。
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):
文章图片
服务端:
文章图片
停不下来了......
客户端2(netcat):
文章图片
服务端:
文章图片
多用户(并发)连接实现了!
改进:
客户端可以选择退出来。
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):
文章图片
服务端:
文章图片
没退出来!怎么回事?
改进:
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):
文章图片
服务端:
文章图片
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端打开:
文章图片
注:在windows平台,回车键是"\r\n",是两个字符。
新浪微博:古老医麦
【Golang——23_网络编程实战】技术交流论坛:http://www.yinchengxueyuan.com/forum.php
推荐阅读
- 【golang】leetcode中级-字母异位词分组&无重复字符的最长子串
- 彻底理解Golang Map
- kratos线上开源年会它来啦~
- 深入浅出 Golang 资源嵌入方案(go-bindata篇)
- 深入浅出 Golang 资源嵌入方案(前篇)
- golang 经典案例总结
- Go实战 | 基于有向无环图的并发执行流的实现
- Golang 数组和切片
- Go JSON编码与解码()
- golang map基础知识