Sending and Receiving a file (Server/Client) in C using socket on Unix

AscaL picture AscaL · Jun 27, 2012 · Viewed 49.4k times · Source

First and foremost, thank you all for reading this and helping, I'm very grateful.
Second I'm sorry but i'm still new to this site and English is not my mother language so I could do some formatting and language mistakes. I apologize in advance.
Also, my C knowledge is not that good, but i'm willing to learn and improve.
Now, to the matter at hand:

What I need to do is to create a Client and a Server, and have the server listen for incoming connections.
Then I have the Client send a quite big text file (I know it will only be ONE file) to the Server.
The Server will then do some operation on the file (it will run a script on the sent file that produces another file in output called "output.txt"). The server then will need to send the output.txt file back to the Client.

Now, I kinda got how to make a Client and a Server (I read beej guide and some other stuff on this site), even tho I probably made some mistakes. I need some help with the server reciving the file, then calling the script and sending the other file back to the client. For now what I did is the Server and Client... I don't really know how to go on.
On a side note, I made this files using what I found on this site and on the internet, I hope they are not too messy, as I'm not that good of a programmer.

This is client.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h> 
#include <pthread.h>


#define SOCKET_PORT "50000"
#define SOCKET_ADR "localhost"
#define filename "/home/aryan/Desktop/input.txt"


void error(const char *msg)
{
    perror(msg);
    exit(0);
}


int main()
{
/* Making the client */
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;

char buffer[256];

portno = atoi(SOCKET_PORT);

sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) 
    error("ERROR opening socket");

server = gethostbyname(SOCKET_ADR);

if (server == NULL) 
{
    fprintf(stderr,"ERROR, no such host\n");
    exit(0);
}

bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr, 
     (char *)&serv_addr.sin_addr.s_addr,
     server->h_length);
serv_addr.sin_port = htons(portno);
if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) 
    error("ERROR connecting");

/* Time to send the file */
FILE *pf;
unsigned long fsize;

pf = fopen(filename, "rb");
if (pf == NULL) 
{
    printf("File not found!\n");
    return 1;
}
else 
{
    printf("Found file %s\n", filename);

    fseek(pf, 0, SEEK_END);
    fsize = ftell(pf);
    rewind(pf);

    printf("File contains %ld bytes!\n", fsize);
    printf("Sending the file now");
}

while (1) 
{
    // Read data into buffer.  We may not have enough to fill up buffer, so we
    // store how many bytes were actually read in bytes_read.
    int bytes_read = fread(buffer, sizeof(char),sizeof(buffer), pf);
    if (bytes_read == 0) // We're done reading from the file
        break;

    if (bytes_read < 0) 
    {
        error("ERROR reading from file"); 
    }

    // You need a loop for the write, because not all of the data may be written
    // in one call; write will return how many bytes were written. p keeps
    // track of where in the buffer we are, while we decrement bytes_read
    // to keep track of how many bytes are left to write.
    void *p = buffer;
    while (bytes_read > 0) 
    {
        int bytes_written = write(sockfd, buffer, bytes_read);
        if (bytes_written <= 0) 
        {
            error("ERROR writing to socket\n");
        }
        bytes_read -= bytes_written;
        p += bytes_written;
    }
}       

printf("Done Sending the File!\n");
printf("Now Closing Connection.\n");

fclose(pf);
close(sockfd);
return 0;
}

This is server.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#include <pthread.h>

#define SOCKET_PORT 50000
#define filename "/home/aryan/Desktop/output.txt"


void error(const char *msg)
{
    perror(msg);
    exit(1);
}

void* client_thread_proc(void* arg)
{
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
FILE *fp;

int thisfd = (int)arg;
printf("Server %d: accepted = %d\n", getpid(), thisfd);

if (thisfd < 0) 
{ 
    printf("Accept error on server\n");
    error("ERROR on accept"); 
    return NULL;
}

printf("Connection %d accepted\n", thisfd);

fp = fopen(filename, "a+b");
if (fp == NULL) 
{
    printf("File not found!\n");
    return NULL;
}
else 
{
    printf("Found file %s\n", filename);
}

/* Time to Receive the File */
while (1)
{
    bzero(buffer,256);
    n = read(thisfd,buffer,255);
    if (n < 0) error("ERROR reading from socket");

    n = fwrite(buffer, sizeof(char), sizeof(buffer), fp);
    if (n < 0) error("ERROR writing in file");

    n = write(thisfd,"I am getting your file...",25);
    if (n < 0) error("ERROR writing to socket");
} /* end child while loop */

fclose(fp);

return NULL;
}

void serve_it(int Client)
{
    void* arg = (void*)Client;
    pthread_t new_thread;
    pthread_create( &new_thread, NULL, &client_thread_proc, arg);
}

/* Making Server */
int main()
{
int sockfd, newsockfd, portno;
socklen_t clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
FILE *fp;

signal (SIGCHLD, SIG_IGN);

sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) 
    error("ERROR opening socket");

bzero((char *) &serv_addr, sizeof(serv_addr));

serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(SOCKET_PORT);

if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) 
      error("ERROR on binding");

listen(sockfd,5);

clilen = sizeof(cli_addr);

while (1)
{
    printf("Server %d accepting connections\n", getpid());

    newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);

    serve_it(newsockfd);
}  // serving loop


close(sockfd);   
return 0; 
}

I'd like some pointers on how to go on...
How do I make a script go on the file i received from client to server?
How do I send the new file back to the same client?
And if you could help me with the errors in the code i'd be grateful.

Thank you all and sorry for the long read. Have a nice day!

Answer

Viktor Latypov picture Viktor Latypov · Jun 27, 2012

First error:

#define filename = "Home\\Desktop\\input.txt"

should be

#define filename "Home\\Desktop\\input.txt"

Otherwise the preprocessor inserts the

= "Home\Desktop\input.txt"

not the

"Home\\Desktop\\input.txt"

that you expect.

Second error:

int bytes_read = read(filename /* THAT IS WRONG, FILE HANDLE MUST BE HERE */, buffer, strlen(buffer) /* also WRONG, must be MAX_BYTES_IN_BUFFER or something */ );

Here you must read from "pf" (you've opened it with the fopen() call) and the last argument must be the number of bytes you want to read. So if you do the strlen(buffer) and the buffer contains some garbage at the beginning of the program's runtime you will get a crash. strlen() must only be called for valid zero-terminated string, it is not the size of the array !

EDIT: elaborated server's loop:

while (1)
{
    printf("Server %d accepting connections\n", getpid());

    newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);

    serve_it(newsockfd);
}  // serving loop

The serve_it():

void serve_int(int Client)
{
    void* arg = (void*)Client;
    pthread_t new_thread;
    pthread_create( new_thread, NULL, &client_thread_proc, arg);
}

void* client_thread(void* arg)
{
    int thisfd = (int)arg;
    printf("Server %d: accepted = %d\n", getpid(), thisfd);

    if (thisfd < 0) 
    { 
        printf("Accept error on server\n");
        error("ERROR on accept"); 
        return NULL;
    }

    printf("Connection %d accepted\n", thisfd);

    fp = fopen(filename, "a+b");
    if (fp == NULL) 
    {
        printf("File not found!\n");
        return NULL;
    }
    else 
    {
        printf("Found file %s\n", filename);
    }

    /* Time to Receive the File */
    while (1)
    {
        bzero(buffer,256);
        n = read(thisfd,buffer,255);
        if (n < 0) error("ERROR reading from socket");

        n = fwrite(buffer, sizeof(buffer), 1, fp);
        if (n < 0) error("ERROR writing in file");

        n = write(thisfd,"I am getting your file...",25);
        if (n < 0) error("ERROR writing to socket");
    } /* end child while loop */

    return NULL;
}