zynq ps放个html,从windows电脑浏览器打开这个html带发生按钮发送字符串,然后ps再运行一个linux c程序接收并打印字符串,linux C收到回发一个字符串到html界面进行显示。
整体实现思路
-
通信架构:C 程序作为简易 HTTP 服务器,监听指定端口(如 8080);HTML 页面通过 AJAX(Fetch API)向该服务器发送 POST 请求(带字符串),并接收服务器的响应字符串。
-
运行环境:确保 Zynq 的 Linux 系统开启了对应端口的访问权限,Windows 电脑与 Zynq 处于同一局域网,能通过 Zynq 的 IP 访问。
-
HTML 代码(运行在 Zynq PS 端,命名为index.html)
这个 HTML 页面包含输入框、发送按钮,以及显示接收内容的区域,通过 Fetch API 与 C 服务器通信。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Zynq PS 字符串交互</title>
<style>
body { margin: 20px; font-family: Arial; }
.container { max-width: 400px; }
input { width: 250px; padding: 8px; margin: 10px 0; }
button { padding: 8px 16px; background: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer; }
button:hover { background: #0056b3; }
#response { margin-top: 20px; padding: 10px; border: 1px solid #ccc; min-height: 50px; }
</style>
</head>
<body>
<div class="container">
<h3>字符串发送与接收</h3>
<input type="text" id="sendInput" placeholder="输入要发送的字符串">
<button onclick="sendString()">发送</button>
<div>
<p>服务器返回内容:</p>
<div id="response">等待响应...</div>
</div>
</div>
<script>
// 替换为你的Zynq PS的实际IP地址(如192.168.1.100)
const SERVER_IP = "192.168.1.100";
const SERVER_PORT = 8080;
// 发送字符串到C服务器
function sendString() {
const input = document.getElementById("sendInput");
const responseDiv = document.getElementById("response");
const sendStr = input.value.trim();
if (!sendStr) {
alert("请输入要发送的字符串!");
return;
}
// 使用Fetch API发送POST请求
fetch(`http://${SERVER_IP}:${SERVER_PORT}`, {
method: "POST",
headers: {
"Content-Type": "text/plain; charset=utf-8",
},
body: sendStr // 发送的字符串内容
})
.then(response => {
if (!response.ok) {
throw new Error("服务器响应失败");
}
return response.text(); // 接收服务器返回的字符串
})
.then(data => {
responseDiv.textContent = data; // 显示返回内容
console.log("收到服务器返回:", data);
})
.catch(error => {
responseDiv.textContent = "通信失败:" + error.message;
console.error("通信错误:", error);
});
}
</script>
</body>
</html>
HTML 代码关键说明
SERVER_IP:必须替换为你 Zynq PS 的实际 IP(可在 Zynq Linux 中用ifconfig查看)。Fetch API:实现异步 HTTP POST 请求,向 C 服务器发送输入的字符串,并接收响应。- 页面布局:简洁的输入框、按钮和响应显示区域,适配浏览器操作。
2. Linux C 程序(简易 HTTP 服务器,命名为server.c)
这个 C 程序基于 TCP 套接字实现简易 HTTP 服务器,监听 8080 端口,接收浏览器的 POST 请求(提取字符串),打印后返回自定义字符串。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 8080 // 监听端口
#define BUFFER_SIZE 1024 // 缓冲区大小
#define MAX_CLIENTS 1 // 单客户端处理
// 提取HTTP POST请求中的正文(发送的字符串)
char* extract_post_body(const char* request) {
// HTTP POST请求头和正文之间有一个空行(\r\n\r\n),以此分割
const char* body_start = strstr(request, "\r\n\r\n");
if (body_start == NULL) {
return strdup(""); // 无正文返回空字符串
}
body_start += 4; // 跳过\r\n\r\n
return strdup(body_start); // 复制正文内容并返回
}
int main() {
int server_fd, new_socket;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
char buffer[BUFFER_SIZE] = {0};
char response[BUFFER_SIZE] = {0};
// 1. 创建套接字文件描述符
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
// 2. 设置套接字选项(复用端口/地址)
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
perror("setsockopt");
exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY; // 监听所有网卡
address.sin_port = htons(PORT);
// 3. 绑定套接字到端口8080
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
// 4. 开始监听(最大等待连接数为MAX_CLIENTS)
if (listen(server_fd, MAX_CLIENTS) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
printf("服务器启动成功,监听端口:%d\n", PORT);
printf("等待客户端连接...\n");
while (1) { // 循环接收客户端连接
// 5. 接受客户端连接
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
perror("accept");
continue;
}
// 打印客户端信息
printf("\n===== 新客户端连接 =====\n");
printf("客户端IP:%s,端口:%d\n", inet_ntoa(address.sin_addr), ntohs(address.sin_port));
// 6. 读取客户端发送的HTTP请求
ssize_t valread = read(new_socket, buffer, BUFFER_SIZE);
if (valread < 0) {
perror("read failed");
close(new_socket);
continue;
}
buffer[valread] = '\0'; // 确保字符串结束
// 7. 提取POST请求中的字符串正文
char* post_body = extract_post_body(buffer);
printf("收到客户端发送的字符串:%s\n", post_body);
// 8. 构造响应内容(返回给HTML页面)
snprintf(response, sizeof(response),
"服务器已接收:%s | 回发字符串:%s",
post_body, "Hello from Zynq Linux!");
// 9. 构造HTTP响应头(必须包含,否则浏览器无法解析)
char http_response[BUFFER_SIZE * 2];
snprintf(http_response, sizeof(http_response),
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain; charset=utf-8\r\n"
"Content-Length: %zu\r\n"
"Access-Control-Allow-Origin: *\r\n" // 允许跨域(关键)
"\r\n"
"%s",
strlen(response), response);
// 10. 发送响应给客户端(HTML页面)
send(new_socket, http_response, strlen(http_response), 0);
printf("已向客户端回发:%s\n", response);
// 11. 释放资源并关闭连接
free(post_body);
close(new_socket);
printf("===== 连接关闭 =====\n");
memset(buffer, 0, sizeof(buffer)); // 清空缓冲区
}
// 关闭服务器套接字(实际不会执行到这里,因为while(1)循环)
close(server_fd);
return 0;
}
C 代码关键说明
- HTTP 协议适配:必须构造标准 HTTP 响应头(包含状态码、Content-Type、跨域允许等),否则浏览器会拒绝解析响应。
Access-Control-Allow-Origin: *:关键!允许 Windows 浏览器跨域访问 Zynq 的服务器,否则会报跨域错误。extract_post_body函数:从 HTTP POST 请求中提取纯字符串正文(跳过请求头)。- 循环监听:程序启动后持续监听端口,支持多次发送请求。
Windows 浏览器操作
- 打开浏览器(Chrome/Edge/Firefox),输入地址:
http://[Zynq IP]:8080/index.html(替换为实际 IP)。 - 在输入框中输入任意字符串,点击 "发送" 按钮,即可看到:
- Zynq 的 C 程序终端打印收到的字符串;
- 浏览器页面显示 C 程序回发的字符串。