23 网络编程实战(并发服务器)
简单版并发服务器的实现。
package main
import (
"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 main
import (
"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 main
import (
"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 main
import (
"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):
服务端:
服务端:
package main
import (
"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 main
import (
"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 main
import (
"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 main
import (
"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",是两个字符。
新浪微博:古老医麦
技术交流论坛:http://www.yinchengxueyuan.com/forum.php