现在已经完成了客户端与服务端的通信,但是服务端只能接收一个用户发送过来的数据,怎样接收多个客户端发送过来的数据,实现一个高效的并发服务器呢?
Accept()函数的作用是等待客户端的链接,如果客户端没有链接,该方法会阻塞。如果有客户端链接,那么该方法返回一个Socket负责与客户端进行通信。所以,每来一个客户端,该方法就应该返回一个Socket与其通信,因此,可以使用一个死循环,将Accept()调用过程包裹起来。
需要注意的是,实现并发处理多个客户端数据的服务器,就需要针对每一个客户端连接,单独产生一个Socket,并创建一个单独的goroutine与之完成通信。
package main
import (
"net"
"fmt"
)
func Handle(conn net.Conn) {
buf:=make([]byte,4096)
n,err:=conn.Read(buf)
if err!=nil{
fmt.Println("read err",err)
return
}
messsage:=buf[:n]
fmt.Println("%d服务器端发来信息%s",conn.RemoteAddr(),messsage)
}
func main() {
listen, err := net.Listen("tcp", "127.0.0.1")
if err != nil {
fmt.Println("listen err", err)
return
}
defer listen.Close()
for {
conn,err:=listen.Accept()
if err!=nil{
fmt.Println("accept err",err)
return
}
go Handle(conn)
}
}
客户端不仅需要持续的向服务端发送数据,同时也要接收从服务端返回的数据。因此可将发送和接收放到不同的协程中。
主协程循环接收服务器回发的数据(该数据应已转换为大写),并打印至屏幕;子协程循环从键盘读取用户输入数据,写给服务器。读取键盘输入可使用 os.Stdin.Read(str)。定义切片str,将读到的数据保存至str中。
这样,客户端也实现了多任务。
客户端代码实现:
package main
import (
"net"
"fmt"
"os"
)
func main() {
conn, err := net.Dial("tcp", "127.0.0.1")
if err != nil {
fmt.Println("dial err", err)
return
}
defer conn.Close()
go func() {
buf := make([]byte, 4096)
for {
n, err := os.Stdin.Read(buf)
if err != nil {
fmt.Println("read err", err)
}
conn.Write(buf[:n])
}
}()
read := make([]byte, 4096)
n, err := conn.Read(read)
if err != nil {
fmt.Println("read err", err)
return
}
fmt.Println("从服务器中读取数据%s", string(read[:n]))
}
其实对于UDP而言,服务器不需要并发,只要循环处理客户端数据即可。客户端也等同于TCP通信并发的客户端。
服务器:
package main
import (
"net"
"fmt"
)
func main() {
// 创建 服务器 UDP 地址结构。指定 IP + port
laddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:8003")
if err != nil {
fmt.Println("ResolveUDPAddr err:", err)
return
}
// 监听 客户端连接
conn, err := net.ListenUDP("udp", laddr)
if err != nil {
fmt.Println("net.ListenUDP err:", err)
return
}
defer conn.Close()
for {
buf := make([]byte, 1024)
n, raddr, err := conn.ReadFromUDP(buf)
if err != nil {
fmt.Println("conn.ReadFromUDP err:", err)
return
}
fmt.Printf("接收到客户端[%s]:%s", raddr, string(buf[:n]))
conn.WriteToUDP([]byte("I-AM-SERVER"), raddr) // 简单回写数据给客户端
}
}
客户端
ackage main
import (
"net"
"fmt"
"os"
)
func main() {
conn, err := net.Dial("udp", "127.0.0.1")
if err != nil {
fmt.Println("dial err", err)
return
}
defer conn.Close()
go func() {
buf := make([]byte, 4096)
for {
n, err := os.Stdin.Read(buf)
if err != nil {
fmt.Println("read err", err)
}
conn.Write(buf[:n])
}
}()
read := make([]byte, 4096)
n, err := conn.Read(read)
if err != nil {
fmt.Println("read err", err)
return
}
fmt.Println("从服务器中读取数据%s", string(read[:n]))
}