-
Notifications
You must be signed in to change notification settings - Fork 221
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PortPool: add check port before alloc #72
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,49 +27,107 @@ SOFTWARE. | |
*/ | ||
package main | ||
|
||
import "fmt" | ||
import ( | ||
"fmt" | ||
"net" | ||
"strconv" | ||
) | ||
|
||
// The port pool manage available ports. | ||
// PortPool The port pool manage available ports. | ||
type PortPool struct { | ||
shell *ShellBoss | ||
// alloc new port from ports, fill ports from left, | ||
// release to ports when free port. | ||
// Alloc new port from ports. Alloc new port from the head of the list. | ||
// Release to ports when free port. | ||
// If check failed, put the port to the tail of the list | ||
ports []int | ||
left []int | ||
// The ports in use. fill used when alloc | ||
used []int | ||
} | ||
|
||
// alloc port in [start,stop] | ||
// NewPortPool alloc port in [start,stop] | ||
func NewPortPool(start, stop int) *PortPool { | ||
v := &PortPool{} | ||
v.ports = make([]int, stop-start+1) | ||
for i := start; i <= stop; i++ { | ||
if len(v.ports) < 64 { | ||
v.ports = append(v.ports, i) | ||
} else { | ||
v.left = append(v.left, i) | ||
} | ||
v.ports[i-start] = i | ||
} | ||
return v | ||
} | ||
|
||
func (v *PortPool) Alloc(nbPort int) (ports []int, err error) { | ||
// allocOnePort alloc a port from the port pool | ||
func (v *PortPool) allocOnePort() (int, error) { | ||
if len(v.ports) <= 0 { | ||
return 0, fmt.Errorf("empty port pool") | ||
} | ||
|
||
for i, p := range v.ports { | ||
if checkPort(p) { | ||
// delete i-index element | ||
v.ports = append(v.ports[:i], v.ports[i+1:]...) | ||
v.used = append(v.used, p) | ||
return p, nil | ||
} | ||
} | ||
|
||
return 0, fmt.Errorf("No available port") | ||
} | ||
|
||
// Alloc alloc nbPort ports from the port pool | ||
func (v *PortPool) Alloc(nbPort int) ([]int, error) { | ||
if nbPort <= 0 { | ||
return nil, fmt.Errorf("invalid ports %v", nbPort) | ||
} | ||
if len(v.ports)+len(v.left) < nbPort { | ||
return nil, fmt.Errorf("no %v port available, left %v", nbPort, len(v.ports)+len(v.left)) | ||
} | ||
|
||
if len(v.ports) < nbPort { | ||
cp := nbPort - len(v.ports) | ||
v.ports = append(v.ports, v.left[0:cp]...) | ||
v.left = v.left[cp:] | ||
return nil, fmt.Errorf("no %v port available, left %v", nbPort, len(v.ports)) | ||
} | ||
|
||
ports = v.ports[0:nbPort] | ||
v.ports = v.ports[nbPort:] | ||
return | ||
ports := []int{} | ||
for i := 0; i < nbPort; i++ { | ||
p, err := v.allocOnePort() | ||
if err != nil { | ||
return nil, err | ||
} else { | ||
ports = append(ports, p) | ||
} | ||
} | ||
return ports, nil | ||
} | ||
|
||
// Free free port from the port pool | ||
func (v *PortPool) Free(port int) { | ||
v.ports = append(v.ports, port) | ||
// Free used ports to the head of the ports list for better port reused. | ||
v.ports = append([]int{port}, v.ports...) | ||
for i, p := range v.used { | ||
if port == p { | ||
// delete i-index element | ||
v.used = append(v.used[:i], v.used[i+1:]...) | ||
return | ||
} | ||
} | ||
} | ||
|
||
// GetPortsInUse get a list of port in use | ||
func (v *PortPool) GetPortsInUse() []int { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 为何要export这个函数? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 另外,case 有failed:https://circleci.com/gh/ossrs/go-oryx/16 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 一般的一个程序会占用一个端口, 启动时会配置进去, nc这个项目会占用多个端口, 而且是动态分配的, 需要提供个接口来查询哪些端口被占用了. 这样能了解当前系统占用了哪些端口. |
||
return v.used | ||
} | ||
|
||
// checkPort check if a port is available | ||
func checkPort(port int) bool { | ||
// Concatenate a colon and the port | ||
host := ":" + strconv.Itoa(port) | ||
|
||
// Try to create a server with the port | ||
listener, err := net.Listen("tcp", host) | ||
|
||
// if it fails then the port is likely taken | ||
if err != nil { | ||
return false | ||
} | ||
|
||
// close the server | ||
listener.Close() | ||
|
||
// we successfully used and closed the port | ||
// so it's now available to be used again | ||
return true | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个地方可以改成:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个 used 变量可以方便增加一个方法, 打印出我当前在使用哪些 port.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
我增加了一个方法 GetPortsInUse() 可以获取当前使用中的 port
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
为什么需要暴露这个函数呢:GetPortsInUse,这个是给谁用的?