Golang——23_网络编程实战

23 网络编程实战(并发服务器)

23.1 仅实现服务端

        简单版并发服务器的实现。

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版):

Golang——23_网络编程实战_第1张图片

        发送一句话就结束了!

服务端:

Golang——23_网络编程实战_第2张图片

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

改进:

        一次连接要能发送多次消息。

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):

Golang——23_网络编程实战_第3张图片

服务端:

Golang——23_网络编程实战_第4张图片

        停不下来了......

客户端2(netcat):

Golang——23_网络编程实战_第5张图片

服务端:

Golang——23_网络编程实战_第6张图片

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

改进:

        客户端可以选择退出来。

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):

Golang——23_网络编程实战_第7张图片

服务端:

Golang——23_网络编程实战_第8张图片

        没退出来!怎么回事?

改进:

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):

Golang——23_网络编程实战_第9张图片

服务端:

Golang——23_网络编程实战_第10张图片


23.2 自己写客户端和服务端

服务端:

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端打开:

Golang——23_网络编程实战_第11张图片


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


新浪微博:古老医麦

技术交流论坛:http://www.yinchengxueyuan.com/forum.php


你可能感兴趣的:(Golang)