Client端
package main
import (
"fmt"
"net"
"os"
"syscall"
"unsafe"
)
func main() {
// 创建多个网络连接
conn1, _ := net.Dial("tcp", "localhost:8000")
conn2, _ := net.Dial("tcp", "localhost:8001")
conn3, _ := net.Dial("tcp", "localhost:8002")
//获取文件描述符
fd1 := getFD(conn1)
fd2 := getFD(conn2)
fd3 := getFD(conn3)
// 将多个网络连接的文件描述符添加到fdset中
fdset := syscall.FdSet{}
var bits = unsafe.Sizeof(fdset.Bits[0]) * 8
fdset.Bits[(fd1)/bits] |= 1 << (fd1 % bits)
fdset.Bits[(fd2)/bits] |= 1 << (fd2 % bits)
fdset.Bits[(fd3)/bits] |= 1 << (fd3 % bits)
// 使用select系统调用实现IO多路复用
for {
newFdset := fdset
err := syscall.Select(int(fd3+1), &newFdset, nil, nil, nil)
if err != nil {
fmt.Println("Error:", err)
return
}
for fd := 0; fd <= int(fd3); fd++ {
if !FD_ISSET(fd, newFdset) {
continue
}
switch fd {
case int(fd1):
handleConn(uintptr(fd))
break
case int(fd2):
handleConn(uintptr(fd))
break
case int(fd3):
handleConn(uintptr(fd))
break
}
}
}
}
func FD_ISSET(fd int, fdSet syscall.FdSet) bool {
return ((fdSet.Bits[(fd)/32] >> (fd) % 32) & 1) != 0
}
func getFD(conn net.Conn) uintptr {
file, err := conn.(*net.TCPConn).File()
if err != nil {
fmt.Println("Error getting file descriptor:", err)
os.Exit(1)
}
return file.Fd()
}
func handleConn(fd uintptr) {
fmt.Println(fd)
data := make([]byte, 1024)
n, err := syscall.Read(int(fd), data)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("Read data:", string(data[:n]))
}
Server端
起三个不同端口的server
package main
import (
"bufio"
"fmt"
"net"
"os"
"strings"
)
func main() {
go server("8000")
for {
}
}
func server(port string) {
// 创建一个TCP服务器
listener, err := net.Listen("tcp", fmt.Sprintf("localhost:%s", port))
if err != nil {
fmt.Println("Error listening:", err.Error())
return
}
defer listener.Close()
fmt.Println("Server started, listening on port 8888...")
for {
// 等待客户端连接
conn, err := listener.Accept()
if err != nil {
fmt.Println("Error accepting:", err.Error())
return
}
// 处理客户端请求
go HandleRequest(conn)
}
}
func HandleRequest(conn net.Conn) {
// 2、使用 conn 连接进行数据的发送和接收
input := bufio.NewReader(os.Stdin)
for {
s, _ := input.ReadString('\n')
s = strings.TrimSpace(s)
if strings.ToUpper(s) == "Q" {
return
}
_, err := conn.Write([]byte(s))
if err != nil {
fmt.Printf("send failed, err:%v\n", err)
return
}
}
conn.Close()
}