Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/60.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
通过TCP/IP套接字发送文件(web服务器)_C_Sockets_Http - Fatal编程技术网

通过TCP/IP套接字发送文件(web服务器)

通过TCP/IP套接字发送文件(web服务器),c,sockets,http,C,Sockets,Http,我正在编写一个web服务器的基本框架,但我不明白为什么我的文件不能通过我的套接字发送,我正在连接到它,它只是不发送我的文件。。。我错过了什么 //代码服务器.c //文件index.html*同一目录 <html> <body> <h1>Hello World</h1> </body> </html> 除了数学家1975年指出的在不同地方使用的错误大小之外,您真正的问题是您试图与需要HTTP服务器的浏览器通信 超文

我正在编写一个web服务器的基本框架,但我不明白为什么我的文件不能通过我的套接字发送,我正在连接到它,它只是不发送我的文件。。。我错过了什么

//代码服务器.c

//文件index.html*同一目录

<html>
<body>
    <h1>Hello World</h1>
</body>
</html>

除了数学家1975年指出的在不同地方使用的错误大小之外,您真正的问题是您试图与需要HTTP服务器的浏览器通信

超文本传输协议是。它比简单的连接和内容转储更复杂

您必须根据请求解析请求,并以某种方式发送标题和内容。

检查绑定是否失败,如果失败,请报告。您正在绑定到端口80;在类Unix操作系统下,只有root用户可以绑定到小于1024的保留端口

更新1:

在调用accept之前,必须将addrlen初始化为sizeofaddress。发件人:

addrlen参数是一个值结果参数:调用方必须 初始化它以包含指向的结构的大小(以字节为单位) 地址为:;返回时,它将包含对等的实际大小 地址

为什么fsize+1?你不需要+1

未选中的返回值。第二个参数应该是fsize。目前,您只传递指针的大小

//create/bind socket
if ((create_socket = socket(AF_INET, SOCK_STREAM, 0)) > 0)
{    
  printf("The socket was created\n");
}
如果套接字创建失败,您必须a打印一条正确的错误消息,如下所述,b而不是像没有发生错误一样继续执行

if (bind(create_socket, (struct sockaddr *) &address, sizeof(address)) == 0)
{    
  printf("Binding Socket\n");
}

同上

//listen, create new_sock, write headers, send file 
while (1){   
   if (listen(create_socket, 10) < 0) {    
       perror("server: listen");    
       exit(1);    
    }
无效。未选中的返回代码。只有当recv返回一个正整数时,缓冲区才是有效的,并且只有它的许多字节是有效的。应该是:

    int count = recv(new_socket, buffer, bufsize, 0);    
    printf("%.*s\n", count, buffer);    
然后我们从HTTP开始:

    write(new_sock, "HTTP/1.1 200 OK\n", 16);
    write(new_sock, "Content-length: 46\n", 19);
    write(new_sock, "Content-Type: text/html\n\n", 25);
HTTP中的行终止符是从Telnet继承的,它被指定为\r\n而不是\n

不充分。如果从任何系统调用中得到错误,则必须调用perror,或在错误消息中使用errno或strerror。失败不会传递任何有用的信息,调试只会变成一个猜测游戏。不要这样写代码。对于上面所有其他未检查的返回值,您应该使用perror或您决定的任何值

但还有一个更大的问题。您假设该文件适合内存。没有必要这样假设。只需使用8k缓冲区复制文件,如下所示:

int count;
while ((count = read(in, buffer, sizeof buffer)) > 0)
{
    send(out, buffer, count, 0);
}
if (count < 0)
{
    perror("send failed");
}
我会避免使用stdio,因为它有太多的问题,比如设计糟糕的fread和fwrite函数api。

由于十几个不同的原因,代码完全被破坏了。请尝试类似以下内容:

#include <netinet/in.h>    
#include <stdio.h>    
#include <stdlib.h>    
#include <sys/socket.h>    
#include <sys/stat.h>    
#include <sys/types.h>    
#include <unistd.h>    

bool writeDataToClient(int sckt, const void *data, int datalen)
{
    const char *pdata = (const char*) data;

    while (datalen > 0){
        int numSent = send(sckt, pdata, datalen, 0);
        if (numSent <= 0){
            if (numSent == 0){
                printf("The client was not written to: disconnected\n");
            } else {
                perror("The client was not written to");
            }
            return false;
        }
        pdata += numSent;
        datalen -= numSent;
    }

    return true;
}

bool writeStrToClient(int sckt, const char *str)
{
    return writeDataToClient(sckt, str, strlen(str));
}

int main(void){
    int create_socket, new_socket;    
    char *buffer;
    int bufsize = 1024;    
    struct sockaddr_in address;    
    socklen_t addrlen;    

    buffer = (char*) malloc(bufsize);    
    if (!buffer){
        printf("The receive buffer was not allocated\n");
        exit(1);    
    }

    create_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (create_socket == -1){    
        perror("The socket was not created");    
        exit(1);    
    }

    printf("The socket was created\n");

    memset(&address, 0, sizeof(address));    
    address.sin_family = AF_INET;    
    address.sin_addr.s_addr = INADDR_ANY;    
    address.sin_port = htons(80);    

    if (bind(create_socket, (struct sockaddr *) &address, sizeof(address)) == -1){    
        perror("The socket was not bound");    
        exit(1);    
    }

    printf("The socket is bound\n");    

    long fsize;
    FILE *fp = fopen("index.html", "rb");
    if (!fp){
        perror("The file was not opened");    
        exit(1);    
    }

    printf("The file was opened\n");

    if (fseek(fp, 0, SEEK_END) == -1){
        perror("The file was not seeked");
        exit(1);
    }

    fsize = ftell(fp);
    if (fsize == -1) {
        perror("The file size was not retrieved");
        exit(1);
    }
    rewind(fp);

    char *msg = (char*) malloc(fsize);
    if (!msg){
        perror("The file buffer was not allocated\n");
        exit(1);
    }

    if (fread(msg, fsize, 1, fp) != 1){
        perror("The file was not read\n");
        exit(1);
    }
    fclose(fp);

    printf("The file size is %ld\n", fsize);

    if (listen(create_socket, 10) == -1){
        perror("The socket was not opened for listening");    
        exit(1);    
    }    

    printf("The socket is listening\n");

    while (1) {    

        addrlen = sizeof(address);
        new_socket = accept(create_socket, (struct sockaddr *) &address, &addrlen);

        if (new_socket == -1) {    
            perror("A client was not accepted");    
            exit(1);    
        }    

        printf("A client is connected from %s:%hu...\n", inet_ntoa(address.sin_addr), ntohs(address.sin_port));    

        // I will leave it as an exercise for you to implement
        // a proper HTTP request parser here...
        int numRead = recv(new_socket, buffer, bufsize, 0);
        if (numRead < 1){
            if (numRead == 0){
                printf("The client was not read from: disconnected\n");
            } else {
                perror("The client was not read from");
            }
            close(new_socket);
            continue;
        }
        printf("%.*s\n", numRead, buffer);    

        if (!writeStrToClient(new_socket, "HTTP/1.1 200 OK\r\n")){
            close(new_socket);
            continue;
        }

        char clen[40];
        sprintf(clen, "Content-length: %ld\r\n", fsize);
        if (!writeStrToClient(new_socket, clen)){
            close(new_socket);
            continue;
        }

        if (!writeStrToClient(new_socket, "Content-Type: text/html\r\n")){
            close(new_socket);
            continue;
        }

        if (!writeStrToClient(new_socket, "Connection: close\r\n\r\n") == -1){
            close(new_socket);
            continue;
        }

        //if (!writeStrToClient(new_socket, "<html><body><H1>Hello world</H1></body></html>")){
        if (!writeDataToClient(new_socket, msg, fsize)){
            close(new_socket);
            continue;
        }

        printf("The file was sent successfully\n");
        close(new_socket);    
   }    

   close(create_socket);    
   return 0;    
}

是的,这就是我认为是标题。。。。在发送fileindex.html之前,先在套接字上写这些文件行吗?@jordavis阅读了有关协议的内容。这个答案太长,无法表达,但网上有很多信息。我知道协议,我不是一个十足的白痴:,让服务器将html作为字符串发送,但现在我尝试将其作为文件发送时失败了。。我的猜测是,在发送包含html的缓冲区之前,我需要将标题发送到套接字。。。或者我需要在发送缓冲区之前将标题写入缓冲区?大图片,是的,标题在内容之前。但是,如果你真的打算认真对待这件事,那就多读一些关于protocol@JordanDavis:TCP是一种流式传输。您可以根据需要多次发送,数据将根据需要在网络层上进行缓冲。重要的是你发送的内容。我知道这不是因为我之前让它处理一个HTML字符串,而且编译器在bind上没有失败。我只是更新了我的代码,添加了值。。。为了清楚起见,我把支票留了下来,我把它写在这个问题的顶部……谢谢你输入@ejpt这个裸体服务器有很多问题,一点也不好笑。您没有很好地处理错误。您正在以文本模式而不是二进制模式打开文件。SizeOfMg是错误的,请使用fsize。我不建议将整个文件读入内存,而是将其分块读取并发送,否则以后将无法处理大型文件。你调用listen的次数太多了,只调用一次,而不是循环调用。您没有检查recv是否失败。。。。。。在发送回复之前,您根本没有试图解析客户机的正确性请求。您必须在回复标题中使用\r\n而不是\n。您的Content length标头未指定文件的实际fsize值不是46字节。您无法确保send成功发送所有请求的字节。发送fsize+1字节是错误的,因为该文件只有fsize字节数。并且没有连接:正在发送关闭标头。@Jordandavi不,您没有。您刚刚添加了成功报告。在这段代码中几乎没有任何故障处理。@jordavis:显然,他没有。代码完全错了,原因有十几个。@jordavis:我刚刚发了一个examp
但是你忽略了fread的返回值,如果read返回零,你就调用perror,这是无效的。我没有忽略fread的返回值,但是你说的recv的返回值是对的,我没有调用read。我已经修正了。我对代码做了一些调整。请重试编译。@Pilpel:在本例中不需要,因为它是硬编码的,只使用IPv4,只在INADR\U ANY上侦听。使用getaddrinfo将在中生成相同的sockaddr_,除非启用IPv6,在这种情况下,需要分配多个具有多个绑定的套接字,否则getaddrinfo是有意义的。或者您可以创建一个双堆栈套接字来同时处理IPv4和IPv6,在这种情况下,您将不再使用getaddrinfo。@Pilpel:它可以用于服务器端,但在客户端更有用
    int count = recv(new_socket, buffer, bufsize, 0);    
    printf("%.*s\n", count, buffer);    
    write(new_sock, "HTTP/1.1 200 OK\n", 16);
    write(new_sock, "Content-length: 46\n", 19);
    write(new_sock, "Content-Type: text/html\n\n", 25);
    if(send(new_sock, filebuff, fsize+1, 0) > 0){
        printf("success");
    }     
    else{
        printf("failed");
    }
int count;
while ((count = read(in, buffer, sizeof buffer)) > 0)
{
    send(out, buffer, count, 0);
}
if (count < 0)
{
    perror("send failed");
}
#include <netinet/in.h>    
#include <stdio.h>    
#include <stdlib.h>    
#include <sys/socket.h>    
#include <sys/stat.h>    
#include <sys/types.h>    
#include <unistd.h>    

bool writeDataToClient(int sckt, const void *data, int datalen)
{
    const char *pdata = (const char*) data;

    while (datalen > 0){
        int numSent = send(sckt, pdata, datalen, 0);
        if (numSent <= 0){
            if (numSent == 0){
                printf("The client was not written to: disconnected\n");
            } else {
                perror("The client was not written to");
            }
            return false;
        }
        pdata += numSent;
        datalen -= numSent;
    }

    return true;
}

bool writeStrToClient(int sckt, const char *str)
{
    return writeDataToClient(sckt, str, strlen(str));
}

int main(void){
    int create_socket, new_socket;    
    char *buffer;
    int bufsize = 1024;    
    struct sockaddr_in address;    
    socklen_t addrlen;    

    buffer = (char*) malloc(bufsize);    
    if (!buffer){
        printf("The receive buffer was not allocated\n");
        exit(1);    
    }

    create_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (create_socket == -1){    
        perror("The socket was not created");    
        exit(1);    
    }

    printf("The socket was created\n");

    memset(&address, 0, sizeof(address));    
    address.sin_family = AF_INET;    
    address.sin_addr.s_addr = INADDR_ANY;    
    address.sin_port = htons(80);    

    if (bind(create_socket, (struct sockaddr *) &address, sizeof(address)) == -1){    
        perror("The socket was not bound");    
        exit(1);    
    }

    printf("The socket is bound\n");    

    long fsize;
    FILE *fp = fopen("index.html", "rb");
    if (!fp){
        perror("The file was not opened");    
        exit(1);    
    }

    printf("The file was opened\n");

    if (fseek(fp, 0, SEEK_END) == -1){
        perror("The file was not seeked");
        exit(1);
    }

    fsize = ftell(fp);
    if (fsize == -1) {
        perror("The file size was not retrieved");
        exit(1);
    }
    rewind(fp);

    char *msg = (char*) malloc(fsize);
    if (!msg){
        perror("The file buffer was not allocated\n");
        exit(1);
    }

    if (fread(msg, fsize, 1, fp) != 1){
        perror("The file was not read\n");
        exit(1);
    }
    fclose(fp);

    printf("The file size is %ld\n", fsize);

    if (listen(create_socket, 10) == -1){
        perror("The socket was not opened for listening");    
        exit(1);    
    }    

    printf("The socket is listening\n");

    while (1) {    

        addrlen = sizeof(address);
        new_socket = accept(create_socket, (struct sockaddr *) &address, &addrlen);

        if (new_socket == -1) {    
            perror("A client was not accepted");    
            exit(1);    
        }    

        printf("A client is connected from %s:%hu...\n", inet_ntoa(address.sin_addr), ntohs(address.sin_port));    

        // I will leave it as an exercise for you to implement
        // a proper HTTP request parser here...
        int numRead = recv(new_socket, buffer, bufsize, 0);
        if (numRead < 1){
            if (numRead == 0){
                printf("The client was not read from: disconnected\n");
            } else {
                perror("The client was not read from");
            }
            close(new_socket);
            continue;
        }
        printf("%.*s\n", numRead, buffer);    

        if (!writeStrToClient(new_socket, "HTTP/1.1 200 OK\r\n")){
            close(new_socket);
            continue;
        }

        char clen[40];
        sprintf(clen, "Content-length: %ld\r\n", fsize);
        if (!writeStrToClient(new_socket, clen)){
            close(new_socket);
            continue;
        }

        if (!writeStrToClient(new_socket, "Content-Type: text/html\r\n")){
            close(new_socket);
            continue;
        }

        if (!writeStrToClient(new_socket, "Connection: close\r\n\r\n") == -1){
            close(new_socket);
            continue;
        }

        //if (!writeStrToClient(new_socket, "<html><body><H1>Hello world</H1></body></html>")){
        if (!writeDataToClient(new_socket, msg, fsize)){
            close(new_socket);
            continue;
        }

        printf("The file was sent successfully\n");
        close(new_socket);    
   }    

   close(create_socket);    
   return 0;    
}