chuckfinley
chuckfinley

Reputation: 2595

Reading from a file and outputting to sockets

so i am working on a method that reads in a file and outputs its contents to a socket.

However, instead of my simple index.html file my browser shows this:

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

Code:

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

Upvotes: 0

Views: 70

Answers (1)

alk
alk

Reputation: 70981

Change

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

to be

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

to only send what fgets() did read.


Moreover, be aware, that send() does not necessarly sends as much bytes as it was told to do.

To make sure everthing is sent, test send()'s result to see how much actual was send and loop around send() to send the rest.

From man send:

On success, these calls return the number of bytes sent.


Also send() returns ssize_t not int.


Also^2 it's at least:

int main(void)

Also^3: The code misses to fclose() the file in case fgets() returned NULL, what it defintily will do when it reached EOF.


Also^Finally: serve_file() ever only reads (and sends) the file's first line.

To fix this change this

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

to look like this

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

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

Upvotes: 3

Related Questions