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.
Related
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)
client-side code:
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include <netdb.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
void error(char * msg){
perror(msg);
exit(0);
}
// Returns an string array from function
char *buff(const char *path){
int end = 0;
unsigned char * buf;
int f_write = open(path,O_RDONLY);
end = lseek(f_write,0,SEEK_END);
lseek(f_write,0,SEEK_SET);
buf =(char*)malloc(sizeof(char*)*(end+1));
read(f_write,buf,end);
close(f_write);
buf[end+1]= '\0';
return buf;
}
//connects to the socket
int connection(int portno,struct hostent * server,int sockfd){
struct sockaddr_in serv_addr;
int conn =0;
bzero((char *)&serv_addr,sizeof(serv_addr));
serv_addr.sin_family= AF_INET;
bcopy((char*)server->h_addr,(char *)&serv_addr.sin_addr.s_addr,server->h_length);
serv_addr.sin_port = htons(portno);
conn = connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));
return conn;
}
int main(int argc, char *argv[]) {
int sockfd = -1;
int check =0;
char projname[100]= "project1";
int portno = -1;
int conn = -1;
int file_size =0;
ssize_t len;
int n = -1;
struct hostent *server;
char buffer[256];
int fd =0;
if(argc < 3){
fprintf(stderr,"usage %s hostname port\n",argv[0]);
exit(0);
}
// getting the portnumber
portno = atoi(argv[2]);
sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd < 0){
error("Error opening socket");
}
// getting the hostname
server = gethostbyname(argv[1]);
if(server == NULL){
fprintf(stderr,"Error no such host\n");
exit(0);
}
conn = connection(portno,server,sockfd);
if(conn < 0){
printf("%s\n",strerror(errno));
}
int path = open("text.txt",O_CREAT | O_WRONLY, 0644);
if(path < 0){
printf("%s\n",strerror(errno));
}
int remain_data = file_size;
printf("Printing out the file size ");
printf("%d\n",file_size);
char *buffer1 = (char*)malloc(sizeof(char)*file_size+1);
len = recv(sockfd,buffer1,BUFSIZ,0);
printf("%d",len);
buffer1[file_size]= '\0';
printf("printing the sentence\n");
printf("%s\n",buffer1);
int total_read_bytes =0;
int nread =0;
return 0;
}
server-side code
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/sendfile.h>
#include <sys/stat.h>
#include <sys/socket.h>
void error(char * msg){
perror(msg);
exit(1);
}
int main(int argc, char const *argv[]){
int sockfd =-1;
int newsockfd = -1;
int portno = -1;
int clilen = -1;
int remain_data =0;
char buffer[300];
char buffer1[300];
int peer_socket = -1;
struct sockaddr_in serv_addr,cli_addr;
int n = -1;
struct stat file_stat;
char file_size[256];
ssize_t len;
int sent_bytes =0;
int path = open("project1/text.txt",O_RDONLY);
read(path,buffer1,30);
buffer1[31]= '\0';
printf("%s\n",buffer1);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd <0){
error("Error opening socket");
}
bzero((char*) &serv_addr,sizeof(serv_addr));
portno=atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if(bind(sockfd,(struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0){
error("Error on Binding");
}
listen(sockfd,5);
int fd = open("project1/text.txt",O_RDONLY);
fstat(fd,&file_stat);
clilen = sizeof(cli_addr);
peer_socket = accept(sockfd,(struct sockaddr *)&cli_addr, &clilen);
sprintf(file_size,"%d",file_stat.st_size);
//sends file size
len = send(peer_socket,file_size,sizeof(file_size),0);
if(peer_socket <0){
error("Error on accept");
}
off_t offset = 0;
remain_data = file_stat.st_size;
//send the file
while(((sent_bytes=sendfile(peer_socket,fd,&offset,remain_data))>0) &&( remain_data>0)){
fprintf(stdout,"1.Server sent %d bytes from files data, offset is now : %d and remaining data = %d\n",sent_bytes, offset,remain_data);
remain_data -=sent_bytes;
fprintf(stdout, "2. Server sent %d bytes from files data, offest is not: %d and remaing data = %d\n",sent_bytes, offset,remain_data);
}
return 0;
}
I am able to get the size of my file from server side but I am unable to get file content from my server on client side. My client prints out an empty space where the data of the file is supposed to be, I don't know if I am using the recv function correctly the file correctly.
P.S I understand that I must close the sockets when finished.
For safety and robustness, you must check the return values of all the standard library functions you call to check for errors. For recv() and read(), however, you must check and appropriately handle return values for correctness. These functions do not guarantee to transfer the full number of bytes requested, and for network connections it is reasonably common that they don't. If you want to fully transfer a specific number of bytes then you must be prepared to use multiple recv() or read() calls to do so, generally by calling the function in a loop.
You do not check the return value of your recv() call, so if you have a short read -- or if there is an error or if the remote side closes the connection without sending anything -- then your client will not notice, and will simply output whatever garbage happens to be in the buffer.
Modify the following socket program and let the server send a file to the client.
I'm stuck with this i can't figure this out.
below is the server and client that where given to me. right now the server will send the client the time stamp.
Socket Server Example (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>
#include <time.h>
int main(int argc, char *argv[])
{
int listenfd = 0, connfd = 0;
struct sockaddr_in serv_addr;
char sendBuff[1025];
time_t ticks;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&serv_addr, '0', sizeof(serv_addr));
memset(sendBuff, '0', sizeof(sendBuff));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(5000);
bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
listen(listenfd, 10);
while(1)
{
connfd = accept(listenfd, (struct sockaddr*)NULL, NULL);
ticks = time(NULL);
snprintf(sendBuff, sizeof(sendBuff), "%.24s\r\n",
ctime(&ticks));
write(connfd, sendBuff, strlen(sendBuff));
close(connfd);
sleep(1);
}
}
Socket Client Example (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 sockfd = 0, n = 0;
char recvBuff[1024];
struct sockaddr_in serv_addr;
if(argc != 2)
{
printf("\n Usage: %s <ip of server> \n",argv[0]);
return 1;
}
memset(recvBuff, '0',sizeof(recvBuff));
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("\n Error : Could not create socket \n");
return 1;
}
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(5000);
if(inet_pton(AF_INET, argv[1], &serv_addr.sin_addr)<=0)
{
printf("\n inet_pton error occured\n");
return 1;
}
if( connect(sockfd, (struct sockaddr *)&serv_addr,
sizeof(serv_addr)) < 0)
{
printf("\n Error : Connect Failed \n");
return 1;
}
while ( (n = read(sockfd, recvBuff, sizeof(recvBuff)-1)) > 0)
{
recvBuff[n] = 0;
if(fputs(recvBuff, stdout) == EOF)
{
printf("\n Error : Fputs error\n");
}
}
if(n < 0)
{
printf("\n Read error \n");
}
return 0;
}
If you don't want to or can't read the whole content of the file you wish to send at once into memory, use a loop with your buffer:
#include <fcntl.h>
if (argv[1]) // or whereever you get the file name from
{
int fd = open(argv[1], O_RDONLY);
if (fd < 0) perror(argv[1]);
else
{
ssize_t n;
while (n = read(fd, sendBuff, sizeof sendBuff), n > 0)
if (send(connfd, sendBuff, n, MSG_NOSIGNAL) < 0)
{ perror("send"); break; }
close(fd);
if (n < 0) perror("read");
}
}
In the client use a similar loop. Be aware that the file might contain NUL characters, so functions like fputs, operating on C strings, are inept.
while ((n = read(sockfd, recvBuff, sizeof recvBuff)) > 0)
if (write(1, recvBuff, n) < 0) perror("write");
Read the content of the file you wish to send, and save it into a string:
char *loadFileContent(char *fileName, size_t *len){
FILE* input_file = fopen(fileName, "rb");
size_t stat;
if(!input_file){
OCSP_ERR_INDEX = OCSP_LOG_ERR_load_file_fail;
return NULL;
}
fseek(input_file, 0, SEEK_END);
long int input_file_size = ftell(input_file);
rewind(input_file);
char *file_contents = malloc((input_file_size + 1) * (sizeof(char)));
stat = fread(file_contents, sizeof(char), (size_t) input_file_size, input_file);
if(stat<1){
OCSP_ERR_INDEX = OCSP_LOG_ERR_load_file_fail;
return NULL;
}
fclose(input_file);
file_contents[input_file_size] = 0;
*len = (size_t) input_file_size;
return file_contents;
}
In your code, modify the line in server that is supposed to send response to client.
So this line write(connfd, sendBuff, strlen(sendBuff)); becomes:
size_t len;
char *text = loadFileContent("myfile.txt", &len);
write(connfd, text, len);
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);
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.