从文件中读取并输出到套接字

时间:2014-03-02 13:41:55

标签: c file sockets http file-io

所以我正在研究一个读取文件并将其内容输出到套接字的方法。

但是,我的浏览器显示了以下内容,而不是我的简单index.html文件:

#öÇdÿ GÊdÿ(˜ÊdÿÎ+Yÿ@0Çdÿ  ŸÊdÿÐÎ+YÿÍ×ÇdÿHÌÊdÿèÌÊdÿ@Î+YÿlñÇdÿ ŸÊdÿ8öŒÿ¶¢ð‘ÿÎ+YÿòXÈdÿ GÊdÿ ŸÊdÿؾÊdÿâ@”ÐÎ+YÿŠÈdÿ Ð+Yÿ ŸÊdÿ ²Êdÿâ@”Ï+YÿŠÈdÿ Ð+YؾÊdÿ°0ÊdÿؾÊdÿ°0Êdÿ°0Êdÿ ŸÊdÿ`Ï+Yÿ¡Èdÿ°0Êdÿ ŸÊdÿ°0Êdÿâ@” Ð+Yÿ°Ï+YÿcbÈdÿ Ð+Yÿ¼À‡¨Qµpÿ8A”ë@”p0” ŸÊdÿPÐ+Yÿ¨ ®ÿ «ª2Ð+Yÿ©$®ÿ„Ð+Yÿ€Ð+Yÿ|Ð+Yÿ†Æuÿ€¸†Æuÿ€wÈ` †ÆuÿèƒÆuÿ yÆuÿ†Æuÿ Ð+Yÿó(®ÿU«""öèƒÆu` ƒƒèƒÆuÿ/”ÐÐ+YÿÕ;$ŒÿèƒÆuÿ/”ôÆuÿÐÑ+Yÿ$Œÿ †ÆuÿU«""ö@Ð+Yÿin:/bin:/usr/sbin:/sbin:/usr/locusr/local/bin:/usr/local/git/bin0àÑ+YÿàÐ+Yÿusername

代码:

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

#include <errno.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define PORT 8080
#define PROTOCOL 0
#define BACKLOG 10
#define BUFLEN 1500



void serve_file(int sock, char* filename) 
{ 
  char buffer[1024]; 
  FILE *file;

  // Open file for reading
  file = fopen(filename, "rb");
  if (!file) {
    printf("Error: can't open file for reading");
    return;
  }

  if ((fgets(buffer, sizeof buffer, file)) != NULL) {
    int sent = send(sock, &buffer, sizeof buffer, 0);
    if (sent == -1) {
      printf("Error: send to socket failed\n");
      printf("Error code: %s\n", strerror(errno));      
    }
  } else {
    printf("Error: could not read file contents");
    return;
  }

  // Bye
  fclose(file);
} 

int main()
{
  int fd;
  int connfd;

  // For bind()
  struct sockaddr_in addr; 

  // For accept()
  struct sockaddr_in cliaddr; 
  socklen_t cliaddrlen = sizeof(cliaddr);

  // For reading and writing
  ssize_t i;
  ssize_t rcount;
  char buffer[BUFLEN];

  // Open a socket
  fd = socket(AF_INET, SOCK_STREAM, PROTOCOL);
  if (fd == -1) {
    printf("Error: unable to open a socket\n");
    printf("Error code: %s\n", strerror(errno));
    exit(1);
  }

  // Create an address
  //memset(&addr, 0, sizeof addr);
  addr.sin_addr.s_addr = INADDR_ANY;
  addr.sin_family = AF_INET;
  addr.sin_port = htons(PORT);

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

  if ((bind(fd, (struct sockaddr *)&addr, sizeof(addr))) == -1) {
    printf("Error: unable to bind\n");
    printf("Error code: %s\n", strerror(errno));
    exit(1);
  }

  // Listen for connections
  if ((listen(fd, BACKLOG)) == -1) {
    printf("Error: unable to listen for connections\n");
    printf("Error code: %s\n", strerror(errno));
    exit(1);
  }

  // Accept connections
  connfd = accept(fd, (struct sockaddr *) &cliaddr, &cliaddrlen);
  if (connfd == -1) {
    printf("Error: unable to accept connections\n");
    printf("Error code: %s\n", strerror(errno));
    exit(1);
  }

  // Read data
  rcount = read(connfd, buffer, BUFLEN);
  if (rcount == -1) {    
    printf("Error: unable to accept connections\n");
    printf("Error code: %s\n", strerror(errno));
    exit(1);
  }

  for (i = 0; i < rcount; i++) {
    printf("%c", buffer[i]);
  }

  //write(connfd, buffer, rcount);
  serve_file(connfd, "index.html");


  // Bye
  close(connfd);
  return 0;
}

1 个答案:

答案 0 :(得分:3)

更改

int sent = send(sock, &buffer, sizeof buffer, 0);

int sent = send(sock, &buffer, strlen(buffer), 0);

仅发送fgets()已阅读的内容。


此外,请注意,send()并不需要发送尽可能多的字节。

要确保发送外包,请测试send()的结果以查看实际发送的数量,然后循环send()以发送其余内容。

来自man send

  

成功时,这些调用将返回发送的字节数。


同样send()返回ssize_t而不是int


另外^ 2至少是:

int main(void)

另外^ 3:如果fclose()返回fgets(),则代码会错过NULL文件,当它达到EOF时,它肯定会做什么。


同样^最后:serve_file()只读取(并发送)文件的第一行。

要解决此更改

  if ((fgets(buffer, sizeof buffer, file)) != NULL) {
    int sent = send(sock, &buffer, sizeof buffer, 0);
    if (sent == -1) {
      printf("Error: send to socket failed\n");
      printf("Error code: %s\n", strerror(errno));      
    }
  } else {
    printf("Error: could not read file contents");
    return;
  }

看起来像这样

  while ((fgets(buffer, sizeof buffer, file)) != NULL) {
    ...
  }

  if (ferror(file)) {
    printf("Error reading file contents.");
  }