Golang实现从共享库运行服务器的方案

Golang实现从共享库运行服务器的方案 尝试从共享库运行服务器,因此我执行了以下步骤:

  1. 编写共享库如下:
// server.go
package main

import (
	"fmt"
	"net/http"
)
import "C"

func hello(w http.ResponseWriter, req *http.Request) {
	fmt.Fprintf(w, "hello\n")
}
func headers(w http.ResponseWriter, req *http.Request) {
	for name, headers := range req.Header {
		for _, h := range headers {
			fmt.Fprintf(w, "%v: %v\n", name, h)
		}
	}
}
func main() {}

// export Run server
func Run(port string) {
	http.HandleFunc("/hello", hello)
	http.HandleFunc("/headers", headers)
	if err := http.ListenAndServe("localhost:"+port, nil); err == nil {
		fmt.Println("listening to 8090")
	} else {
		fmt.Println("ListenAndServe: ", err)
	}
}
  1. 编译共享库如下:
$ go build -buildmode c-shared -o server.so server.go
  1. 编写调用共享库中 Run 函数的主文件如下:
//main.go
package main

/*
#cgo LDFLAGS: -ldl
#include <dlfcn.h>

void Run(char* port){}

*/
import "C"

func main() {
	// handle := C.dlopen(C.CString("server.so"), C.RTLD_LAZY)
	// C.dlsym(handle, C.CString("8090"))

	C.dlopen(C.CString("server.so"), C.RTLD_LAZY)
	C.run(C.CString("8090"))
}
  1. 运行主文件如下:
$ go run main.go

主函数直接终止了,服务器并未在 http://localhost:8090/hello 地址上运行。


更多关于Golang实现从共享库运行服务器的方案的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

你似乎是在非 Windows 系统上运行,因此我建议研究一下 plugin 包。

更多关于Golang实现从共享库运行服务器的方案的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


你的方案存在几个关键问题。以下是修正后的实现:

  1. 共享库需要正确导出函数:
// server.go
package main

import (
	"fmt"
	"net/http"
)

import "C"

//export Run
func Run(port *C.char) {
	http.HandleFunc("/hello", hello)
	http.HandleFunc("/headers", headers)
	
	goPort := C.GoString(port)
	addr := "localhost:" + goPort
	
	fmt.Printf("Starting server on %s\n", addr)
	if err := http.ListenAndServe(addr, nil); err != nil {
		fmt.Printf("ListenAndServe error: %v\n", err)
	}
}

func hello(w http.ResponseWriter, req *http.Request) {
	fmt.Fprintf(w, "hello\n")
}

func headers(w http.ResponseWriter, req *http.Request) {
	for name, headers := range req.Header {
		for _, h := range headers {
			fmt.Fprintf(w, "%v: %v\n", name, h)
		}
	}
}

func main() {}

编译共享库:

go build -buildmode=c-shared -o server.so server.go
  1. 主程序需要正确加载和调用共享库函数:
// main.go
package main

/*
#cgo LDFLAGS: -ldl
#include <dlfcn.h>
#include <stdlib.h>

typedef void (*RunFunc)(char*);

void callRun(void* handle, char* port) {
    RunFunc run = (RunFunc)dlsym(handle, "Run");
    if (run != NULL) {
        run(port);
    }
}
*/
import "C"

import (
	"fmt"
	"unsafe"
)

func main() {
	// 加载共享库
	libPath := C.CString("./server.so")
	defer C.free(unsafe.Pointer(libPath))
	
	handle := C.dlopen(libPath, C.RTLD_LAZY)
	if handle == nil {
		fmt.Printf("Failed to load library: %s\n", C.GoString(C.dlerror()))
		return
	}
	defer C.dlclose(handle)
	
	// 调用Run函数
	port := C.CString("8090")
	defer C.free(unsafe.Pointer(port))
	
	C.callRun(handle, port)
	
	// 保持主程序运行
	select {}
}
  1. 或者使用更简洁的cgo直接调用方式:
// main_simple.go
package main

/*
#cgo LDFLAGS: -L. -lserver
#include <stdlib.h>

extern void Run(char* port);
*/
import "C"

import (
	"time"
)

func main() {
	port := C.CString("8090")
	defer C.free(unsafe.Pointer(port))
	
	C.Run(port)
	
	// 保持程序运行
	for {
		time.Sleep(time.Hour)
	}
}

编译并运行:

# 编译共享库
go build -buildmode=c-shared -o libserver.so server.go

# 运行主程序
go run main.go

关键修正点:

  1. 使用 //export Run 注释正确导出函数
  2. 在C代码中声明函数指针类型并正确调用dlsym
  3. 主程序需要保持运行(使用select{}或for循环)
  4. 添加必要的错误处理
  5. 使用goroutine安全的字符串转换

服务器将在 http://localhost:8090/hello 正常运行。

回到顶部