在现代软件开发中,多语言集成变得越来越普遍。Go(Golang)以其高效的并发处理和强大的网络编程能力受到广泛欢迎,而C语言则以其高效的底层控制和性能著称。有时我们需要在 Go 应用中调用已有的 C 库函数,为此我们可以使用 CGO 这个强大的工具。
下面是我实现的一个示例,通过 Go 语言与 C 语言进行 FFI(外部函数接口)集成,并创建一个能够通过网页按钮进行操作的简单 Web 应用。
项目结构
首先,让我们明确一下项目的目录结构:
project/
├── myclib.c # C语言源文件
├── myclib.h # C语言头文件
├── libmyclib.a # 编译生成的C语言静态库文件
├── main.go # Go语言主程序
└── static/
└── index.html # HTML客户端页面
项目开发
1. 编写C语言库
我们将编写一个简单的 C 语言函数,并将其编译成静态库。
下面是一个简单的 C 函数,并通过它打印一条信息。
myclib.h
#ifndef MYCLIB_H
#define MYCLIB_H
void say_hello();
#endif
myclib.c
#include "myclib.h"
#include <stdio.h>
void say_hello() {
printf("Hello from C library!\n");
}
2. 编译C语言库
我们需要先编译 C 源文件,生成静态库文件:
gcc -c -o myclib.o myclib.c
ar rcs libmyclib.a myclib.o
注:可通过 CMD,也可以通过 IDE 中的终端进行编译。
这会在当前目录下生成 libmyclib.a 静态库文件。
3. 编写Go语言代码
我们将通过 CGO 在 Go 程序中调用上述 C 函数,并通过 Go 的 HTTP 包提供一个简单的 Web 服务。
main.go
package main
/*
#cgo CFLAGS: -I.
#cgo LDFLAGS: -L. -lmyclib
#include "myclib.h"
*/
import "C"
import (
"fmt"
"net/http"
)
// use Go to invoke C
func callCFunction(w http.ResponseWriter, r *http.Request) {
C.say_hello()
fmt.Fprintf(w, "Called C function successfully!\n")
}
func main() {
// configure routing
http.HandleFunc("/call_c", callCFunction)
// provide static file services
http.Handle("/", http.FileServer(http.Dir("static")))
fmt.Println("Server started at http://localhost:8080")
if err := http.ListenAndServe(":8080", nil); err != nil {
fmt.Println("Failed to start server:", err)
}
}
在这里,我们通过 CGO 链接了先前编译的 C 静态库,并在 HTTP 路由中设置了 /call_c 路径来调用 C 语言函数。
4. 创建HTML客户端
我们使用 HTML 和 JavaScript 来创建一个客户端页面,能够通过按钮点击发起 HTTP 请求并调用我们的 Go 函数,这个 Go 函数会调用 C 函数。
static/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>FFI测试</title>
<script>
function callCFunction() {
fetch('/call_c')
.then(response => response.text())
.then(data => alert(data))
.catch(error => alert("Error: " + error));
}
</script>
</head>
<body>
<button onclick="callCFunction()">Call C Function</button>
</body>
</html>
5. 运行应用
确保项目是在同一个目录下有编译产生的 C 语言库文件(即:libmyclib.a),然后运行 Go 代码:
go run main.go
此时,我们可以打开浏览器访问:
http://localhost:8080
如图所示:
在界面中会看到一个按钮。
点击这个按钮后会执行一次 HTTP 请求,请求到达 Go 服务器后,Go 服务器调用 C 函数并返回结果,最后在客户端弹出提示框显示结果。如图所示:
回到终端,我们可以看到在服务运行链接下面出现了新的连接成功输出语句:
如果我们后面有更复杂的需求,可以在此基础上继续扩展和优化。