File transfer using thread - c

I am trying to write a file transfer program using threading. The format I am trying to follow is:
./server 4501 ..................(will run forever)
./client 4501 add1.txt
./client 4501 bdd1.txt
And add1.txt and bdd1.txt will save in server side as add2.txt and bdd2.txt. But after running my code I found that add2.txt contains the characters from add1.txt plus some extra characters.
**
Updated Solution
**
Server Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <netinet/in.h>
#include <pthread.h>
#include <unistd.h>
/* Preprocessor Directives */
#define NTHREADS 50
#define QUEUE_SIZE 5
#define BUFFER_SIZE 256
/* Global counter locked via mutex */
pthread_t threadid[NTHREADS]; // Thread pool
pthread_mutex_t lock;
int counter = 0;
void *threadworker(void *arg)
{
int sockfd, rw; // File descriptor and 'read/write' to socket indicator
char *buffer; // Message buffer
sockfd = (int) arg; // Getting sockfd from void arg passed in
buffer = malloc(BUFFER_SIZE);
bzero(buffer, BUFFER_SIZE);
rw = read(sockfd, buffer, BUFFER_SIZE); // Blocks until there is something to be read in the socket
FILE *fp;
fp=fopen("add2.txt","w");
fprintf(fp,"%s",buffer);
//fwrite(buffer, strlen(buffer) + 1, 1, fp);
//fwrite(buffer,sizeof(char),BUFFER_SIZE, fp);
fclose(fp);
printf("%d\n",strlen(buffer));
printf("the file was received successfully\n");
printf("the new file created is add2.txt\n");
if (rw < 0)
{
perror("Error reading form socket, exiting thread");
pthread_exit(0);
}
//printf("New message received: %s", buffer); // String already has newline
bzero(buffer, BUFFER_SIZE);
//sprintf(buffer, "Acknowledgement from TID:0x%x", pthread_self());
/*rw = write(sockfd, buffer, strlen(buffer));
if (rw < 0)
{
perror("Error writing to socket, exiting thread");
pthread_exit(0);
}*/
/* Critical section */
/*printf("Requesting mutex lock...\n");
pthread_mutex_lock (&lock);
printf("Current counter value: %d, upping by 1...\n", counter);
counter++;
pthread_mutex_unlock (&lock);
printf("Done! Mutex unlocked again, new counter value: %d\n", counter);
*/
close(sockfd);
//printf("TID:0x%x served request, exiting thread\n", pthread_self());
pthread_exit(0);
}
int main(int argc, char *argv[])
{
/* Variable declarations */
int serv_sockfd, new_sockfd; //Socket identifiers for server and incoming clients
struct addrinfo flags; // Params used to establish listening socket
struct addrinfo *host_info; // Resultset for localhost address info, set by getaddrinfo()
socklen_t addr_size; // Client address size since we use sockaddr_storage struct to store
// client info coming in, not using addrinfo as done for host (local)
// by calling getaddrinfo for resolution, which stores results in
// the more convenient addrinfo struct
struct sockaddr_storage client; // Sockaddr storage struct is larger than sockaddr_in,
// can be used both for IPv4 and IPv6
pthread_attr_t attr; // Thread attribute
int i; // Thread iterator
/* Start of main program */
if (argc < 2) {
fprintf(stderr,"Error: no port provided\n");
exit(-1);
}
memset(&flags, 0, sizeof(flags));
flags.ai_family = AF_UNSPEC; // Use IPv4 or IPv6, whichever
flags.ai_socktype = SOCK_STREAM; // TCP
flags.ai_flags = AI_PASSIVE; // Set address for me
if (getaddrinfo(NULL, argv[1], &flags, &host_info) < 0)
{
perror("Couldn't read host info for socket start");
exit(-1);
}
serv_sockfd = socket(host_info->ai_family, host_info->ai_socktype, host_info->ai_protocol);
if (serv_sockfd < 0)
{
perror("Error opening socket");
exit(-1);
}
if (bind(serv_sockfd, host_info->ai_addr, host_info->ai_addrlen) < 0)
{
perror("Error on binding");
exit(-1);
}
freeaddrinfo(host_info); // Don't need this struct anymore
pthread_attr_init(&attr); // Creating thread attributes
pthread_attr_setschedpolicy(&attr, SCHED_FIFO); // FIFO scheduling for threads
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); // Don't want threads (particualrly main)
// waiting on each other
listen(serv_sockfd, QUEUE_SIZE); // Pass in socket file descriptor and the size of the backlog queue
// (how many pending connections can be in queue while another request
// is handled)
addr_size = sizeof(client);
i = 0;
while (1)
{
if (i == NTHREADS) // So that we don't access a thread out of bounds of the thread pool
{
i = 0;
}
new_sockfd = accept(serv_sockfd, (struct sockaddr *) &client, &addr_size);
if (new_sockfd < 0)
{
perror("Error on accept");
exit(-1);
}
pthread_create(&threadid[i++], &attr, &threadworker, (void *) new_sockfd);
sleep(0); // Giving threads some CPU time
}
return 0;
}
And the Client Code is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <netinet/in.h>
#include <pthread.h>
#include <unistd.h>
#define BUFFER_SIZE 256
int main(int argc, char *argv[])
{
int sockfd, rw;
struct addrinfo flags;
struct addrinfo *server_info;
char *buffer = malloc(BUFFER_SIZE);
if (argc < 4)
{
fprintf(stderr, "Usage: ./client <hostname/address> <port> <file_path>");
exit(-1);
}
memset(&flags, 0, sizeof(flags)); // Clear so we're not working with garbage
flags.ai_family = AF_UNSPEC; // IPv4 or IPv6 doesn't matter
flags.ai_socktype = SOCK_STREAM; // TCP
flags.ai_flags = AI_PASSIVE; // get the IP for me
if (getaddrinfo(argv[1], argv[2], &flags, &server_info) < 0) { // Resolve host based on CMD args
perror("Couldn't find host");
exit(-1);
}
sockfd = socket(server_info->ai_family, server_info->ai_socktype, server_info->ai_protocol); // Initialize socket
if (connect(sockfd, server_info->ai_addr, server_info->ai_addrlen) < 0)
{
perror("Couldn't conenct...");
exit(-1);
}
//printf("Connection established, please enter a message:\n");
bzero(buffer, BUFFER_SIZE);
//fgets(buffer, BUFFER_SIZE - 1, stdin);
//char buffer[100];
FILE *f;
size_t read=0;
if((f=fopen(argv[3],"r"))==NULL){
printf("Failed");
exit(-1);
}
//fseek(f, 0, SEEK_END);
//len = ftell(f);
//while (fgets(buffer, strlen(buffer), f) != NULL)
//fscanf(f,"%s",buffer);
//fread(buffer, strlen(buffer)+1, 1, f);
do{
read = fread(buffer,sizeof(char),BUFFER_SIZE-1, f);
if (read > 0) //if return value is > 0
{
buffer[BUFFER_SIZE]='\0';
rw = write(sockfd, buffer, strlen(buffer));
}
}
while(read == BUFFER_SIZE); //end when a read returned fewer items
fclose(f);
//write(sock, &len, sizeof(int));
//write(sock, buffer, len);
printf("the file was sent successfully");
//rw = write(sockfd, buffer, strlen(buffer)); // Sending the contents of the buffer - writes using socket file descriptor
if (rw < 0)
{
perror("Failed to send message");
exit(-1);
}
/*bzero(buffer, BUFFER_SIZE);
rw = read(sockfd, buffer, BUFFER_SIZE); // Read the ENTIRE buffer because we don't know stlen yet
if (rw < 0)
{
perror("Error reading from socket");
exit(-1);
}
printf("The message is: %s\n", buffer);
*/
close(sockfd);
return 0;
}
My add1.txt file contains
abcd
efgh
ijkl
mnop
The add2.txt file contains as output:
abcd
efgh
ijkl
mnop
############################################################################################################################################################################################################################################
Can anyone please advice me what are the modifications I will need then.
Thank you, in advance.

You need to call fclose on File *fp (server code) and File *f (client code) after you are done reading/writing the file. You did close the connection between the client and server, but you did not close the file stream which is probably the cause of the files being empty. So in your case it will be safe to call fclose after you called fprintf (server code) and fscanf (client code).

Related

Communication: Sending a message from a client to a server

My Server can handle multiple clients/switches at a time.
My problem is in my switch I believe, I'm trying to send an open message to the the controller. I create the the tcp socket in the switch and then right after I try to send the message to the controller, however when I try to do this, the socket disconnects from the controller and goes into an infinite loop. I'm not sure why this occurs as I'm creating and sending the message outside of my while loop. If I comment where I send the message, the socket stays connected to the controller and I am able to wait for one of a set of file descriptors to become ready to perform I/O, currently I only have the keyboard and the socket. My socket also receives a message from the controller when it's connected "You are connected to the server". In addition since my switch socket disconnects my recv() return error code 107 due to the fact the socket is disconnected.
I'm not sure If I provided too much code to look through but I added comments where I thought my error was occurring in the switch as well as the controller. Greatly appreciated for some help. I didn't add any of my own header files because they are not necessary.
This where I execute the switch. Sends and receive messages here.
#include "switch.h"
#include "openFIFO.h"
#include "packets.h"
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include<poll.h>
#include <signal.h>
void do_switch(int swIport, char *trafficfile,int swJport, int swKport, int IPlow, int IPhigh,char serverAddress[256], unsigned short portNumber){
int switch_sock;
char server_response[256];
struct pollfd pfds[6];
int rval;
/* Switch */
Switch sw;
sw.swJport = swJport;
sw.swIport = swIport;
sw.swKport = swKport;
sw.IPlow = IPlow;
sw.IPhigh = IPhigh;
int switchLength = sizeof(Switch);
// printf("\n\nstruct switchLength: %d\n", switchLength);
// printf("\n\nSwitch Struct: swIport: %d, swJport: %d, swKport: %d,
IPlow: %d, IPhigh: %d\n", sw.swIport, sw.swJport, sw.swKport, sw.IPlow,
sw.IPhigh);
printf("\n\nSwitch created with the following: swIport: %d, trafficfile:
%s, swJport: %d, swKport: %d, IPlow: %d, IPhigh: %d, serverAddress: %s,
portNumber: %d\n", swIport, trafficfile, swJport, swKport, IPlow, IPhigh,
serverAddress, portNumber);
int fifoWrite[2];
int fifoRead[2];
int counter = 0;
char message[20] = "Hello";
/* Create fifos */
if(swJport != -1){
fifoWrite[0] = openWF(swIport,swJport);
fifoRead[0] = openReadFifo(swJport, swIport);
counter = counter + 2;
}
if(swKport != -1){
fifoWrite[1] = openWF(swIport,swKport);
fifoRead[1] = openReadFifo(swKport, swIport);
counter = counter + 2;
}else if(swKport == -1){
fifoWrite[0] = openWF(swIport,swKport);
fifoRead[0] = openReadFifo(swKport, swIport);
counter = counter + 2;
}
printf("fifoWrite[0]: %d\n", fifoWrite[0]);
printf("fifoRead[0]: %d\n", fifoRead[0]);
printf("fifoWrite[1]: %d\n", fifoWrite[1]);
printf("fifoRead[1]: %d\n", fifoRead[1]);
/* Establish connection between the controller and switch */
/* Send a open packet to the controller */
/* Sending a stuct */
//PROBELM HERE BELOW!!!!!!!
switch_sock = CreateTCPClientSocket(portNumber, serverAddress);
if(send(switch_sock, message, sizeof(message), 0) == -1){
fprintf(stderr, "Send() Failed");
}
else{
printf("Open packet is being sent to the controller\n");
}
/* Initialize poll parameters */
//Keyboard
pfds[0].fd = STDIN_FILENO;
pfds[0].events = POLLIN;
// Socket!
pfds[1].fd = switch_sock;
pfds[1].events = POLLIN;
printf("Starting switch............................\n\n");
while(1){
rval = poll(pfds,2,-1);
if(rval == 0){
fprintf(stderr, "Poll timed out. \n");
}if(rval == -1){
fprintf(stderr, "ERROR: poll() failed");
exit(0);
}
/* Check Keyboard */
if(pfds[0].revents & POLLIN && pfds[0].fd == 0){
int a;
char command[1024][256];
int commands;
char buf[256];
commands = read(0, buf, 256);
buf[commands] = '\0';
buf[commands] = '\0';
char *token;
token = strtok(buf, " ");
while(token != NULL){
strcpy(command[a], token);
a++;
token = strtok(NULL, " ");
}
a = 0;
bzero(buf, 256);
if(strcmp(command[0], "list") == 0){
//TODO: Make a print function
printf("print_switch()\n");
}
if(strcmp(command[0], "exit") == 0){
//TODO: Make a print function
printf(" print_switch()\n");
printf("switch-disconnected\n");
close(switch_sock);
exit(0)
}
}
/* Server sent a welcome message */
// Might be PROBELM HERE BELOW when trying to send the initial packet to
controller!!!!!!!
if(pfds[1].revents & POLLIN){
recv(switch_sock, &server_response, sizeof(server_response), 0);
printf("%s\n", server_response);
}
}
}
Creates a TCP Socket for the switch.
int CreateTCPClientSocket( unsigned short port, char *serverAddress){
int sock; /*socket to create */
struct sockaddr_in servAddr; /* Local address */
/* Construct local address structure */
/* Create socket for incoming connections */
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0){
fprintf(stderr,"ERROR: socket() failed\n");
exit(0);
}
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_port = htons(port);
servAddr.sin_addr.s_addr = inet_addr(serverAddress);
if(connect(sock, (struct sockaddr *)&servAddr, sizeof(struct sockaddr)) <
0){
printf("Error code: %d\n", errno);
fprintf(stderr, "ERROR: connect() just failed\n");
exit(0);
}
return sock;
}
This is the controller
#include "controller.h"
#include "packets.h"
#include "switch.h"
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
void do_controller(int nSwitch, int portNumber){
int controller_sock; /* Socket descriptor for server/controller */
int clnSocket; /*Socket descriptor for clients */
int activity;
int max_sd;
int sd;
int client_socket[nSwitch];
struct sockaddr_in address;
int addrlen;
/* Controller stuff */
Controller cont;
cont.ackCounter = 0;
cont.openCounter = 0;
Switch sw;
char message[256] = "You have reached the server\n";
char recv_message[20];
printf("\n\nController created: nSwitch: %d on portNumber: %d\n", nSwitch, portNumber);
/* Initialise all client_socket[] to 0 so not checked */
for(int i = 0; i < nSwitch; i++){
client_socket[i] = 0;
}
/*Create the server/controller socket */
controller_sock = CreateTCPServerSocket(portNumber);
//addrlen = sizeof(address);
/* Prepare for nonblocking I/O polling/select from the controller socket */
printf("Starting server.........\n\n");
while(1){
/* Zero the socket set and set for server sockets */
/* This must be reset every time select() is called */
/* Add keyboard to descriptor */
/* Add client and controller sockets to set */
FD_ZERO(&sockSet);
FD_SET(STDIN_FILENO, &sockSet);
FD_SET(controller_sock, &sockSet);
max_sd = controller_sock;
//max_sd = 0;
printf("nSwitch: %d\n", nSwitch);
for(int x = 0; x < nSwitch; x++){
sd = client_socket[x];
printf("sd: %d\n\n", sd);
if(sd > 0)
FD_SET(sd, &sockSet);
if(sd > max_sd)
max_sd = sd;
}
printf("max_sd: %d\n", max_sd);
//wait for one of the sockets, timeout is Null,
//so wait indefinitely
activity = select(max_sd + 1, &sockSet, NULL, NULL,NULL);
//printf("Activity: %d\n", activity);
if(activity < 0){
fprintf(stderr, "ERROR: select()\n");
exit(0);
}
/*Check keyboard */
if(FD_ISSET(STDIN_FILENO, &sockSet)){
int a;
char command[1024][256];
int commands;
char buf[256];
commands = read(0, buf, 256);
buf[commands] = '\0';
char *token;
token = strtok(buf, " ");
while(token != NULL){
strcpy(command[a], token);
a++;
token = strtok(NULL, " ");
}
a = 0;
bzero(buf, 256);
if(strcmp(command[0], "list") == 0){
//TODO: Make a print function
print_controller(&cont, nSwitch);
}
if(strcmp(command[0], "exit") == 0){
//TODO: Make a print function
print_controller(&cont, nSwitch);
exit(0);
}
continue;
}
/* Check the incoming FIFOS from the controller an attached switches */
/*If something happened on the controller socket,
then its an incomming connection. Accept new communitcation.Wait for a client to connect.
Recieve packets sent to the controller_sock
*/
if(FD_ISSET(controller_sock, &sockSet)){
clnSocket = AcceptTCPConnection(controller_sock);
if(send(clnSocket, message, sizeof(message), 0) != sizeof(message)){
fprintf(stderr, "Send()");
exit(0);
}
puts("Welcome message sent successfuly");
//PROBELM HERE BELOW!!!!!!! Returns error code 107 because the
socket disconnected.
recv(controller_sock, &recv_message, sizeof(recv_message), 0);
printf("This is my recv_message: %s\n", recv_message);
/*add new socket to array of sockets*/
for(int a = 0; a < nSwitch; a++){
/*if position is empty */
if(client_socket[a] == 0){
client_socket[a] = clnSocket;
printf("Adding to list of sockets as %d\n", client_socket[a]);
break;
}
}
}
/* Communicate with the sockets and handle TCP Client */
for(int z = 0; z <nSwitch; z++){
sd = client_socket[z];
/*Check if it was socket closed, and do other stuff */
if(FD_ISSET(sd ,&sockSet )){
getpeername(sd , (struct sockaddr*)&address , (socklen_t*)&addrlen);
printf("Host disconnected , ip %s , port %d \n" , inet_ntoa(address.sin_addr) , ntohs(address.sin_port));
close( sd );
client_socket[z] = 0;
}else{
//Do stuff for the client
printf("This is the client %d\n", sd);
}
}
}
}
These are the controllers functions: Assign a port to socket,Set socket to listen
int AcceptTCPConnection(int servSock){
int clntSock; /* Socket descriptor for client */
unsigned int clientAddressLen; /* sizeof(client_address); Length of client */
struct sockaddr_in cli_addr; /* Client address */
/* Set the size of the in-out parameter */
clientAddressLen = sizeof(cli_addr);
printf("ClientAddressLen: %x\n", clientAddressLen);
/* Wait for a client to connect */
if ((clntSock = accept(servSock, (struct sockaddr *) &cli_addr,
&clientAddressLen)) < 0){
fprintf(stderr, "ERROR: accept failed\n");
exit(0);
}
/* clntSock is connected to a client! */
//infrom user of socket number used in send and receive commands
printf("Handling client %s\n", inet_ntoa(cli_addr.sin_addr));
printf("New connection: socket fd is: %d, ip is: %s, port: %d\n\n",
clntSock, inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port));
return clntSock;
}
Create a TCP socket
int CreateTCPServerSocket(unsigned short port){
int sock; /* socket to create */
struct sockaddr_in servAddr; /* Local address */
/* Create socket for incoming connections */
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0){
fprintf(stderr,"ERROR: socket() failed\n");
exit(0);
}
/* Construct local address structure */
/* Define the server address */
//bzero((char *) &server_address, sizeof(server_address));
memset(&servAddr, 0, sizeof(servAddr)); /* Zero out structure */
servAddr.sin_family = AF_INET; /* Internet address family
*/
servAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface
*/
servAddr.sin_port = htons(port); /* Local port */
/* Bind to the local address */
printf("New connection: ip is: %s, port: %d\n\n",
inet_ntoa(servAddr.sin_addr), ntohs(servAddr.sin_port));
if (bind(sock, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0){
printf("Error code: %d\n", errno);
fprintf(stderr,"ERROR: bind() just failed\n");
exit(0);
}
/* Mark the socket so it will listen for incoming connections */
if (listen(sock, 5) < 0){
fprintf(stderr,"ERROR: listen() failed\n");
exit(0);
}
return sock;
}

How to correctly use fwrite? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
So I have a char* called bufptr that is of size 512. Within the first couple of spots is the name of the file that I will be reading from and everything else after that is data.
ex. char* bufptr = {'f', 'o', 'o', '.', 'c', '\0', ...}
I did not initialize it like that but that is the general idea
After this I store the name of the file into a different file using strcpy
ex.
auto int i = 0;
while(*bufptr != '\0')
{
fname[i++] = *bufptr;
bufptr++;
}
bufptr++;
After that, I open up the file
What I am having problems with is the fwrite portion.
I tried writing fwrite(bufptr, 1, 512 - strlen(destString), fp)
but instead of
// ============================================================================
// File: fcclient.c (Fall 2017)
// ============================================================================
I got þ================================================
How would I correctly call fwrite so that I don't run into this issue or is it because I am not skipping over the null? Or does string have something before or after the null?
edit:
I added a loop to check over bufptr and got this as the output
fcclient.c▒▒▒▒▒▒▒▒▒▒id▒.N=▒C▒h▒▒▒.8▒▒l▒ ▒ ▒▒▒`▒ ▒P▒▒▒H▒
▒`▒djd▒▒dd▒▒#▒
▒#▒(▒d▒p▒▒jd▒▒▒▒▒Бd▒=======================================================================
// File: fcclient.c (Fall 2017)
// ============================================================================
// This program is a file transfer client. The user at the keyboard is pread a total of 1 bytes
this was the loop I used
auto int t = 0;
for(; t < 512; t+=)
if(*(bufptr + t) != '\0')
printf("%c", *(bufptr + t));
Here is the server code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
// prototypes
int CopyFile(int src_sock);
// defined constants
#define BUFLEN 512
#define SERVER_PORT 50004
#define TRUE 1
#define FALSE 0
// function prototypes
int CopyFile(int src_sock);
int main(void)
{
auto char buf[BUFLEN]; // local buffer
auto socklen_t client_addr_size; // used for call to accept
auto int client_socket; // used for call to accept
auto int server_socket; // used for call to socket
auto struct sockaddr_in client_address; // used for call to accept
auto struct sockaddr_in server_address; // used for call to bind
// greet the user
puts("Welcome to fcserver!");
puts("Waiting to recieve file from client...");
// create a socket for the server
server_socket = socket(AF_INET, SOCK_STREAM, 0);
// prepare the socket address structure for the server
memset(&server_address, 0, sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
server_address.sin_port = htons(SERVER_PORT);
// bind the server socket to an address, using the address structure
if(bind(server_socket, (struct sockaddr*) &server_address, sizeof(server_address)))
{
perror("server -- bind failed");
}
// put the server socket into a listening state
if(listen(server_socket, 5))
{
perror("server -- bind failed");
}
// let stdout know the server is waiting for a connection
puts("server waiting...");
// wait for an actual client connection (this will block)
client_addr_size = sizeof(server_address);
client_socket = accept(server_socket, (struct sockaddr*) &server_address, &client_addr_size);
CopyFile(client_socket);
// close the client and server sockets
close(client_socket);
close(server_socket);
return 0;
} // end of "main"
int CopyFile(int src_sock)
{
auto char buf[BUFLEN];
auto char *bufptr;
auto char fname[BUFLEN];
auto FILE* fptr;
auto int num_client_bytes;
auto unsigned long total_bytes = 0;
if(-1 == (num_client_bytes = recv(src_sock, bufptr, BUFLEN, 0)))
perror("server -- recv failed");
strcpy(fname, bufptr);;
auto int t = 0;
for(; t< num_client_bytes; t++)
{
if(*(bufptr + t) != '\0')
printf("%c", *(bufptr + t));
}
fptr = fopen(fname, "w");
auto int i = strlen(fname) +1;
bufptr += i;
total_bytes = fwrite(bufptr, sizeof(bufptr), 1, fptr);
printf("read a total of %lu bytes \n", total_bytes);
// loop and read the rest of the file from the client
do {
if(num_client_bytes == 0)
break;
printf("read a total of %d bytes \n", num_client_bytes);
total_bytes += fwrite(buf, 1, num_client_bytes, fptr);
} while (TRUE);
fclose(fptr);
printf("there were a total of %lu bytes written \n", total_bytes);
return TRUE;
} // end of "CopyFile"
Here is the client file
// ============================================================================
// File: fcclient.c (Fall 2017)
// ============================================================================
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/un.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#define BUFLEN 256
#define SERVER_PORT 50004
int main(void)
{
auto char buf[BUFLEN]; // general purpose buffer
auto int server_socket; // used for server socket
auto struct sockaddr_in server_address; // used for server address
auto char fname[BUFLEN]; // used for filename
auto char *bufptr; // used for heap block
auto FILE *fptr; // used for input file
auto int result; // used to check return values
auto long fileSize; // used to store file size
// greet the user
puts("Welcome to fcclient!");
// get the filename from stdin
printf("Please enter in the filename: ");
scanf("%s", fname);
// open the input file
fptr = fopen(fname, "r");
if(fptr == NULL)
{
printf("Sorry there was an error trying to locate the file. Please exit and try again \n");
return 0;
}
// get the size of the file
fseek(fptr, 0, SEEK_END);
fileSize = ftell(fptr);
fseek(fptr, 0, SEEK_SET);
// allocate a buffer to store the file in heap memory
bufptr = malloc(sizeof(char) * fileSize);
// create a socket to connect with the server
server_socket = socket(AF_INET, SOCK_STREAM, 0);
// setup a socket address structure to target the server
memset(&server_address, 0, sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_port = htons(SERVER_PORT);
server_address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
printf("Currently connecting to server... \n");
// connect to the server
if(-1 == connect(server_socket, (struct sockaddr*) &server_address, sizeof(server_address)))
perror("client -- connect failed");
// send the filename to the server (include the NULL!)
if(-1 == send(server_socket, fname, BUFLEN, 0))
perror("client -- send failed");
// read the file into the allocated buffer
fseek(fptr, sizeof(bufptr),SEEK_SET);
if(0 == fread(bufptr, sizeof(bufptr), fileSize, fptr))
{
printf("There was an error sorry. \n");
return 0;
}
// send the data to the server
if(-1 == send(server_socket, bufptr, fileSize, 0))
perror("client -- send failed");
// close the input file and the sockets
fclose(fptr);
close(server_socket);
return 0;
} // end of "main"
bufptr is not pointing to the content of the buffer,Because of bufptr += strlen(destString) , Its pointing to the location next to the content. Update the value of bufptr to point to the content you actually want to write.
There are two sets of problems in the code (some of them diagnosed in comments made to question). First, you write a full length buffer even though it contains mostly junk, and then you try to interpret that as part of the file, but it isn't. And second, you're playing with an uninitialized variable in the client file copy code — you're (un)lucky it didn't crash.
This code works.
fcserver.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define BUFLEN 512
#define SERVER_PORT 50004
void CopyFile(int src_sock);
int main(void)
{
socklen_t client_addr_size;
int client_socket;
int server_socket;
struct sockaddr_in server_address;
puts("Welcome to fcserver!");
puts("Waiting to recieve file from client...");
server_socket = socket(AF_INET, SOCK_STREAM, 0);
memset(&server_address, 0, sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
server_address.sin_port = htons(SERVER_PORT);
if (bind(server_socket, (struct sockaddr *)&server_address, sizeof(server_address)))
{
perror("server -- bind failed");
}
if (listen(server_socket, 5))
{
perror("server -- bind failed");
}
puts("server waiting...");
client_addr_size = sizeof(server_address);
client_socket = accept(server_socket, (struct sockaddr *)&server_address, &client_addr_size);
CopyFile(client_socket);
close(client_socket);
close(server_socket);
return 0;
}
void CopyFile(int src_sock)
{
char buf[BUFLEN];
char fname[BUFLEN];
FILE *fptr;
int num_client_bytes;
unsigned long total_bytes = 0;
if (-1 == (num_client_bytes = recv(src_sock, fname, BUFLEN, 0)))
{
perror("server -- recv failed");
exit(1);
}
printf("File name: [%s]\n", fname);
fptr = fopen(fname, "w");
if (fname == 0)
{
perror(fname);
exit(1);
}
while ((num_client_bytes = recv(src_sock, buf, BUFLEN, 0)) > 0)
{
printf("read a total of %d bytes\n", num_client_bytes);
total_bytes += fwrite(buf, 1, num_client_bytes, fptr);
}
fclose(fptr);
printf("there were a total of %lu bytes written\n", total_bytes);
}
That's 85 lines, instead of 170-odd lines.
fcclient.c
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/un.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#define BUFLEN 256
#define SERVER_PORT 50004
int main(void)
{
int server_socket;
struct sockaddr_in server_address;
char fname[BUFLEN] = "";
char *bufptr;
FILE *fptr;
size_t fileSize;
puts("Welcome to fcclient!");
printf("Please enter in the filename: ");
scanf("%s", fname);
fptr = fopen(fname, "r");
if (fptr == NULL)
{
printf("Sorry there was an error trying to locate the file. Please exit and try again \n");
return 0;
}
fseek(fptr, 0, SEEK_END);
fileSize = ftell(fptr);
fseek(fptr, 0, SEEK_SET);
bufptr = malloc(sizeof(char) * fileSize);
server_socket = socket(AF_INET, SOCK_STREAM, 0);
memset(&server_address, 0, sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_port = htons(SERVER_PORT);
server_address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
printf("Currently connecting to server... \n");
if (-1 == connect(server_socket, (struct sockaddr *)&server_address, sizeof(server_address)))
perror("client -- connect failed");
if (-1 == send(server_socket, fname, BUFLEN, 0))
perror("client -- send failed");
fseek(fptr, 0, SEEK_SET);
if (fileSize != fread(bufptr, sizeof(char), fileSize, fptr))
{
printf("There was an error sorry. \n");
return 0;
}
if (-1 == send(server_socket, bufptr, fileSize, 0))
perror("client -- send failed");
fclose(fptr);
close(server_socket);
return 0;
}
That's 68 lines instead of 170-odd lines.
Testing
It is crucial to run the server in a different directory from the client, else you could get files truncated. However, when I used a sub-directory junk containing a file animals19.c and ran the client in that directory, while the server ran in the parent directory, I got the output:
server window
$ ./fcserver
Welcome to fcserver!
Waiting to recieve file from client...
server waiting...
File name: [animals19.c]
read a total of 512 bytes
read a total of 292 bytes
there were a total of 804 bytes written
$
client window
$ ../fcclient
Welcome to fcclient!
Please enter in the filename: animals19.c
Currently connecting to server...
$ ls -l animals19.c ../animals19.c
-rw-r--r-- 1 jleffler staff 804 Dec 13 00:42 ../animals19.c
-rw-r--r-- 1 jleffler staff 804 Dec 3 21:54 animals19.c
$ diff animals19.c ../animals19.c
$
Oh, and at some point, you should note "i before e except after c" (so it is receive and not recieve). You should also note that perror() prints an error; it does not exit. Continuing after using perror() is usually wrong.

multi-threaded file transfer with socket

I am trying to make a multi-threaded server-client file transfer system in C. There are clients which will send or list or do some other choice (in a switch case you can see) and a server storing the files and serving a lot of clients.
Multi-thread ideology is really difficult as far as I can see. It needs too much experience instead of knowledge. I have been working on the project for more than one week and I haven't been able to get on top of the problems.
There are 4 choices: first one is lists local files of client in its directory, second one is list files which are transferred between the client and server, third reading filename from user and copy the file into server's directory.
My vital issue here is about multi-threading. I cannot connect multiple clients. I have read the code from a to z heaps of times but I really can't catch my errors and am stuck.
The other issue is that the client will end when the SIGINT is caught, but, for instance, after choosing list files when press ctrl-c it doesn't stop. Same issue for the server file as well. It is more troublesome compared to the client's catching because when server gets SIGINT, clients will be disconnected respectively from the server.
Thanks for your helps!
server.c
/*
Soner
Receive a file over a socket.
Saves it to output.tmp by default.
Interface:
./executable [<port>]
Defaults:
- output_file: output.tmp
- port: 12345
*/
#define _XOPEN_SOURCE 700
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <netdb.h> /* getprotobyname */
#include <netinet/in.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <unistd.h>
#include <pthread.h>
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
enum { PORTSIZE = 5 };
void* forClient(void* ptr);
void sig_handler(int signo)
{
if (signo == SIGINT)
printf("!! OUCH, CTRL - C received by server !!\n");
}
int main(int argc, char **argv) {
struct addrinfo hints, *res;
int enable = 1;
int filefd;
int server_sockfd;
unsigned short server_port = 12345u;
char portNum[PORTSIZE];
socklen_t client_len[BUFSIZ];
struct sockaddr_in client_address[BUFSIZ];
int client_sockfd[BUFSIZ];
int socket_index = 0;
pthread_t threads[BUFSIZ];
if (argc != 2) {
fprintf(stderr, "Usage ./server <port>\n");
exit(EXIT_FAILURE);
}
server_port = strtol(argv[1], NULL, 10);
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET; //ipv4
hints.ai_socktype = SOCK_STREAM; // tcp
hints.ai_flags = AI_PASSIVE; // fill in my IP for me
sprintf(portNum, "%d", server_port);
getaddrinfo(NULL, portNum, &hints, &res);
server_sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (server_sockfd == -1) {
perror("socket");
exit(EXIT_FAILURE);
}
if (setsockopt(server_sockfd, SOL_SOCKET, (SO_REUSEPORT | SO_REUSEADDR), &enable, sizeof(enable)) < 0) {
perror("setsockopt(SO_REUSEADDR) failed");
exit(EXIT_FAILURE);
}
if (bind(server_sockfd, res->ai_addr, res->ai_addrlen) == -1) {
perror("bind");
exit(EXIT_FAILURE);
}
if (listen(server_sockfd, 5) == -1) {
perror("listen");
exit(EXIT_FAILURE);
}
fprintf(stderr, "listening on port %d\n", server_port);
while (1) {
client_len[socket_index] = sizeof(client_address[socket_index]);
puts("waiting for client");
client_sockfd[socket_index] = accept(
server_sockfd,
(struct sockaddr*)&client_address[socket_index],
&client_len[socket_index]
);
if (client_sockfd[socket_index] < 0) {
perror("Cannot accept connection\n");
close(server_sockfd);
exit(EXIT_FAILURE);
}
pthread_create( &threads[socket_index], NULL, forClient, (void*)client_sockfd[socket_index]);
if(BUFSIZ == socket_index) {
socket_index = 0;
} else {
++socket_index;
}
pthread_join(threads[socket_index], NULL);
close(filefd);
close(client_sockfd[socket_index]);
}
return EXIT_SUCCESS;
}
void* forClient(void* ptr) {
int connect_socket = (int) ptr;
int filefd;
ssize_t read_return;
char buffer[BUFSIZ];
char *file_path;
char receiveFileName[BUFSIZ];
int ret = 1;
// Thread number means client's id
printf("Thread number %ld\n", pthread_self());
pthread_mutex_lock( &mutex1 );
// until stop receiving go on taking information
while (recv(connect_socket, receiveFileName, sizeof(receiveFileName), 0)) {
file_path = receiveFileName;
fprintf(stderr, "is the file name received? ? => %s\n", file_path);
filefd = open(file_path,
O_WRONLY | O_CREAT | O_TRUNC,
S_IRUSR | S_IWUSR);
if (filefd == -1) {
perror("open");
exit(EXIT_FAILURE);
}
do {
read_return = read(connect_socket, buffer, BUFSIZ);
if (read_return == -1) {
perror("read");
exit(EXIT_FAILURE);
}
if (write(filefd, buffer, read_return) == -1) {
perror("write");
exit(EXIT_FAILURE);
}
} while (read_return > 0);
}
pthread_mutex_unlock( &mutex1 );
fprintf(stderr, "Client dropped connection\n");
pthread_exit(&ret);
}
client.c
/*
Soner
Send a file over a socket.
Interface:
./executable [<sever_hostname> [<port>]]
Defaults:
- server_hostname: 127.0.0.1
- port: 12345
*/
#define _XOPEN_SOURCE 700
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <netdb.h> /* getprotobyname */
#include <netinet/in.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <unistd.h>
// NOTE/BUG: this didn't provide enough space for a 5 digit port + EOS char
#if 0
enum { PORTSIZE = 5 };
#else
enum { PORTSIZE = 6 };
#endif
void
sig_handler(int signo)
{
if (signo == SIGINT)
printf("!! OUCH, CTRL - C received on client !!\n");
}
int
main(int argc, char **argv)
{
struct addrinfo hints,
*res;
char *server_hostname = "127.0.0.1";
char file_path[BUFSIZ];
char *server_reply = NULL;
char *user_input = NULL;
char buffer[BUFSIZ];
int filefd;
int sockfd;
ssize_t read_return;
struct hostent *hostent;
unsigned short server_port = 12345;
char portNum[PORTSIZE];
char remote_file[BUFSIZ];
int select;
char *client_server_files[BUFSIZ];
int i = 0;
int j;
// char filename_to_send[BUFSIZ];
if (argc != 3) {
fprintf(stderr, "Usage ./client <ip> <port>\n");
exit(EXIT_FAILURE);
}
server_hostname = argv[1];
server_port = strtol(argv[2], NULL, 10);
/* Prepare hint (socket address input). */
hostent = gethostbyname(server_hostname);
if (hostent == NULL) {
fprintf(stderr, "error: gethostbyname(\"%s\")\n", server_hostname);
exit(EXIT_FAILURE);
}
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET; // ipv4
hints.ai_socktype = SOCK_STREAM; // tcp
hints.ai_flags = AI_PASSIVE; // fill in my IP for me
sprintf(portNum, "%d", server_port);
getaddrinfo(NULL, portNum, &hints, &res);
sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (sockfd == -1) {
perror("socket");
exit(EXIT_FAILURE);
}
/* Do the actual connection. */
if (connect(sockfd, res->ai_addr, res->ai_addrlen) == -1) {
perror("connect");
return EXIT_FAILURE;
}
while (1) {
if (signal(SIGINT, sig_handler)) {
break;
}
puts("connected to the server");
puts("-----------------");
puts("|1 - listLocal| \n|2 - listServer| \n|3 - sendFile| \n|4 - help| \n|5 - exit| ");
puts("-----------------");
while (1) {
scanf("%d", &select);
switch (select) {
case 1: // list files of client's directory
system("find . -maxdepth 1 -type f | sort");
break;
case 2: // listServer
puts("---- Files btw Server and the Client ----");
for (j = 0; j < i; ++j) {
puts(client_server_files[j]);
}
break;
case 3: // send file
memset(file_path, 0, sizeof file_path);
scanf("%s", file_path);
memset(remote_file, 0, sizeof remote_file);
// send file name to server
sprintf(remote_file, "%s", file_path);
send(sockfd, remote_file, sizeof(remote_file), 0);
filefd = open(file_path, O_RDONLY);
if (filefd == -1) {
perror("open send file");
//exit(EXIT_FAILURE);
break;
}
while (1) {
read_return = read(filefd, buffer, BUFSIZ);
if (read_return == 0)
break;
if (read_return == -1) {
perror("read");
//exit(EXIT_FAILURE);
break;
}
if (write(sockfd, buffer, read_return) == -1) {
perror("write");
//exit(EXIT_FAILURE);
break;
}
}
// add files in char pointer array
client_server_files[i++] = file_path;
close(filefd);
break;
case 5:
free(user_input);
free(server_reply);
exit(EXIT_SUCCESS);
default:
puts("Wrong selection!");
break;
}
}
}
free(user_input);
free(server_reply);
exit(EXIT_SUCCESS);
}
I fixed most of the bugs that others have mentioned.
Key points to get multithread/multiclient working:
Eliminate mutex.
Consolidate all arrays previously indexed by socket_index into a new "control" struct. main thread does a malloc for the struct, fills it in, and passes off the struct pointer to the thread.
Remove pthread_join from main thread and run all threads detached. main no longer does any close/cleanup for the client thread.
client thread now does the close/cleanup/free.
Even with all that, the server/client code still needs some work, but now, it does work with multiple simultaneous client connections which I believe was the main issue.
Note: I've answered a similar question before: executing commands via sockets with popen() Pay particular attention to the discussion of the "flag" character.
Anyway, Here's the code. I've cleaned it, annotated the bugs and fixes and wrapped the old/new code with #if 0. Note that some of the "old" code isn't purely original code, but an interim version of mine. [please pardon the gratuitous style cleanup]:
server.c:
/*
Soner
Receive a file over a socket.
Saves it to output.tmp by default.
Interface:
./executable [<port>]
Defaults:
- output_file: output.tmp
- port: 12345
*/
#define _XOPEN_SOURCE 700
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <netdb.h> /* getprotobyname */
#include <netinet/in.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <unistd.h>
#include <pthread.h>
// NOTE: this consolidates four arrays that were indexed by socket_index
struct client {
socklen_t client_len;
struct sockaddr_in client_address;
int client_sockfd;
pthread_t thread;
};
// NOTE: no longer used/needed for true multiclient
#if 0
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
#endif
// NOTE/BUG: this didn't provide enough space for a 5 digit port + EOS char
#if 0
enum { PORTSIZE = 5 };
#else
enum { PORTSIZE = 6 };
#endif
void *forClient(void *ptr);
void
sig_handler(int signo)
{
if (signo == SIGINT)
printf("!! OUCH, CTRL - C received by server !!\n");
}
int
main(int argc, char **argv)
{
struct addrinfo hints,
*res;
int enable = 1;
//int filefd; // NOTE: this is never initialized/used
int server_sockfd;
unsigned short server_port = 12345u;
char portNum[PORTSIZE];
// NOTE: now all client related data is malloc'ed
#if 0
int socket_index = 0;
#else
struct client *ctl;
#endif
if (argc != 2) {
fprintf(stderr, "Usage ./server <port>\n");
exit(EXIT_FAILURE);
}
server_port = strtol(argv[1], NULL, 10);
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET; // ipv4
hints.ai_socktype = SOCK_STREAM; // tcp
hints.ai_flags = AI_PASSIVE; // fill in my IP for me
sprintf(portNum, "%d", server_port);
getaddrinfo(NULL, portNum, &hints, &res);
server_sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (server_sockfd == -1) {
perror("socket");
exit(EXIT_FAILURE);
}
if (setsockopt(server_sockfd, SOL_SOCKET, (SO_REUSEPORT | SO_REUSEADDR), &enable, sizeof(enable)) < 0) {
perror("setsockopt(SO_REUSEADDR) failed");
exit(EXIT_FAILURE);
}
if (bind(server_sockfd, res->ai_addr, res->ai_addrlen) == -1) {
perror("bind");
exit(EXIT_FAILURE);
}
if (listen(server_sockfd, 5) == -1) {
perror("listen");
exit(EXIT_FAILURE);
}
fprintf(stderr, "listening on port %d\n", server_port);
// NOTE: we want the threads to run detached so we don't have to wait
// for them to do cleanup -- the thread now does its own close/cleanup
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr,1);
while (1) {
// NOTE/BUG: using a fixed list, if you actually let threads detach,
// you don't know which thread completes allowing its control struct
// to be reused
// the solution is to allocate a fresh one, fill it, pass it to the
// thread and let the _thread_ do all the closes and cleanup
#if 0
ctl = &control_list[socket_index];
#else
ctl = malloc(sizeof(struct client));
if (ctl == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
#endif
ctl->client_len = sizeof(ctl->client_address);
puts("waiting for client");
ctl->client_sockfd = accept(server_sockfd,
(struct sockaddr *) &ctl->client_address, &ctl->client_len);
if (ctl->client_sockfd < 0) {
perror("Cannot accept connection\n");
close(server_sockfd);
exit(EXIT_FAILURE);
}
// NOTE: we're running the threads detached now and we're passing down
// extra information just in case the client loop needs it
#if 0
pthread_create(&ctl->thread, NULL, forClient, ctl);
#else
pthread_create(&ctl->thread, &attr, forClient, ctl);
#endif
#if 0
if (BUFSIZ == socket_index) {
socket_index = 0;
}
else {
++socket_index;
}
#endif
// NOTE/BUG: this is why you couldn't do multiple clients at the same
// time -- you are doing a thread join
// but you _had_ to because the main thread didn't know when a thread
// was done with the control struct without the join
#if 0
pthread_join(threads[socket_index], NULL);
close(filefd);
close(client_sockfd[socket_index]);
#endif
}
return EXIT_SUCCESS;
}
void *
forClient(void *ptr)
{
#if 0
int connect_socket = (int) ptr;
#else
struct client *ctl = ptr;
int connect_socket = ctl->client_sockfd;
#endif
int filefd;
ssize_t read_return;
char buffer[BUFSIZ];
char *file_path;
long long file_length;
char receiveFileName[BUFSIZ];
//int ret = 1;
// Thread number means client's id
printf("Thread number %ld\n", pthread_self());
// NOTE: to run parallel threads, this prevents that
#if 0
pthread_mutex_lock(&mutex1);
#endif
// until stop receiving go on taking information
while (recv(connect_socket, receiveFileName, sizeof(receiveFileName), 0)) {
// NOTE/FIX2: now we have the client send us the file length so we
// know when to stop the read loop below
file_length = strtoll(receiveFileName,&file_path,10);
if (*file_path != ',') {
fprintf(stderr,"syntax error in request -- '%s'\n",
receiveFileName);
exit(EXIT_FAILURE);
}
file_path += 1;
fprintf(stderr, "is the file name received? ? => %s [%lld bytes]\n",
file_path,file_length);
// NOTE: if you want to see _why_ sending the length is necessary,
// uncomment this line and the "unable to send two files" bug will
// reappear
//file_length = 1LL << 62;
filefd = open(file_path,
O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if (filefd == -1) {
perror("open");
exit(EXIT_FAILURE);
}
// NOTE/BUG2/FIX: now we only read up to what we're told to read
// previously, we would keep trying to read, so on the _second_
// send, our read call here would get the data that _should_ have
// gone into the recv above
// in other words, we'd lose synchronization with what the client
// was sending us [and we'd put the second filename into the first
// file as data at the bottom]
for (; file_length > 0; file_length -= read_return) {
read_return = BUFSIZ;
if (read_return > file_length)
read_return = file_length;
read_return = read(connect_socket, buffer, read_return);
if (read_return == -1) {
perror("read");
exit(EXIT_FAILURE);
}
if (read_return == 0)
break;
if (write(filefd, buffer, read_return) == -1) {
perror("write");
exit(EXIT_FAILURE);
}
}
fprintf(stderr,"file complete\n");
// NOTE/BUG: filefd was never closed
#if 1
close(filefd);
#endif
}
#if 0
pthread_mutex_unlock(&mutex1);
#endif
fprintf(stderr, "Client dropped connection\n");
// NOTE: do all client related cleanup here
// previously, the main thread was doing the close, which is why it had
// to do the pthread_join
close(connect_socket);
free(ctl);
// NOTE: this needs a void * value like below
#if 0
pthread_exit(&ret);
#endif
return (void *) 0;
}
client.c:
/*
Soner
Send a file over a socket.
Interface:
./executable [<sever_hostname> [<port>]]
Defaults:
- server_hostname: 127.0.0.1
- port: 12345
*/
#define _XOPEN_SOURCE 700
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <netdb.h> /* getprotobyname */
#include <netinet/in.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <unistd.h>
// NOTE/BUG: this didn't provide enough space for a 5 digit port + EOS char
#if 0
enum { PORTSIZE = 5 };
#else
enum { PORTSIZE = 6 };
#endif
// NOTE2: the "volatile" attribute here is critical to proper operation
volatile int signo_taken;
// NOTE/BUG2: don't use BUFSIZ when you really want something else
#define MAXFILES 1000
void
sig_handler(int signo)
{
// NOTE/BUG2/FIX: doing printf within a signal handler is _not_ [AFAIK] a
// safe thing to do because it can foul up the internal structure data of
// stdout if the base task was doing printf/puts and the signal occurred
// in the middle -- there are a number of other restrictions, such as
// _no_ malloc, etc.
// so, just alert the base layer and let it handle things when it's in a
// "safe" state to do so ...
signo_taken = signo;
}
int
main(int argc, char **argv)
{
struct addrinfo hints,
*res;
char *server_hostname = "127.0.0.1";
char file_path[BUFSIZ];
char *server_reply = NULL;
char *user_input = NULL;
char buffer[BUFSIZ];
int filefd;
int sockfd;
struct stat st;
ssize_t read_return;
struct hostent *hostent;
unsigned short server_port = 12345;
char portNum[PORTSIZE];
char remote_file[BUFSIZ];
int select;
char *client_server_files[MAXFILES];
int i = 0;
int j;
// char filename_to_send[BUFSIZ];
if (argc != 3) {
fprintf(stderr, "Usage ./client <ip> <port>\n");
exit(EXIT_FAILURE);
}
server_hostname = argv[1];
server_port = strtol(argv[2], NULL, 10);
/* Prepare hint (socket address input). */
hostent = gethostbyname(server_hostname);
if (hostent == NULL) {
fprintf(stderr, "error: gethostbyname(\"%s\")\n", server_hostname);
exit(EXIT_FAILURE);
}
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET; // ipv4
hints.ai_socktype = SOCK_STREAM; // tcp
hints.ai_flags = AI_PASSIVE; // fill in my IP for me
sprintf(portNum, "%d", server_port);
getaddrinfo(NULL, portNum, &hints, &res);
sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (sockfd == -1) {
perror("socket");
exit(EXIT_FAILURE);
}
/* Do the actual connection. */
if (connect(sockfd, res->ai_addr, res->ai_addrlen) == -1) {
perror("connect");
return EXIT_FAILURE;
}
// NOTE/FIX2: this only needs to be done once, since the desired action is
// to [cleanly] stop the program
signal(SIGINT, sig_handler);
// NOTES:
// (1) instead of using signo_taken as is done, below there are alternate
// ways to handle signals with sigsetjmp and siglongjmp
// (2) but the main reason to _not_ do this is to prevent the handler
// from messing up a file transfer
while (! signo_taken) {
puts("connected to the server");
#if 0
puts("-----------------");
puts("|1 - listLocal| \n|2 - listServer| \n|3 - sendFile| \n|4 - help| \n|5 - exit| ");
puts("-----------------");
#endif
while (! signo_taken) {
// NOTE: not a bug, but it helps the user to output the menu each
// time
#if 1
puts("-----------------");
puts("|1 - listLocal| \n|2 - listServer| \n|3 - sendFile| \n|4 - help| \n|5 - exit| ");
puts("-----------------");
#endif
scanf("%d", &select);
// NOTE: we should check this after _any_ call that requests user
// input (e.g. scanf, fgets(...,stdin), etc.)
if (signo_taken)
break;
switch (select) {
case 1: // list files of client's directory
system("find . -maxdepth 1 -type f | sort");
break;
case 2: // listServer
puts("---- Files btw Server and the Client ----");
for (j = 0; j < i; ++j) {
puts(client_server_files[j]);
}
break;
case 3: // send file
fputs("Enter filename: ",stdout);
fflush(stdout);
memset(file_path, 0, sizeof file_path);
scanf("%s", file_path);
if (signo_taken)
break;
// NOTE/FIX: check the file _before_ sending request to server
// and we [now] want to know the file length so we can send
// that to the server so it will know when to stop receiving
#if 1
filefd = open(file_path, O_RDONLY);
if (filefd == -1) {
perror("open send file");
// exit(EXIT_FAILURE);
break;
}
// get the file's byte length
if (fstat(filefd,&st) < 0) {
perror("stat send file");
// exit(EXIT_FAILURE);
close(filefd);
break;
}
#endif
// send file name to server
memset(remote_file, 0, sizeof(remote_file));
#if 0
sprintf(remote_file, "%s", file_path);
#else
sprintf(remote_file, "%lld,%s",
(long long) st.st_size,file_path);
#endif
send(sockfd, remote_file, sizeof(remote_file), 0);
// NOTE/BUG2: this should be done above to _not_ confuse server
#if 0
filefd = open(file_path, O_RDONLY);
if (filefd == -1) {
perror("open send file");
// exit(EXIT_FAILURE);
break;
}
#endif
while (1) {
read_return = read(filefd, buffer, BUFSIZ);
if (read_return == 0)
break;
if (read_return == -1) {
perror("read");
// exit(EXIT_FAILURE);
break;
}
if (write(sockfd, buffer, read_return) == -1) {
perror("write");
// exit(EXIT_FAILURE);
break;
}
}
close(filefd);
// add files in char pointer array
// NOTE/BUG2: file_path gets overwritten, so we must save it
// here
#if 0
client_server_files[i++] = file_path;
#else
if (i < MAXFILES)
client_server_files[i++] = strdup(file_path);
#endif
puts("file complete");
break;
case 5:
free(user_input);
free(server_reply);
exit(EXIT_SUCCESS);
break;
default:
puts("Wrong selection!");
break;
}
}
}
// NOTE/FIX2: we output this here when it's save to do so
if (signo_taken)
printf("!! OUCH, CTRL - C received on client !!\n");
free(user_input);
free(server_reply);
exit(EXIT_SUCCESS);
}
UPDATE:
I have solved my connection-interruption problem but signal is still occurring. I left two problems more times file sending and signal handling
I have reworked the client signal handling so that it works as expected [which is to print the message and stop the client].
I have also fixed the problem where only one file could be sent. To understand this, consider the actions of both client and server.
To send a file, client prompts for filename, does a send call with the filename in it. It then opens the file and does a read/write loop to send the file data to the server [and then closes the file descriptor].
To receive a file, server does a recv call to get the filename. It then opens the file [for output] and does a read/write to write the data from the socket to the file [and then closes the file descriptor].
Here is the problem: The termination condition for the server's read/write loop is to wait until the read(connect_socket,...) call returns 0. But, it will not return zero [unless the socket has been closed].
So, now the client does a send call to send the second filename. But, the data for this, instead of going into the server's recv call, will merely be part of the read buffer. That is, the second filename will just be appended to the first file as data.
The solution is to have the client tell the server what the file size is. So, instead of the client doing a send of filename, it now does a send of filesize,filename
The server will now decode this filesize and split off the filename in the recv buffer. Now, the server's read/write loop will maintain a count of how many bytes still need to be read and the loop stops when the remaining count hits zero.
There were one or two other minor bugs. I've updated both client.c and server.c with the bug fixes and annotations

Shrinking in size when i use read() and write() in c sockets under linux

I am programming a client server acting like downloader server. The client requests a file name from the server and then the server searches for the file if it exists or not. It works fine, but I observe something weird: when the client downloads the file requested from the server the size of downloaded file is not the same size of the original file.
Here is server code :
// Server.c
#include <errno.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdarg.h> /* ANSI C header file */
#include <syslog.h> /* for syslog() */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
/* Following shortens all the typecasts of pointer arguments: */
#define SA struct sockaddr
#define ListenQ 5
#define MAXLINE 1024 /* max text line length */
void error(char *msg);
/* to define mode for read() or write() */
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | S_IRGRP | S_IWGRP;
volatile sig_atomic_t eflag = 0;
int listenfd, connfd; /* to define Server file descriptor */
int sockfd, fd; /* to define Client file descriptor */
socklen_t clilen;
struct sockaddr_in servaddr;
char buffer[MAXLINE + 1];/* define buffer to send and recive with */
char _fileName[128];
int n; /* to count from reading or wrinting in sockets */
int portno, stringlen;
int CmpValue, i;
int fd_Cli;
int daemon_proc; /* set nonzero by daemon_init() */
uint8_t state; /* define 1 byte state for existance files in sever */
uint8_t secret;
//char fileName[128];
//char *fileTocmp="abc.txt";
int main(int argc, char **argv)
{
/*Error checking for providing appropirate port# */
if (argc < 2)
error("Error,no port provided, please enter the port#:22011 \n");
/*open listening socket for server note the Socket not socket */
listenfd = socket(AF_INET, SOCK_STREAM, 0);
/*
* to convert the port# from ascii to int to deal with it as int in
* address structure
*/
portno = atoi(argv[1]);
//if(portno!=22011)
//error(" please enter the port#:22011\n");
// to zero the structre adress
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(portno);
// to bind the adresses to server
bind(listenfd, (SA *) & servaddr, sizeof(servaddr));
//to put the open socekt descrptor
//to put the open socekt descrptor
listen(listenfd, ListenQ);
puts("Waiting for incoming connections...\n");
for (;;) {
clilen = sizeof(servaddr);
/*
* To handle Interupt which leads Accept() to interupt so here
* to restart Accept()
*/
if ((connfd = accept(listenfd, (SA *) & servaddr, &clilen)) < 0) {
if (errno == EINTR)
continue; /* back to for() */
else
error("accept error");
}
//bzero(&buffer,sizeof(buffer));
//n=read(connfd,&buffer,sizeof(buffer));
secret = 0x55;
sprintf(buffer, "%d", secret);
n = write(connfd, &buffer, sizeof(buffer));
printf("Sending Byte 0x55: (%x) to client (%s:%d) .\n", secret,
inet_ntoa(servaddr.sin_addr), ntohs(servaddr.sin_port));
bzero(&buffer, sizeof(buffer));
n = read(connfd, &buffer, sizeof(buffer));
printf("recived 0XAA is :%s from the client\n", buffer);
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
//this function to read and write from and to client
printf("(%s:%d) connected.\n", inet_ntoa(servaddr.sin_addr),
ntohs(servaddr.sin_port));
printf("waiting to provide file name From: (%s:%d) \n\n",
inet_ntoa(servaddr.sin_addr), ntohs(servaddr.sin_port));
/* to copy the file name to var fileName */
//strncpy(fileName,fileTocmp,128);
for (;;) {
//bzero(&buffer,sizeof(buffer));
//n=read(connfd,&buffer,sizeof(buffer));
/////////////////////////////////////////////
bzero(&buffer, sizeof(buffer));
n = read(connfd, &buffer, sizeof(buffer));
printf("Recived file name :%s from client: (%s:%d)\n", buffer,
inet_ntoa(servaddr.sin_addr), ntohs(servaddr.sin_port));
//printf("\n");
/*
///////////////////////////////////////////
* Hehow to check if file exists in cre is the core of
* comparing files at server if exists or not.
///////////////////////////////////////////
*/
/*
* compare the filename provided by User with the file exist
* in server
*/
//
char *p;
if ((p = strchr(buffer, '\n')))
*p = 0;
//CmpValue=access (buffer, F_OK|R_OK| W_OK);
printf("the buffer now is : %s\n", buffer);
/////////////////////////////
strncpy(_fileName, buffer, 128);
CmpValue = access(buffer, F_OK | R_OK);
printf("the value of CMPaccess is : %d\n", CmpValue);
if (CmpValue == 0) {
bzero(&buffer, sizeof(buffer));
state = 1;
/* to print the state=1 to buffer */
sprintf(buffer, "%d", state);
/* to print the state=1 to stdout */
printf("Sending (%d) to the client : (%s:%d)\n", state,
inet_ntoa(servaddr.sin_addr),
ntohs(servaddr.sin_port));
printf("\n");
/* to send the state=1 to client */
n = write(connfd, &buffer, sizeof(buffer));
///////////////////////////////////////////
printf("here is buffer before Func open is : %s\n",
buffer);
fd = open(_fileName, O_RDONLY);
/* To Handle the file descriptor error. */
if (fd < 0) {
bzero(&buffer, sizeof(buffer));
printf
("Sending Error value : %s (to client# %s:%d) \n",
strerror(errno), inet_ntoa(servaddr.sin_addr),
ntohs(servaddr.sin_port));
/* to print the ERROR to buffer */
snprintf(buffer, sizeof(buffer), "ERROR(%d):%s", errno,
strerror(errno));
/* to send the ERROR to client */
n = write(connfd, &buffer, sizeof(buffer));
if (n < 0) {
error("Error,Writing to socket \n");
}
continue;
}
int serverRead;
while ((serverRead = read(fd, buffer, MAXLINE + 1) > 0)) {
/* to read from open file descriptor */
n = write(connfd, &buffer, n);
printf("------- the value of serverRead is : %d\n",
serverRead);
if (n < 0) {
error("Error,Reading from socket \n");
}
}
printf("hon ya 3rs 5lset writing ............\n");
close(connfd);
//printf("buffer now is : %s\n",buffer);
//buffer[n] = '\0';
//close(connfd);
/*
* to send the buffer contents which "is from reading
* file descripotr" to client
*/
} else {
bzero(&buffer, sizeof(buffer));
state = 0;
/* to print the state=0 to stdout */
printf("Sending (%d) to the client : (%s:%d)\n", state,
inet_ntoa(servaddr.sin_addr),
ntohs(servaddr.sin_port));
printf("\n");
/* to print the state=0 to buffer */
sprintf(buffer, "%d", state);
n = write(connfd, &buffer, sizeof(buffer));
if (n < 0) {
error("Error,Writing to socket \n");
}
/* to send the state=0 to client */
}
} // end of for
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
//this function to read and write from and to client
//close(connfd);
}
//return 0;
}
void error(char *msg)
{
perror(msg);
exit(1);
}
So I haven't found a solution. Maybe it is related to the open and read implementations in Unix syscall?
After you read some number of bytes from the file, that should be the number of bytes that you write. To me, it seems that you are writing some number of bytes that is not related to the number read at all:
int serverRead;
while ((serverRead = read(fd, buffer, MAXLINE + 1) > 0)) {
/* to read from open file descriptor */
n = write(connfd, &buffer, n);
printf("------- the value of serverRead is : %d\n",
serverRead);
if (n < 0) {
error("Error,Reading from socket \n");
}
}
Instead, you should change the way you call write() to write out serverRead bytes from buffer. Realize that writes can be shorter than the requested amount, so you need to protect against that with a loop around the write() call itself.
ssize_t bytes_written = 0;
while (bytes_written < serverRead) {
n = write(connfd, buffer + bytes_written, serverRead - bytes_written);
if (n > 0) {
bytes_written += n;
continue;
}
//...handle error
}

Stoping the recv from server when client finishes reading and sending the file

Basically i use a recv in a while in order to read the data sent from my client. Client finishes reading the file and sending it but server remains in the while. How can i notify the server that the file sending is done meaning feof on clients side?
SERVER
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/types.h> /*For Sockets*/
#include <sys/socket.h> /*For Sockets*/
#include <netdb.h> /*For gethostbyaddr()*/
#include <netinet/in.h> /*For internet sockets*/
#include <dirent.h>
/*Function for creating the lof file of Server*/
void log_event (char *message,char *filename)
{
FILE *file;
char *log_this;
time_t system_time; //Get the system time
time(&system_time);
log_this=strcat(ctime(&system_time),message); //Create the message to log
/*Check for filename and log as appropiate*/
if (filename!=NULL)
{
file = fopen(filename,"a+");
fprintf(file,"%s",log_this); /*writes the message*/
fclose(file); /*done!*/
}
else
{
file = fopen("ftp_tracelog.txt","a+");
fprintf(file,"%s",log_this); /*writes the message*/
fclose(file); /*done!*/
}
}
int main (int argc,char *argv[])
{
/*DECLERATIONS*/
char *filename;
char message [1024];
char *temp;
char temp_2[1024];
char buf[1024];
char *p=buf;
ssize_t bytesRemaining = 1024;
ssize_t bytesRemaining2 = 50;
char request[50];
char command[5];
char c[50];
char copy[1024]="COPY_OF_";
FILE *fp;
DIR *dp;
char list[1024];
int port,sock,newsock,serverlen,clientlen,fname_len,recvMsgSize,i,len,count;
struct sockaddr_in server,client;
struct sockaddr *serverptr, *clientptr;
struct hostent *rem;
struct dirent *ep;
/*END OF DECLERATIONS*/
/*Check for required arguments and get them as appropiate*/
if (argc < 2) {
/* Check if server's port number is given */
printf("Please give the port number!!!\n");
exit(1);
}
/*if server's port number is given and filename for log is given*/
if(argc>2){
filename=argv[1];
port=atoi(argv[2]);
}
/*If only port is given*/
if (argc==2){
port=atoi(argv[1]);
filename=NULL;
}
temp="--Server is Starting!!--";
sprintf(message,"%s\n",temp);
log_event(message,filename);
/* Create socket */
if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{perror("socket"); exit(1); }
server.sin_family = PF_INET; /* Internet domain */
server.sin_addr.s_addr = htonl(INADDR_ANY); /* My Internet address */
server.sin_port = htons(port); /* The given port */
serverptr = (struct sockaddr *) &server;
serverlen = sizeof (server);
/* Bind socket to address */
if (bind(sock, serverptr, serverlen) < 0) {
perror("bind"); exit(1); }
/* Listen for connections */
if (listen(sock, 40) < 0) { /* 5 max. requests in queue */
perror("listen"); exit(1); }
temp="---Listening for connections to port";
sprintf(temp_2,"%d----",port);
sprintf(message,"%s:%s\n",temp,temp_2);
log_event(message,filename);
/*Accepting Connecttion*/
while(1) {
clientptr = (struct sockaddr *) &client;
clientlen = sizeof(client);
/* Accept connection */
if ((newsock = accept(sock, clientptr, &clientlen)) < 0){
perror("accept"); exit(1);}
/* Find client's address */
if ((rem = gethostbyaddr((char *) &client.sin_addr.s_addr,
sizeof (client.sin_addr.s_addr), client.sin_family)) == NULL) {
perror("gethostbyaddr"); exit(1);}
temp="----Accepted connection from ";
sprintf(temp_2,"%s----", rem -> h_name);
sprintf(message,"%s:%s\n",temp,temp_2);
log_event(message,filename);
/* Create child for serving the client */
switch (fork()) {
case -1:
perror("fork"); exit(1);
case 0: /* Child process */
do{
/* Receive message from client */
if ((recvMsgSize = recv(newsock,request,sizeof(request),0))< 0)
perror("recv() failed");
printf("%s\n",request);
//printf("%s\n",command);
/*IF YOU ARE GOING TO EXECUTE AN LS COMMAND*/
if (strcmp(request,"ls")==0)
{
dp = opendir ("./");
if (dp != NULL)
{ /*LOG LS REQUEST*/
temp="--Client ";
sprintf(temp_2,"%s requested ls -------",rem -> h_name);
sprintf(message,"%s:%s\n",temp,temp_2);
log_event(message,filename);
/*SEND ALL DIRECTORY LISTING*/
while (ep = readdir (dp))
{
strcpy(list,ep->d_name);
//printf("sending:%s\n",list);
if (send(newsock,list,sizeof(list), 0)!= sizeof(list))
perror("send() sent a different number of bytes than expected");
}
//IF DIRECORY IS FINISHED SEND A LAST MESSAGE FOR ENDING
(void) closedir (dp);
if (send(newsock,"end",sizeof("end"), 0)!= sizeof("end"))
perror("send() sent a different number of bytes than expected");
}
else
perror ("Couldn't open the directory");
}
/*IF THE COMMAND IS PUT*/
if (strcmp(request,"put")==0)
{
sprintf(buf,"");
printf("execute put!!\n");
do{
ssize_t recvd;
while (bytesRemaining) {
if (( recvd =recv(newsock,p,bytesRemaining,0))< 0){
perror("recv() failed");}
bytesRemaining -= recvd; // keep track of bytes left
p += recvd;
}
}while (buf=="");
strcat(copy,buf);
fp=fopen(copy,"w+");
count=0;
while (c!="")
{
bzero(c,sizeof(c));
if ((recvMsgSize = recv(newsock,c,sizeof(c),0))< 0)
perror("recv() failed");
fprintf(fp,"%s",c);
}
fclose(fp);
printf("!!DONE!!!!\n");
//printf("%s",request);
}
}while (strcmp(request,"end")!=0); //run until client sents end request
/*LOG EXIT OF CLIENT*/
temp="--Client";
sprintf(temp_2,"%s is disconnected---",rem -> h_name);
sprintf(message,"%s:%s\n",temp,temp_2);
log_event(message,filename);
close(newsock); /* Close socket */
exit(0);
} /* end of switch */
}/*end of while*/
}
CLIENT
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
int main (int argc,char *argv[])
{
int port, sock, serverlen,recvMsgSize,was_read;
int fname_len,msg_len,request_len;
char buf[256];
char *fname;
char request[50];
char list[1024];
char msg[512];
char op[1000];
char temp[5];
char *temp3;
char read;
FILE *fp;
char b[50];
struct sockaddr_in server;
struct sockaddr *serverptr;
struct hostent *rem;
temp3="put";
/* Are server's host name and port number given? */
if (argc < 3) {
printf("Please give host name and port number\n"); exit(1);
}
/* Create socket */
if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket");
exit(1);
}
/* Find server address */
if ((rem = gethostbyname(argv[1])) == NULL) {
herror("gethostbyname"); exit(1);
}
/* Convert port number to integer */
port = atoi(argv[2]);
/* Internet domain */
server.sin_family = PF_INET;
bcopy((char *) rem -> h_addr, (char *) &server.sin_addr,
rem -> h_length);
/*Server's Internet address and port*/
server.sin_port = htons(port);
serverptr = (struct sockaddr *) &server;
serverlen = sizeof(server);
if (connect(sock, serverptr, serverlen) < 0) { /* Request connection */
perror("connect");
exit(1); }
printf("Requested connection to host %s port %d\n", argv[1], port);
do{
printf("Please enter request\n:");
scanf("%s",request);
/* Send the string to the server */
if (send(sock,request,sizeof(request), 0)!= sizeof(request))
perror("send() sent a different number of bytes than expected");
if(strcmp(request,"ls")==0)
{
sprintf(list,"");
/*Recieve from server*/
while(strcmp(list,"end")!=0){
if ((recvMsgSize = recv(sock,list,sizeof(list),0))< 0)
perror("recv() failed");
if(strcmp(list,"end")!=0){
printf("%s\n",list);
}
}
bzero(request,sizeof(request));
}
/*Command for put*/
if(strcmp(request,"put")==0)
{ bzero(request,sizeof(request));
bzero(list,sizeof(list));
printf("Please enter filename:\n");
scanf("%s",list);
//printf("%s",list);
if (send(sock,list,sizeof(list), 0)!= sizeof(list))
perror("send() sent a different number of bytes than expected");
fp=fopen(list,"r");
if(fp==NULL)
{
puts ( "Cannot open target file" ) ;
fclose (fp) ;
exit(0);
}
while(!feof(fp))
{
bzero(b,sizeof(b));
int was_read = fread(b, sizeof(char),50,fp);
if (send(sock,b,(sizeof (char) * was_read), 0)!= (sizeof (char) * was_read))
perror("send() sent a different number of bytes than expected");
}
zero(b,sizeof(b));
if (send(sock,b,sizeof(b), 0)!= sizeof(b))
perror("send() sent a different number of bytes than expected");
}
}while (strcmp(request,"end")!=0);
close(sock); /* Close socket */
exit(0);
}
One method is to have the client close the socket at the end of the file. The server will successfully receive 0 bytes from recv(), which means the other end cleanly closed the socket. I notice that you do not currently detect this return value in your server code, but you should.
I notice that your protocol has the ability to request more than one file. In this case, you will need to do something like send the number of bytes in the file before sending the actual file, then the server will know how many bytes to expect. Or, you can do like FTP does and open a second socket connection for the file data (one file at a time).
As a stylistic note, the indenting in your code is terrible. It's hard to read to find out where the blocks start and end. I would reject this code in a code review purely on reasons of formatting.

Resources