【问题标题】:Server displaying text instead of HTML服务器显示文本而不是 HTML
【发布时间】:2019-09-25 03:00:53
【问题描述】:

我正在尝试制作一个 C 服务器,它将接受输入并能够通过 html 格式将它们吐回给用户,服务器作为用户界面工作。 我目前似乎无法弄清楚的问题是为什么 C 服务器在 localhost:3838 处将 HTML 代码作为文本吐出,而不是将其显示为正确的网页。

我该如何解决这个问题并让它能够将用户命令发送回服务器并吐出正确的响应?我是否可以通过使用recieve 然后将消息放入缓冲区,解析该消息,然后将该响应放入缓冲区以使用send 发回?

CSERVER.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 []= 
"<!DOCTYPE html>\n"
"<html>\n"
"<head>\n"
"<title>Web-Based Remote Command Server</title>\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:</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>\n\n"
"</body>\n""</html>";

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);
recv(new_fd, buffer, 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<title>The Web Page</title>\n</head>\n</html>", 46);
            if(send(new_fd, header, MAXLEN, 0) == -1)
                perror("send");
            close(new_fd);
            exit(0);
        }
        close(new_fd);
    }

    return 0;


}

【问题讨论】:

  • 只是为了澄清一些您感到困惑的事情:服务器不显示任何 HTML 内容。这就是浏览器的工作。服务器仅通过 TCP/IP 传送 HTML 内容(或其他内容)。 HTML 是纯文本。因此,服务器将您的内容发送到客户端使用的端口是正确的。
  • 您只发送一个标头。您的 HTML 页面似乎包含的不止这些。如果浏览器只接收 HTML 页面的一部分,即无效的 HTML,它可能只显示源文本。
  • 另外:如果您的标头缓冲区不那么长,为什么要发送 800 个字节? send(new_fd, header, MAXLEN, 0);
  • 只是作为一个缓冲区,但我想我认为我正在发送所有这些现在是有意义的,所以如果我将它全部包含在“标题”中,那么它可能会起作用吗?另外我想我现在更好地理解了如何显示实际的网页,但是如何解析输入和输出呢?

标签: html c input server localhost


【解决方案1】:

您需要像这样添加响应标头:

例如,SO为此页面发送的响应头是:

HTTP/2.0 200 OK
cache-control: private
content-type: text/html; charset=utf-8
content-encoding: gzip
x-frame-options: SAMEORIGIN
x-request-guid: 599a5768-3cc6-4b94-86e1-e1d1daa8acd5
strict-transport-security: max-age=15552000
content-security-policy: upgrade-insecure-requests
accept-ranges: bytes
date: Tue, 07 May 2019 13:17:15 GMT
via: 1.1 varnish
x-served-by: cache-lcy19237-LCY
x-cache: MISS
x-cache-hits: 0
x-timer: S1557235035.073229,VS0,VE89
vary: Accept-Encoding,Fastly-SSL
x-dns-prefetch-control: off
content-length: 35669
X-Firefox-Spdy: h2

【讨论】:

  • 尝试用 write 做类似的事情,但不确定我是否需要多行写入,或者我可以将它们全部合二为一吗?
  • 行间需要 CRLF。
  • CRLF?很抱歉在我这样做的时候学习。把它弄到我可以更改标题或正文但不能同时更改的地方。
猜你喜欢
  • 2016-03-06
  • 1970-01-01
  • 2016-01-26
  • 2022-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-19
  • 2013-01-04
相关资源
最近更新 更多