ZYNQ PS HTML服务器和客户端

zynq ps放个html,从windows电脑浏览器打开这个html带发生按钮发送字符串,然后ps再运行一个linux c程序接收并打印字符串,linux C收到回发一个字符串到html界面进行显示。

整体实现思路

  1. 通信架构:C 程序作为简易 HTTP 服务器,监听指定端口(如 8080);HTML 页面通过 AJAX(Fetch API)向该服务器发送 POST 请求(带字符串),并接收服务器的响应字符串。

  2. 运行环境:确保 Zynq 的 Linux 系统开启了对应端口的访问权限,Windows 电脑与 Zynq 处于同一局域网,能通过 Zynq 的 IP 访问。

  3. 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 浏览器操作

  1. 打开浏览器(Chrome/Edge/Firefox),输入地址:http://[Zynq IP]:8080/index.html(替换为实际 IP)。
  2. 在输入框中输入任意字符串,点击 "发送" 按钮,即可看到:
    • Zynq 的 C 程序终端打印收到的字符串;
    • 浏览器页面显示 C 程序回发的字符串。
相关推荐
康小庄2 小时前
Java自旋锁与读写锁
java·开发语言·spring boot·python·spring·intellij-idea
NO12122 小时前
使用paddle OCR对带文字的图片转正
python
墨染青竹梦悠然2 小时前
基于Django+vue的单词学习平台
前端·vue.js·后端·python·django·毕业设计·毕设
喵手2 小时前
Python爬虫实战:实现 Playwright 的动态名言“瀑布流”采集器,采集名言内容、作者及出处等信息(附 JSON 格式数据导出)!
爬虫·python·爬虫实战·playwright·零基础python爬虫教学·构建动态名言瀑布流采集器·采集数据json导出
喵手2 小时前
Python爬虫实战:全国旅游景区名录智能采集系统 - 构建文旅大数据的基石(附CSV导出 + SQLite持久化存储)!
爬虫·python·爬虫实战·零基础python爬虫教学·全国旅游景区名采集系统·文旅大数据·采集旅游景区sqlite存储
E_ICEBLUE4 小时前
Python 实现 PDF 表单域的自动化创建与智能填充
python·pdf·自动化·表单域
YJlio10 小时前
1.7 通过 Sysinternals Live 在线运行工具:不下载也能用的“云端工具箱”
c语言·网络·python·数码相机·ios·django·iphone
l1t10 小时前
在wsl的python 3.14.3容器中使用databend包
开发语言·数据库·python·databend