html - 如何在不使用 libcurl 的情况下从本地主机服务器获取 URL

标签 html c server output

我制作了一个自定义 HTTP 服务器,该服务器提供一个带有一些文本的 HTML 页面、一个用于输入命令的输入文本框和一个提交按钮。收到表单提交后,服务器应该运行给定的命令并提供包含结果的响应。

我不太清楚的问题是如何获取表单提交请求的 URL,以便解析出要运行的命令。按照目前的实现,服务器在 localhost:3838 上运行,当客户端浏览到该 URL 时,服务器会正​​确响应表单。当用户在文本框中输入(比方说)命令 ls 并单击“运行”提交按钮时,将向 localhost:3838/run?command=ls。如何在服务器中获取该URL,从而解析出并执行命令?

这是当前的服务器代码:

CwebServer.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>

#define PORT "3838" //port being connected to 
#define MAXLEN 800
#define BACKLOG 10 //number of pending connections to be held in queue

//format of html page 

char header []= 
"HTTP/1.1 200 Ok\r\n"
"Content-Type: text/html; charset=UTF-8\r\n\r\n"
"<!DOCTYPE html>\r\n"
"<html>\n"
"<head>\n"
"<title>Web-Based Remote Command Server</title>\r\n"
"</head>\n"
"<body>\n\n";
char input []=
"<form action= \"/run\" method= \"GET\"> \n"
"Command: <input type=\"text\" size=\"100\" name=\"command\">\n"
"<input type=\"submit\" value=\"Run\">\n"
"</form>";
char output []=
"<p>Command that was run and testing this:</p>\n"
"<pre>Your server will include the command that was just run here.</pre>\n\n"
"<p>Standard Output:</p>\n""<pre>Your server will include the stdout results here.</pre>\n\n"
"<p>Standard Error:</p>\n"
"<pre>Your server will include the stderr results here.</pre>\r\n\r\n"
"</body>\r\n""</html>\r\n";

char *buff = header; 

void sigchld_handler(int s)
{
    (void)s; // quiet unused variable warning

    // waitpid() might overwrite errno, so we save and restore it:
    int saved_errno = errno;

    while(waitpid(-1, NULL, WNOHANG) > 0);

    errno = saved_errno;
}


void *get_in_addr(struct sockaddr *sa)
{
    if (sa->sa_family == AF_INET) {
        return &(((struct sockaddr_in*)sa)->sin_addr);
    }

    return &(((struct sockaddr_in6*)sa)->sin6_addr);
}


int main (void){
    int sockfd;
    int new_fd; 
    struct addrinfo hints;
    struct addrinfo *serverinfo; 
    struct addrinfo *p;
    struct sockaddr_storage client_addr;
    socklen_t addrsize;
    struct sigaction sa;
    int yes = 1;
    char s[INET6_ADDRSTRLEN];
    int status;

    memset(&hints, 0, sizeof hints); //makes struct empty 
    hints.ai_family = AF_UNSPEC; //IPv4 or v6 
    hints.ai_socktype = SOCK_STREAM; //TCP type need 
    hints.ai_flags = AI_PASSIVE; //Fill in IP for us 


    //if can't get address info print error 
    if((status = getaddrinfo(NULL, PORT, &hints, &serverinfo)) != 0){
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
        return 1;
    }


    for(p = serverinfo; p != NULL; p = p->ai_next){
        if((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1){
            perror("server: socket");
            continue;
        }

        if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1){
            perror("setsockopt");
            exit(1);
        }

        if(bind(sockfd, p->ai_addr, p->ai_addrlen) == -1){
            close(sockfd);
            perror("server: bind");
            continue;
        }

        break;
    }

    freeaddrinfo(serverinfo);

    if(p == NULL){
        fprintf(stderr, "server: failed to bind\n");
        exit(1);
    }

    if(listen(sockfd, BACKLOG) == -1){
        perror("listen");
        exit(1);
    }

    sa.sa_handler = sigchld_handler; // reap all dead processes
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;
    if (sigaction(SIGCHLD, &sa, NULL) == -1) {
        perror("sigaction");
        exit(1);
    }

    printf("server: waiting for connections....\n");

    while(1){
        addrsize = sizeof client_addr;
        new_fd = accept(sockfd, (struct sockaddr *)&client_addr, &addrsize);
        if(new_fd == -1){
            perror("Did not accept");
            continue;
        }

        inet_ntop(client_addr.ss_family, get_in_addr((struct sockaddr *)&client_addr), s, sizeof s);
        printf("server: got connection from %s\n", s);

        if(!fork()){
            close(sockfd);
            int bufsize = 1024;
            char *buffer = malloc(bufsize);
            send(new_fd, header, bufsize, 0);
            //write(new_fd, "HTTP/1.1 200 OK\n", 16);
            //write(new_fd, "Content-length: 46\n", 19);
            //write(new_fd, "Content-type: text/html\n\n", 25);
            //write(new_fd, "<html><head>\n<head>\n<title>The CAvengers Web Page</title>\n</head>\n</html>", 46);

            if(send(new_fd, buffer, MAXLEN, 0) == -1)
                perror("send");
            close(new_fd);
            exit(0);
        }
        close(new_fd);
    }

    return 0;


}

最佳答案

Web 服务器和客户端通过 HTTP 协议(protocol)进行通信。这就是使它们成为 web 服务器而不是其他类型服务器的原因。 HTTP 是一种请求/响应协议(protocol):客户端向服务器发送请求,其中包含有关其请求内容的信息,服务器处理该请求以确定如何响应。

您的特定服务器似乎打算实现 HTTP 1.1 .这不是最新版本的协议(protocol),但没关系。世界上几乎每个 HTTP 客户端都能理解这种方言。但是您的服务器是一个功能非常简单的服务器,它使用相同的 HTTP 响应响应每个已建立的连接,即使客户端实际上并未发送 HTTP 请求也是如此。

您的问题是如何获取请求 URI。答案是通过 accept() 返回的已连接套接字从客户端读取它。 read()recv() 函数将适用于此。您应该期望客户端使用的格式在我上面链接的 HTTP 规范中进行了描述,但在非常简而言之,您应该期望请求以请求方法名称 (GET),至少一个空格,请求 URI,和一个回车/换行符对。您将需要解析请求 URI 以区分表单的初始请求和表单提交,在后一种情况下,您还可以解析查询参数。

但是请注意,虽然 HTTP 是一个相对简单的协议(protocol),但它仍然比我刚才描述的要复杂得多。

关于html - 如何在不使用 libcurl 的情况下从本地主机服务器获取 URL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56043688/

相关文章:

javascript - 我可以只用 HTML5 实现这个功能吗?

javascript - HTML 文本区域调整大小事件

jquery滑动侧边栏从左到右

C++编译具有相同函数名的多个文件

c++ - "make"是否知道如何在子目录中搜索包含文件?

php - 防止直接 url 访问 php 文件

java - Android 应用程序可以创建本地 session ,其他使用同一应用程序的人无需中间服务器即可连接到该 session 吗?

python - 防止自动完成框出现

linux - 从shell脚本在另一台linux服务器上远程执行命令

编译器错误变量声明