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

时间:2015-09-23 21:35:56

标签: c sockets http

我正在写一个网络服务器的准系统,但我无法弄清楚为什么我的文件不能通过我的套接字发送,我连接到它和它的一切只是没有send()我的档案......我错过了什么?

//代码(server.c)

#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>    

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

   if ((create_socket = socket(AF_INET, SOCK_STREAM, 0)) > 0){    
      printf("The socket was created\n");
   }

   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)) == 0){    
      printf("Binding Socket\n");
   }

    long fsize;
    FILE *fp = fopen("index.html", "r");
    fseek(fp, 0, SEEK_END);
    fsize = ftell(fp);
    rewind(fp);
    char *msg = malloc(fsize + 1);
    fread(msg, sizeof(msg), 1, fp);

   while (1) {    
      if (listen(create_socket, 10) < 0) {    
         perror("server: listen");    
         exit(1);    
      }    

      if ((new_socket = accept(create_socket, (struct sockaddr *) &address, &addrlen)) < 0) {    
         perror("server: accept");    
         exit(1);    
      }    

      if (new_socket > 0){    
         printf("The Client is connected...\n");
      }

        recv(new_socket, buffer, bufsize, 0);    
        printf("%s\n", buffer);    
        write(new_socket, "HTTP/1.1 200 OK\n", 16);
        write(new_socket, "Content-length: 46\n", 19);
        write(new_socket, "Content-Type: text/html\n\n", 25);
/*      write(new_socket, "<html><body><H1>Hello world</H1></body></html>",46); */
        if((send(new_socket, msg, fsize+1, 0)) > 0){
            printf("success");
        }     
        else{
            printf("failed");
        }
      close(new_socket);    
   }    
   close(create_socket);    
   return 0;    
}

// FILE (index.html)*同一目录

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

4 个答案:

答案 0 :(得分:6)

由于十几种不同的原因,代码完全已损坏。尝试更像这样的东西:

remote:        Running: bundle install --without development:test --path     vendor/bundle --binstubs vendor/bundle/bin -j4 --deployment 
remote:        Fetching gem metadata from https://rubygems.org/...........
remote:        Fetching version metadata from https://rubygems.org/...
remote:        Fetching dependency metadata from https://rubygems.org/..
remote:        Could not find net-ssh-2.10.0 in any of the sources
remote:        Bundler Output: Fetching gem metadata from    https://rubygems.org/...........
remote:        Fetching version metadata from https://rubygems.org/...
remote:        Fetching dependency metadata from https://rubygems.org/..
remote:        Could not find net-ssh-2.10.0 in any of the sources
remote:  !
remote:  !     Failed to install gems via Bundler.

答案 1 :(得分:1)

fsize = ftell(fp);
rewind(fp);
char *filebuff = malloc(fsize + 1);

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

fread(filebuff, sizeof(filebuff), 1, fp);

未选中的返回值。第二个参数应为fsize。目前你只传递sizeof指针。

//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);    
    }

listen()调用应该在循环之前,而不是在循环内部。这是您第一次真正处理失败案例。

    new_sock = accept(sock, (struct sockaddr *) &address, &addrlen);            
    recv(new_socket, buffer, bufsize, 0);    
    printf("%s\n", buffer);    

无效。未选中的返回代码。缓冲区仅在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

    if(send(new_sock, filebuff, fsize+1, 0) > 0){
        printf("success");
    }     
    else{
        printf("failed");
    }

不足。如果您在任何系统调用中收到错误消息,则必须在错误消息中调用perror()或使用errnostrerror()。 “失败”没有传达有用的信息,调试变成了猜测游戏。不要写这样的代码。您应该使用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。

答案 2 :(得分:0)

除了在各个地方使用的错误大小(如数学家1975所述),你的“真实”问题是你试图与需要HTTP服务器的浏览器进行通信。

H yper T 分机 T 转发 P rotocol,嗯,a protocol。它比简单连接和内容转储更复杂。

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

答案 3 :(得分:0)

检查addrlen是否失败并报告是否失败。你绑定到端口80;在类Unix操作系统下,只有root可以绑定到保留端口(小于1024)。

更新1:

在致电sizeof(address)之前,您必须先将accept()初始化为{{1}}。来自http://linux.die.net/man/2/accept

  

addrlen参数是一个value-result参数:调用者必须   初始化它以包含指向的结构的大小(以字节为单位)   通过addr;返回时它将包含对等体的实际大小   地址。