funcListen(ipstring,portint)(*Socket,error){socket:=&Socket{}socketFileDescriptor,err:=syscall.Socket(syscall.AF_INET,syscall.SOCK_STREAM,0)iferr!=nil{returnnil,fmt.Errorf("failed to create socket (%v)",err)}socket.FileDescriptor=socketFileDescriptorsocketAddress:=&syscall.SockaddrInet4{Port:port}copy(socketAddress.Addr[:],net.ParseIP(ip))iferr=syscall.Bind(socket.FileDescriptor,socketAddress);err!=nil{returnnil,fmt.Errorf("failed to bind socket (%v)",err)}iferr=syscall.Listen(socket.FileDescriptor,syscall.SOMAXCONN);err!=nil{returnnil,fmt.Errorf("failed to listen on socket (%v)",err)}returnsocket,nil}
func(eventLoop*EventLoop)Handle(handlerHandler){for{newEvents:=make([]syscall.Kevent_t,10)numNewEvents,err:=syscall.Kevent(eventLoop.KqueueFileDescriptor,nil,newEvents,nil)iferr!=nil{continue}fori:=0;i<numNewEvents;i++{currentEvent:=newEvents[i]eventFileDescriptor:=int(currentEvent.Ident)ifcurrentEvent.Flags&syscall.EV_EOF!=0{// client closing connection
syscall.Close(eventFileDescriptor)}elseifeventFileDescriptor==eventLoop.SocketFileDescriptor{// new incoming connection
socketConnection,_,err:=syscall.Accept(eventFileDescriptor)iferr!=nil{continue}socketEvent:=syscall.Kevent_t{Ident:uint64(socketConnection),Filter:syscall.EVFILT_READ,Flags:syscall.EV_ADD,Fflags:0,Data:0,Udata:nil,}socketEventRegistered,err:=syscall.Kevent(eventLoop.KqueueFileDescriptor,[]syscall.Kevent_t{socketEvent},nil,nil)iferr!=nil||socketEventRegistered==-1{continue}}elseifcurrentEvent.Filter&syscall.EVFILT_READ!=0{// data available -> forward to handler
handler(&socket.Socket{FileDescriptor:int(eventFileDescriptor)})}// ignore all other events
}}}
funcmain(){s,err:=socket.Listen("127.0.0.1",8080)iferr!=nil{log.Println("Failed to create Socket:",err)os.Exit(1)}eventLoop,err:=kqueue.NewEventLoop(s)iferr!=nil{log.Println("Failed to create event loop:",err)os.Exit(1)}log.Println("Server started. Waiting for incoming connections. ^C to exit.")eventLoop.Handle(func(s*socket.Socket){reader:=bufio.NewReader(s)for{line,err:=reader.ReadString('\n')iferr!=nil||strings.TrimSpace(line)==""{break}s.Write([]byte(line))}s.Close()})}
处理函数会根据换行符逐行读取数据内容,直到它读取到空行,然后会关闭连接。
我们可以通过 curl 来测试,curl 将会发送一个 GET 请求,并输出响应的内容,响应内容其实就是它发送的 GET 请求体的内容。