C sockets upload and download a file in same request - c

I am trying to receive a file thats uploaded by the client and in the same socket descriptor send a command download a file from the server in chunks
The issue is if the socket descriptors are in different files things work flawlessly but if its the same file client and server programs are hanging up
The second problem is even if its in different files I could not send the client a message saying that the file is received
Can anyone please advice
PS- to run the program might need to create a file named fileclient.txt and enter some random text
server.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#define PORT 8088
int main(void){
int fd =0, confd = 0,b,tot;
struct sockaddr_in serv_addr;
char buff[1025];
fd = socket(AF_INET, SOCK_STREAM, 0);
printf("Socket created\n");
memset(&serv_addr, '0', sizeof(serv_addr));
memset(buff, '0', sizeof(buff));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(PORT);
bind(fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
listen(fd, 10);
while(1){
confd = accept(fd, (struct sockaddr*)NULL, NULL);
if (confd==-1) {
perror("Accept");
continue;
}
//READ COMMAND reads first 4 characters of the buffer
int bf = recv(confd, buff, 1024,0);
char *filecmd = malloc(5 * sizeof(char));
memcpy(filecmd, buff, 4);
filecmd[4] = 0; //string termination
//if command is DOWN send chunks to the client
if(strcmp(filecmd, "DOWN") == 0){
int bt;
char sendbuffer[100];
FILE *fpdl = fopen("file.txt", "rb");
if(fpdl == NULL){
perror("File");
return 2;
}
while( (bt = fread(sendbuffer, 1, sizeof(sendbuffer), fpdl))>0 ){
send(confd, sendbuffer, bt, 0);
}
fclose(fpdl);
}
//if DOWN did not match that means client is uploading a file write down the file on server
else{
FILE* fp = fopen( "newfile.txt", "wb");
tot=0;
tot+=bf;
fwrite(buff, 1, bf, fp);
if(fp != NULL){
while( (b = recv(confd, buff, 1024,0))> 0 ) {
tot+=b;
fwrite(buff, 1, b, fp);
}
printf("Received byte: %d\n",tot);
if (b<0) perror("Receiving Error");
fclose(fp);
} else {
perror("File");
}
}
free(filecmd);
close(confd);
}
return 0;
}
client.c
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
#define PORT 8088
int main(int argc, char *argv[]){
int sfd =0, n=0, b;
char sendbuffer[100];
struct sockaddr_in serv_addr;
sfd = socket(AF_INET, SOCK_STREAM, 0);
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
b=connect(sfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
if (b==-1) {
perror("Connect");
return 1;
}
FILE *fp = fopen("fileclient.txt", "rb");
if(fp == NULL){
perror("File");
return 2;
}
while( (b = fread(sendbuffer, 1, sizeof(sendbuffer), fp))>0 ){
send(sfd, sendbuffer, b, 0);
}
fclose(fp);
char *rpccommand = "DOWN";
send(sfd , rpccommand , strlen(rpccommand) , 0 );
char buffer[1024] = {0};
FILE* fpx = fopen( "downloadfile.txt", "wb");
int tot=0, bn;
if(fpx != NULL){
while( (bn = recv(sfd, buffer, 1024,0))> 0 ) {
tot+=bn;
fwrite(buffer, 1, bn, fpx);
}
printf("Received byte: %d\n",tot);
if (bn<0) perror("Receiving");
fclose(fpx);
} else {
perror("File");
}
return 0;
}

You seem to expect that the string "DOWN" is recognized by the server and a download is triggered. This is very unlikely to happen.
TCP connections do not take care about granularity of data that is put into the socket. If you put in 1000 bytes at once on one side, it is not guaranteed that those 1000 bytes are received in one go.
You may receive either 1000 bytes or 500 + 500 bytes of 999 + 1 bytes.
Same applies if you send with multiple requests. Putting in 1000+4 bytes could result in receiving 1000+4 or 1004 or 500+500+4 bytes or any other combination.
This means that you cannot simply rely on receiving all bytes for the file upload first and then wait for another command ("DOWN") or another file. It is very likely that you will receive the "DOWN" together with the last bytes of the uploaded file and simply store them into the output file.
The same applies for download direction. The client would not be able to distinguish a file download from an "upload done" notification.
To solve your problem you need to introduce more logic into your protocol. There are various options:
Use 1 socket and 1 connection for each operation or each direction. No need to mix everything into a single socket.
Add some indication about file upload, e.g. total length to be expected in front of your upload.
Use 1 socket for control flow and multiple others for data transfer (see FTP for details)

Related

UDP File Transfer Program in C, While loops won't do anything

I am trying to make a file transfer program with UDP, using a stop and wait protocol. The client prompts user to enter the text file to transfer and if exist, the server will find it and send it back in packets (80 char at a time). The part where the client sends the file name and the server receives it works, but once I get into the while(1) loop for the file transfer, nothing happens. Not sure why this is the case, any help will be great! thanks!
Client.c
`#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libgen.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <errno.h>
/*This source file lies the client side of the file transfer. Its job is to open a
socket and ask to connect with server
It should then ask user for input of the text file they wish to transfer.
Once server sends out the file in packets, the client will then place this data in an
output.txt file, viewable for the user*/
typedef struct packet{
char pktData[80]; //data in each packet
}Packet;
typedef struct frame{
int frame_kind; //ACK:0, SEQ:1 FIN:2
int countOfChar; //count of characters in a packet
int sq_no;
int ack;
Packet packet;
}Frame;
int offset = 4;
int main(){
int sockfd = 0; //socket descriptor
int countOfChar = 0; //count of characters in a packet
char buffer[80]; //data in each packet
char fileName[20];
char pktData[80];
//socklen_t addr_size;
int frame_id = 0;
int frame_id2 = 0;
Frame frame_send; //frame being sent to server (for the filename)
Frame frame_recv; //frame being received from the server (for the data)
Frame name_send;
Frame name_recv;
int ack_recv = 1;
struct sockaddr_in serv_addr;
struct sockaddr_in new_addr;
memset(&serv_addr, '0', sizeof(serv_addr));
// Open a socket
if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0){
printf("Error creating socket");
return 1;
}
// Server address structure
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(20000);
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
socklen_t addr_size = sizeof(serv_addr);
//Sending File name
printf("\nConnected to server successfully!\nEnter the file name: ");
scanf("%[^\n]%*c",fileName);
printf("\n");
char buff[20];
strcpy(buff, fileName);
sendto(sockfd, &buff, sizeof(buff), 0, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
int new_addr_size = sizeof(new_addr);
//int addr_size = sizeof(serv_addr);
//writing file into output.txt
FILE *fp = fopen("output.txt", "ab");
//loop until theres no more to read
while(1){
int f_recv_size = recvfrom(sockfd, &frame_recv, sizeof(Frame), 0, (struct sockaddr*)&serv_addr, &addr_size);
if (f_recv_size > 0 && frame_recv.frame_kind == 1 && frame_recv.sq_no == frame_id){
fwrite(frame_recv.packet.pktData, 1, sizeof(frame_recv.packet.pktData), fp);
//printf("[+]Frame %d received with %lu data bytes\n",frame_recv.sq_no, sizeof(frame_recv.packet.pktData));
printf("Frame Received");
frame_send.sq_no = 0;
frame_send.frame_kind = 0;
frame_send.ack = frame_recv.sq_no + 1;
sendto(sockfd, &frame_send, sizeof(frame_send), 0, (struct sockaddr*)&serv_addr, addr_size);
printf("[+]Ack Sent\n");
}else{
printf("[+]Frame Not Received\n");
}
frame_id++;
}
close(sockfd);
return 0;
}
Server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/*This source file lies the server side of the file transfer. Its job is to listen
for a connection and connect with client when prompted.
It should then read the file with the txt file name and start sending out packets of
80 bytes each with the data of the given file name.*/
typedef struct packet{
char pktData[80]; //data in each packet
}Packet;
typedef struct frame{
int frame_kind; //ACK:0, SEQ:1 FIN:2
int countOfChar; //count of characters in a packet
int sq_no;
int ack;
Packet packet;
}Frame;
int main(){
unsigned int size = 0;
int listenfd = 0;
int connfd = 0;
char file_buff[20];
char buffer[80];
char FLAG[] = "NF"; //No file flag
int frame_id = 0;
int frame_id2 = 0;
Frame name_recv;
Frame name_send;
Frame frame_recv;
Frame frame_send;
int ack_recv;
struct sockaddr_in server_addr, client_addr;
char sendBuff[1025];
size = sizeof(client_addr);
listenfd = socket(AF_INET, SOCK_DGRAM, 0); //listening descriptor
printf("Server initiated...\n");
memset(&server_addr, '0', sizeof(server_addr));
memset(sendBuff, '0', sizeof(sendBuff));
//Local address structure
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(20000);
//bind to local address
bind(listenfd, (struct sockaddr*)&server_addr, sizeof(server_addr));
// Receiving File Name
recvfrom(listenfd, &file_buff, sizeof(file_buff), 0, (struct sockaddr*)&client_addr, &size);
printf("Filename requested by client = %s\n",file_buff);
if (access(file_buff, F_OK) != -1 ) {
printf("File exist!\n");
FILE *fp = fopen(file_buff,"rb");
while(1){
if(ack_recv == 1){
frame_send.sq_no = frame_id;
frame_send.frame_kind = 1;
frame_send.ack = 0;
fscanf(fp, "%s ", buffer);
strcpy(frame_send.packet.pktData, buffer);
sendto(listenfd, &frame_send, sizeof(Frame), 0, (struct sockaddr*)&client_addr, sizeof(client_addr));
//printf("[+]Frame %d Sent with %lu data bytes\n",frame_send.sq_no, strlen(frame_send.packet.pktData));
printf("Frame Sent");
}
int addr_size = sizeof(server_addr);
int f_recv_size = recvfrom(listenfd, &frame_recv, sizeof(frame_recv), 0 ,(struct sockaddr*)&client_addr, &size);
if( f_recv_size > 0 && frame_recv.sq_no == 0 && frame_recv.ack == frame_id+1){
printf("[+]Ack Received\n");
ack_recv = 1;
}
else{
printf("[-]Ack Not Received\n");
ack_recv = 0;
}
frame_id++;
}
}
else {
printf("File doesn't exist\n");
write(listenfd, FLAG, sizeof(FLAG));
close(listenfd);
return 0;
}
close(listenfd);
return 0;
}
Sorry for all the clutter and unnecessary variables in advanced, I've been trying so many options but nothing's working.
Server's response in terminal
Client's response in terminal
The first problem is that you never initialize ack_recv in the server program before attempting to read it. Reading an uninitialized variable that hasn't had its address taken triggers undefined behavior.
At the very least, a value besides 1 was read so the server is waiting on a read from the client which never comes because the client is waiting on the server. You need to initialize ack_recv to 1 so that the server sends the first part of the file.
The code has more problems than this, however.
The main problem is it assumes that no packets get lost. UDP doesn't guarantee delivery. So if a packet does get lost, one side will be stuck forever waiting for a packet that doesn't arrive. When reading, each side should use select to allow for a timeout while waiting. If the timeout triggers, it should assume that the last packet sent was lost and resend it.
For the client, this also means that it can get multiple copies of a given sequence number from the server if an ACK gets lost. So it should not increment frame_id until it receives that sequence number.
There's also an infinite loop on both sides, as there is a while (1) loop with no break, return, or exit inside. The server needs to know when to stop sending, and it needs some way to let the client know when it's done.
Also, as a general rule, when debugging network programs you should use tcpdump or wireshark to trace the packets traveling in both directions.

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.

Sending multiple messages through a socket in c

So in this program I am trying to send the file content and file name from client to server in two steps. I tried using memset() to empty the buffer so as to use it for storing the filename, however then I realised that the filename is being passed into the buffer along with the content, so there is no point of memset(). So, I need to separate the two transmissions I was thinking of closing the buffer for first process and then opening it for the second transmission again, I am not sure how to proceed.
Here's my code:
Server.c
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
int main(int argc, char *argv[]){
int fd =0, confd = 0;
struct sockaddr_in serv_addr;
char buff[1025];
int num;
fd = socket(AF_INET, SOCK_STREAM, 0);
printf("Socket created\n");
memset(&serv_addr, '0', sizeof(serv_addr));
memset(buff, '0', sizeof(buff));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(5000);
bind(fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
listen(fd, 10);
while(1){
confd = accept(fd, (struct sockaddr*)NULL, NULL);
FILE* fp = fopen( "create.txt", "wb");
int b = recv(confd, buff, 1024, 0);
if(fp!=NULL){
while(b>0){
fwrite(buff, 1, b, fp);
b = recv(confd, buff, 1024, 0);
}
}
else{
printf("Error!");
}
printf("Got it :)\n");
//printf("Buff before: %s\n", buff);
memset(buff, 0, sizeof(buff));
num = read(confd, buff, 1024);
//printf("Buff after: %s\n", buff);
if(num<0){
printf("error reading the socket");}
else{
printf("File uploaded: %s\n", buff);
}
//close(confd);
fclose(fp);
}
return 0;
}
Client.c
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
int main(int argc, char *argv[]){
int i=0, k=0,num;
char ip[50];
char upfile[50];
char dwfile[50];
for(i=0; i<argc; i++){
if(strcmp(argv[i], "-i")==0){
strcpy(ip, argv[i+1]);
}
else if(strcmp(argv[i],"-u")==0){
strcpy(upfile, argv[i+1]);
k =2;
}
else if(strcmp(argv[i], "-d")==0){
strcpy( dwfile, argv[i+1]);
k=3; }
/* else(argv[i] = "-l"){
}*/
}
printf("%s %s %s", ip, upfile, dwfile);
int sfd =0, n=0, c;
char rbuff[1024];
struct sockaddr_in serv_addr;
memset(rbuff, '0', sizeof(rbuff));
sfd = socket(AF_INET, SOCK_STREAM, 0);
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(5000);
serv_addr.sin_addr.s_addr = inet_addr(ip);
c = connect(sfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
if(c==-1){
perror("Connect");
return 1;
}
if (k==2){
printf("==========This is the upload function");
FILE *fp = fopen(upfile, "rb");
if(fp == NULL){
fprintf(stderr, "oh no!");
return 1;
}
char sendbuffer[100];
int b = fread(sendbuffer, 1, sizeof(sendbuffer),fp);
while(b>0){
send(sfd, sendbuffer, b, 0);
b = fread(sendbuffer, 1, sizeof(sendbuffer),fp);
}
num = write(sfd, upfile, strlen(upfile));
fclose(fp);
printf("Send filename: %s", upfile);
printf("============End upload!");
}
return 0;
}
Can anyone help ?
EDIT1:
Sending the filename before sending the file contents seems to work, but however doing that is printing a long trail of zeroes. For example: File uploaded: tt.txt000000000000000000000....
There are two common solutions: One is to use a separator, a special byte or sequence of bytes, that can't be in the message data and that marks the separator between the two messages. In the case of you sending a binary file it's not really feasible since there are really no safe sequences.
The other common method is to have a special fixed-sized header which contains the length of the data you send. Then you simply send this fixed-sized header first followed by the actual data.
In your case you could use both methods actually, but I really recommend you send the filename first, or it will be hard for the server to open the file and write the data.
You could send the filename with the terminating zero, thereby having the string terminator as a field separator between the fiilename and the file data.
Or you could send both the length of the filename and the file data, followed by the name and the data.
BTW, be sure not to allow a full file name to be sent - you can't trust
the client, and you wouldn't want any client to create an arbitrary
file.

Sending files from client to server using sockets in C

The program is supposed to send the contents of a file from the client side to an output file on the server side. However, my code is working for few files and not working for most of the files. For example if I try to copy content of a file called morefood.txt to an output file say picolo.txt, nothing is copied.
Server code:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
int main(int argc, char *argv[]){
int fd =0, confd = 0;
struct sockaddr_in serv_addr;
char buff[1025];
int num;
fd = socket(AF_INET, SOCK_STREAM, 0);
printf("Socket created\n");
memset(&serv_addr, '0', sizeof(serv_addr));
memset(buff, '0', sizeof(buff));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(5000);
bind(fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
listen(fd, 10);
FILE* fp = fopen( "picolo.txt", "wb");
if(fp == NULL){
fprintf(stderr, "something went south");
return 1;
}
while(1){
confd = accept(fd, (struct sockaddr*)NULL, NULL);
char recvbuff[10];
int b = recv(confd, recvbuff, 10, 0);
while(b>0)
{
fwrite(recvbuff, 1, b, fp);
b = recv(confd, recvbuff, 10, 0);
}
close(confd);
}
return 0;
}
Client code:
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
int main(int argc, char *argv[]){
int sfd =0, n=0;
char rbuff[1024];
struct sockaddr_in serv_addr;
memset(rbuff, '0', sizeof(rbuff));
sfd = socket(AF_INET, SOCK_STREAM, 0);
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(5000);
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
connect(sfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
FILE *fp = fopen("morefood.txt", "rb");
if(fp == NULL){
fprintf(stderr, "oh no!");
return 1;
}
char sendbuffer[100];
int b = fread(sendbuffer, 1, sizeof(sendbuffer), fp);
while(!feof(fp)){
send(sfd, sendbuffer, b, 0);
b = fread(sendbuffer, sizeof(sendbuffer), 1, fp);
}
return 0;
}
The issue is that both transmission and reception loop are bugged! I've modified them in a way that the codes run better, but I think there's a lot to modify to have a solid code!
Client:
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
int main(int argc, char *argv[]){
int sfd =0, n=0, b;
char rbuff[1024];
char sendbuffer[100];
struct sockaddr_in serv_addr;
memset(rbuff, '0', sizeof(rbuff));
sfd = socket(AF_INET, SOCK_STREAM, 0);
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(5000);
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
b=connect(sfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
if (b==-1) {
perror("Connect");
return 1;
}
FILE *fp = fopen("prova.jpg", "rb");
if(fp == NULL){
perror("File");
return 2;
}
while( (b = fread(sendbuffer, 1, sizeof(sendbuffer), fp))>0 ){
send(sfd, sendbuffer, b, 0);
}
fclose(fp);
return 0;
}
Server:
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
int main(int argc, char *argv[]){
int fd =0, confd = 0,b,tot;
struct sockaddr_in serv_addr;
char buff[1025];
int num;
fd = socket(AF_INET, SOCK_STREAM, 0);
printf("Socket created\n");
memset(&serv_addr, '0', sizeof(serv_addr));
memset(buff, '0', sizeof(buff));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(5000);
bind(fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
listen(fd, 10);
while(1){
confd = accept(fd, (struct sockaddr*)NULL, NULL);
if (confd==-1) {
perror("Accept");
continue;
}
FILE* fp = fopen( "provacopy.jpg", "wb");
tot=0;
if(fp != NULL){
while( (b = recv(confd, buff, 1024,0))> 0 ) {
tot+=b;
fwrite(buff, 1, b, fp);
}
printf("Received byte: %d\n",tot);
if (b<0)
perror("Receiving");
fclose(fp);
} else {
perror("File");
}
close(confd);
}
return 0;
}
this code, in the client:
char sendbuffer[100];
int b = fread(sendbuffer, 1, sizeof(sendbuffer), fp);
while(!feof(fp)){
send(sfd, sendbuffer, b, 0);
b = fread(sendbuffer, sizeof(sendbuffer), 1, fp);
}
is not a good way to send a 'nameless' file.
I suggest
while( 0< (byteCount = fread( sendbuffer, sizeof(sendbuffer), 1, fp) ) )
{
send(sfd, sendbuffer, byteCount, 0);
}
however, for robustness
--client send a file name and total file size with recordNum 0
--server when receiving recordNum 0
open the appropriate file name
if successful open, send 'ack', maxRecordSize echo recordNum
else send 'nak' echo recordNum
--client, on following records,
send byteCount, recordNum, data
--server respond with 'ack' for each received record
when it is expected recordNum
otherwise respond with 'nak' expected recordNum
--when client receives 'ack' send next record
--when client receives 'nak' resend prior record
--client, after all file sent, send file checksum with recordnum -1
--server, when receive recordNum -1 compares checksum, closes file
responds with final 'ack' if checksum matches
responds with final 'nak' if checksum does not match
This 'lockstep' communication, which is often used in the real world,
will assure both ends of the communication know what is going on
and will assure a successful file transfer,
This works for only one file being sent at a time.
for multiple files being sent at the same time,
the records will need another field, that indicates which file
'this' record is part of.
of course, all send/recv/open/connect/bind/ etc system function calls need to have the returned value(s) checked for errors
Part to read from file in server
.
. // Your other code
.
read(client, rbuff, sizeof(rbuff); //Getting file name from client
printf("File wanted by client%s\n", textToRec);
int filedesc = open(textToRec, O_RDONLY); //Opening the file
struct stat sb; //To get the size of file
if (lstat(ruff, &sb) == -1) {
exit(EXIT_FAILURE);
}
long long fsize;
fsize = sb.st_size;
if ((0 == filedesc)) {
fprintf(stderr,"error in reading file");
exit(-1);
}
write(client, fsize, sizeof(fsize)); //Sending Filesize
read(filedesc, sendbuffer, fsize); //Putting file in buffer
write(client, sendbuffer, sizeof(sendbuffer)); //Sending buffer to client
close(socketid);
.
.
. // Your code
Part on the client side:
/* your code above */
printf("file name sent...Now wait!\n");
// I am assuming you put filename in buff
read(sock, buff,sizeof(buff)); //Receiving file size
long long fsize = strtol(buff,NULL,10);
read(sock, buff,sizeof(buff));
/*It's better to use sizeof instead of actual number as you can change the size of buffer anytime without needing to change values everywhere */
int filedesc;
filedesc =
open(textToSend, O_WRONLY | O_APPEND | O_CREAT, 0644);
if (!filedesc) {
printf("failed to create file\n");
exit;
}
write(filedesc, buff, fsize);
close(filedesc);
close(confd);

C Socket Server is unable to terminate connection?

I have made a Socket server and client.the client selects the pdf file and sends it to the server.This code runs perfectly on local machine i.e Server and client run on same host,the file is transfered on the server side and opens up with the content but when i run server and client on different hosts i encounter the following problem the Server is unable to quit and file transfered is getting overwritten at the server side,thus unable to show file content,like if i am sending a 240 kb file from client the file received at the server is of 2 GB.
I am programming in qt creator,and the client is a Gui application that also runs Socket client code while server is a console project.
This is server.cpp
#include <QtCore/QCoreApplication>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define Size 2048
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
int s, fd, len;
struct sockaddr_in my_addr;
struct sockaddr_in remote_addr;
socklen_t sin_size;
char buf[BUFSIZ];
FILE *fp = fopen("/home/D.A.D19/Desktop/Filecopy/Q7Basic_essentials.pdf","a+");
memset(&my_addr, 0, sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_addr.s_addr = inet_addr("192.168.103.128");
my_addr.sin_port = htons(8000);
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
qWarning("socket");
return 1;
}
if (bind(s,(struct sockaddr *)&my_addr,sizeof(struct sockaddr))<0)
{
qWarning("bind");
return 1;
}
listen(s, 5);
sin_size = sizeof(struct sockaddr_in);
if ((fd =accept(s,(struct sockaddr *)&remote_addr,&sin_size)) < 0)
{
qWarning("accepted client %s\n", inet_ntoa(remote_addr.sin_addr));
return 1;
}
len = send(fd, "Welcome to my server\n", 21, 0);
while(1)
{
len = recv(fd,buf,Size,0);
The problem is here
if (strcmp(buf,"quit") == 0){
qWarning("Connection terminated");
break;
}
fwrite(buf,Size,1, fp);
memset(buf,0,Size);
}
fclose(fp);
close(fd);
close(s);
return a.exec();
}
This is Client.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QLabel>
#include <QPushButton>
#include <QFileDialog>
#include <QLineEdit>
#include <QString>
#include <QtCore/QCoreApplication>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define SIZE 2048
QString Path;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QLabel *label1 = new QLabel(this);
label1->setText("FileName");
label1->setGeometry(15,25,70,30);
label1->show();
QPushButton *pushbutton = new QPushButton(this);
pushbutton->setText("Browse");
pushbutton->setGeometry(180,28,90,25);
pushbutton->show();
QObject::connect(pushbutton,SIGNAL(clicked()),this, SLOT(browse()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::browse()
{
int s, len;
struct sockaddr_in remote_addr;
char buf[BUFSIZ];
memset(&remote_addr, 0, sizeof(remote_addr));
remote_addr.sin_family = AF_INET;
remote_addr.sin_addr.s_addr = inet_addr("192.168.103.128");
remote_addr.sin_port = htons(8000);
QLineEdit *line = new QLineEdit(this);
line->setGeometry(82,28,90,25);
QString filename = QFileDialog::getOpenFileName(this,tr("Find files"),
"/home/D.A.D19/Desktop");
line->setText(filename);
line->show();
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
qWarning("socket");
//return 1;
}
if (::connect(s, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr)) < 0)
{
qWarning("connect");
//return 1;
}
qWarning("connected to server \n");
len = recv(s, buf, BUFSIZ, 0);
qWarning("%s \n",buf);
buf[len] = '\0';
sprintf(buf, "%s", qPrintable(filename));
FILE *fp = fopen(buf,"r");
while(1)
{
if(feof(fp))
{
strcpy(buf,"quit");
send(s,buf,SIZE,0);
break;
}
if(!feof(fp))
{
int count = fread(buf,SIZE,1,fp);
len = send(s, buf,SIZE, 0);
memset(buf,0,SIZE);
}
}
fclose(fp);
::close(s);
return;
}
When you enter the string quit, it will also have the \n.
So when you compare the string, compare like this:
if (strcmp(buf,"quit\n") == 0)
And then execute the code. Now the string will be matched and connection will be terminated.

Resources