So I'm trying to send more than a file from my server side to the client .I have already completed the task of sending one file with its size. To explain more the name of the file is passed as argument to the client then send to the server to check if there is a file with this name in the shared folder by the server, if yes then the server sends the file to the client.
My idea was send the number of files to be sent to the client then do the same stuff I do for one single file in for loop but the cold crush I don't now why.
And I also try to connect using wifi in 2 different PC but the code does it work correctly, I test it before using ethernet cable and all go ok
Can any one help me please?
this link to the project folder :
https://github.com/amaraoussama94/Server_Client-C-app
i try some video youtube and some other solution but it crush
i expect to have some idea , or code to boost me
Snap of project :
server :
#include <arpa/inet.h> // inet_addr()/
#include <stdio.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdlib.h>//system
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h> // read(), write(), close()
#include <errno.h>
#include "Const.h"
#include "arg_test.h"
#include <time.h>//get time and date for log file
#include <string.h>//
//void* SendFileToClient(int *arg)
void SendFileToClient(int *ptr_connfd,char * fname ,struct sockaddr_in cli )
{
//int connfd=(int)*arg;
printf("[i]Connection accepted and id: %d\n",*ptr_connfd);
printf("[i]Connected to Clent: %s:%d\n",inet_ntoa(cli.sin_addr),ntohs(cli.sin_port));
write(*ptr_connfd, fname,256);
FILE *fp = fopen(fname,"rb");
if(fp==NULL)
{
printf("\033[0;31m");
printf("[-]File for transfer open error\n");
printf("\033[0m");
exit(1);
}
/*******************************************/
fseek(fp, 0L, SEEK_END);
// calculating the size of the file
long int res = ftell(fp);
//conver to char to send it
char size[10];
sprintf(size, "%f", (res/1024.0) );
//send file size to the client
write(*ptr_connfd, size, sizeof(size));
printf("[i]size of the file to transfer is %f Kb\n",(res/1024.0));
fseek(fp, 0, SEEK_SET);
/******************************************/
/* Read data from file and send it */
while(1)
{
/* First read file in chunks of 256 bytes */
unsigned char buff[1024]={0};
int nread = fread(buff,1,1024,fp);
//printf("Bytes read %d \n", nread);
/* If read was success, send data. */
if(nread > 0)
{
//printf("Sending \n");
write(*ptr_connfd, buff, nread);
}
if (nread < 1024)
{
if (feof(fp))
{
// printf("End of file\n");
printf("\033[0;32m");
printf("[+]File transfer completed for id: %d\n",*ptr_connfd);
printf("\033[0m");
}
if (ferror(fp))
{
printf("\033[0;31m");
printf("[-]Error reading file for transfer \n");
printf("\033[0m");
}
break;
}
}
printf("\033[0;32m");
printf("[+]Closing Connection for id: %d\n",*ptr_connfd);
printf("\033[0;31m");
close(*ptr_connfd);
//shutdown(*ptr_connfd,SHUT_WR);
sleep(2);
}
// Function designed for chat between client and server.
int share_msg(int* ptr_connfd,char **argv ,struct sockaddr_in cli,int *ptr_change )
{
FILE *filePointer,*filePointerTransfer ;
char cmd [100]="./script.sh ";
char buff[MAX];
char string[MAX];
int Exist =0 ;
int j =0;
int err ;
pthread_t tid;
// bzero :Set N bytes of pointer to 0.
bzero(buff, MAX);//or you can use memset (&buff,'\0',sizeof(buff))
// read the message from client and copy it in buffer
read(*ptr_connfd, buff, sizeof(buff));
// print buffer which contains the client contents
if (strncmp("bash_list", buff, 9) == 0)
{ printf("[i]The client wants information about shared folder\n ");
//| awk '{print $1 " " $11 }' " " : field are sparate with space , $1 et $ 11 print colom1 and 11
//chdir(argv[4]);// change the path
strcat(cmd,argv[4]);
//int status = system("ls -al|awk '{print $1 " " $11}' > cmdoutput" );
int status = system(cmd);
//open file
filePointer = fopen("stdout.txt", "r");
//ste the psotion of the pointer at the bening of the file
if (filePointer == NULL)
{
printf("\033[0;31m");
printf("[-]Error can t find list of file to share \n");
printf("\033[0m");
bzero(buff,sizeof(buff));
strcat(buff,"ERRORFILE1");
write(*ptr_connfd, buff, sizeof(buff));
exit(1);
}
fseek(filePointer, 0, SEEK_SET);
while(fgets(buff, MAX, filePointer))
{
// send that buffer to clients
if (strncmp(buff ,".",1)==0 || strncmp(buff ,"..",2)==0 || strncmp(buff ,"/",1)==0)
{
continue;
}
write(*ptr_connfd, buff, sizeof(buff));
}
bzero(buff, MAX);
for(int j =0 ;j<sizeof(buff);j++)
{
buff[j] = '#';
}
//send to client
write(*ptr_connfd, buff, sizeof(buff));
//file
fclose(filePointer);
return 1;
}
else if (strcmp("bash_Transf", buff) == 0)
{
int num_file ;
//get numlber of file to send
bzero(buff, MAX);
read(*ptr_connfd, buff, sizeof(buff));
sscanf(buff,"%d",&num_file);
printf("[i] the number of file to send to the client is %d\n",num_file);
//get file name
bzero(buff, MAX);
read(*ptr_connfd, buff, sizeof(buff));
printf("the file name is %s \n",buff);
/*********************************************///must change dir if it run 2nd it crush
char path[100] ;
//get the current dir path
if (*ptr_change)
{
getcwd(path, sizeof(path)) ;
}
*ptr_change =0 ;
int dir_test = chdir(path);
//printf(" hello dir_test =%d and path=%s\n",dir_test,path);
//system("pwd");//test to check dir path
/********************************************/
filePointer = fopen("stdout.txt", "r");
if (filePointer == NULL)
{
printf("\033[0;31m");
printf("[-]Error can t find list of file to share \n");
printf("\033[0m");
exit(1);
}
//get iof the file name existt or no in the shared folder
while ( fgets( string ,MAX, filePointer) )// fscanf(filePointer,"%s", string) == 1
{
//lets take out the \n introduce by fgets
string[strcspn(string,"\n")]= 0;
if (strcmp(string,buff)==0)
{
Exist = 1;
break;
}
}
if (Exist)
{
fclose(filePointer);
//transfer file here
chdir(argv[4]);// change the path
printf( "[i]the file for transfer name is = %s \n",buff);
SendFileToClient(ptr_connfd,buff ,cli );
//create thread for sending the file to the client
/*err = pthread_create(&tid, NULL, &SendFileToClient, ptr_connfd);
if (err != 0)
printf("\ncan't create thread :[%s]", strerror(err));*/
}
else
{
bzero(buff, sizeof(buff));
strcat(buff,"file_error");
write(*ptr_connfd, buff, sizeof(buff));
bzero(buff, sizeof(buff));
printf("\033[0;31m");
printf("[-] Client try to get file that doesn't exist in the shared folder \n");
printf("\033[0m");
}
// si il n y a aucun paramatere passe au clien ni t ni
// list le server se ferme par return 1 and close the while loop
return 1;
}
else
return 0;
}
void create_scoket(int * sockfd)
{
*sockfd = socket(AF_INET, SOCK_STREAM, 0);// AF_INET :IPV4 , SOCK_STREAM:TCP
if (sockfd < 0)
{
printf("\033[0;31m");
perror("[-]socket creation failed...\n");
printf("\033[0m");
exit(1);
}
else
{
printf("\033[0;32m");
printf("[+]Socket successfully created..\n");
printf("\033[0m");
}
}
void socket_bind(struct sockaddr_in *servaddr ,int * sockfd)
{
// Binding newly created socket to given IP and verification
if ((bind(*sockfd, (SA*)servaddr, sizeof(*servaddr))) < 0)
{
printf("\033[0;31m");
perror("[-]socket bind failed...\n");
printf("\033[0m");
exit(1);
}
else
{
printf("\033[0;32m");
printf("[+]Socket successfully binded..\n");
printf("\033[0m");
}
}
void socket_listening (int *sockfd)
{
if ((listen(*sockfd, LISTENQ)) != 0) //5 connection requests will be queued before further requests are refused.
{
printf("\033[0;31m");
printf("[-]Listen failed...\n");
printf("\033[0m");
exit(1);
}
else
{
printf("\033[0;32m");
printf("[+]Server listening..\n");
printf("\033[0m");
}
}
void socket_accept (int *connfd , int* sockfd ,struct sockaddr_in*cli , int *len)
{
*connfd = accept(*sockfd, (SA*)cli, len);
if (connfd < 0)
{
printf("\033[0;31m");
perror("[-]server accept failed...\n");
printf("\033[0m");
exit(1);
}
else
{
printf("\033[0;32m");
printf("[+]server accept the client...\n");
printf("\033[0m");
}
}
// Driver function
int main(int argc, char **argv)
{
//for socket
int sockfd, connfd, len;
int *ptr_sockfd ,*ptr_connfd , *ptr_len;
struct sockaddr_in servaddr, cli;
struct sockaddr_in *ptr_servaddr , *ptr_cli;
int change =1 ; //for transfer
int *ptr_change =&change;
check_arg_server(argc,argv);
// socket create and verification
ptr_sockfd = &sockfd;
create_scoket(ptr_sockfd);
//initialize to zeo
// bzero :Set N bytes of pointer to 0.
bzero(&servaddr, sizeof(servaddr));//or you can use memset (&servaddr,'\0', sizeof(servaddr))
// assign IP, PORT
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr =htonl(INADDR_ANY);// Address to accept any incoming messages.
servaddr.sin_port = htons(atoi(argv[2]));//htons :Functions to convert between host and network byte order
//binding
ptr_servaddr = &servaddr;
socket_bind(ptr_servaddr ,ptr_sockfd);
// Now server is ready to listen and verification
socket_listening (ptr_sockfd);
//chek for ctr+z as input to stope server
while (1)
{
len = sizeof(cli);
//printf("hello ok \n");
// Accept the data packet from client and verification
ptr_connfd = &connfd;
ptr_len = &len;
ptr_cli= &cli ;
socket_accept (ptr_connfd , ptr_sockfd , ptr_cli , ptr_len);
//temp sol to stop server
int b = share_msg(ptr_connfd,argv,cli,ptr_change);
if (!b)
{
close(connfd);
break;
}
close(connfd);
sleep(1);
}
// After chatting close the socket
close(sockfd);
printf("[i] Server will Shutdown \n");
return 0;
}
client :
#include <arpa/inet.h> // inet_addr()/
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h> // bzero()
#include <sys/socket.h>
#include <unistd.h> // read(), write(), close()
#include "Const.h"
#include "arg_test.h"
// for mkdir function
#include <sys/stat.h>
#include <sys/types.h>
const int PROG_BAR_LENGTH =30 ;//30 caractere
void update_bar(float percent_done )
{
int num_car =(int) percent_done * PROG_BAR_LENGTH / 100 ;//number of caractere to print
printf(" \r[");
for(int i =0;i<num_car;i++)
{
printf("\033[0;32m"); //Set the text to the color Green
printf("■");
}
for(int i =0;i<(PROG_BAR_LENGTH -num_car);i++) //unfinish part of progress bar
{
printf(" ");
}
if((int)percent_done > 100)
{
percent_done =100 ;
}
printf("\033[0m"); //Resets the text to default color
printf("] %d%% Done.",(int)percent_done );
// fflush(stdout);//print all to the screen
}
void share_msg(int *sockfd,char ** argv, int argc)
{
char buff[MAX]="bash";
char msg[MAX];
FILE *filetransferPointer;
int n , bytesReceived = 0 ;
if (strcmp("--list", argv[5]) == 0)
{
strcat(buff,"_list");
}
if (strcmp("-T", argv[5]) == 0)
{
strcat(buff,"_Transf");
}
//send to server
write(*sockfd, buff, sizeof(buff));
bzero(buff, sizeof(buff));
if (strcmp("--list", argv[5]) == 0)
{
//read receive msg from server
read(*sockfd, msg, sizeof(msg));
read(*sockfd, msg, sizeof(msg));
if(!strcmp(msg,"ERRORFILE1"))
{
printf("[-] Error server can t list file \n ");
exit(1);
}
printf("[i]This is the list of file and folder shared by the server : \n These are the directories : \n" );
while(1)
{
read(*sockfd, msg, sizeof(msg));
if(!strncmp(msg, "#", 1) )
{
break;
}
printf("%s \n ",msg);
}
}
else if (strcmp("-T", argv[5]) == 0)
{
//get number of file to receive from server
int num_file = argc-6;
bzero(msg, sizeof(msg));
sprintf(msg,"%d",num_file);
write(*sockfd, msg, sizeof(msg));
//printf ("num = %s\n",msg);
//send file name to server
bzero(msg, sizeof(msg));
strcat(msg,argv[6]);
printf(" the buff is = %s",msg);
write(*sockfd, msg, sizeof(msg));
//check if the file name exist or no
bzero(msg, sizeof(msg));
read(*sockfd, msg, sizeof(msg));
if (strcmp(msg,"file_error")==0)
{ printf("\033[0;31m");
printf("[-]Please try again ,maybe try --list first then try again ,or maybe no file has this name \n" );
printf("\033[0m");
exit(1);
}
//get the file
char* dirname = "transfer";
mkdir(dirname,0755);
//system("mkdir transfer");
chdir("transfer");
//system("cd test/");
//system("pwd");
filetransferPointer = fopen(argv[6] , "ab");
if (filetransferPointer == NULL)
{
printf("\033[0;31m");
printf("[-]Error can t create file for transfer \n");
printf("\033[0m");
exit(-1);
}
/**********************************************/
char size[10];
long double size_file =0;
read(*sockfd, size, sizeof(size));
//convert data to long double
sscanf(size, "%Lf", &size_file);
printf("[i]Size of the file %Lf Kb \n",size_file);
/*************************************************/
/* Receive data in chunks of 256 bytes */
long double sz=0;
long double * ptr_sz =&sz;
while((bytesReceived = read(*sockfd, msg, 1024)) > 0)
{
//sz++;
//gotoxy(0,4);
//printf(" \r Received: %LF Mb \t \t \t",(sz/1024)); //LF for long double
//fflush(stdout);
// recvBuff[n] = 0;
/******************************************************/
double percent_done;
//long double batch_size =1/1024 ;//Mb
percent_done += 100/ size_file ; //;(batch_size/size_file)*100
//printf(" the file size is %Lf the percent_done = %lf and in in = %d \n",size_file,percent_done,(int)percent_done);
update_bar(percent_done);
fflush(stdout);
fwrite(msg, 1,bytesReceived,filetransferPointer);
usleep(20000);//sleep for 20ms
//printf("%s \n", recvBuff);
}
printf("\n");
if(bytesReceived < 0)
{
printf("[-]Error can t create file %s to recive it \n",argv[6]);
}
fclose(filetransferPointer);
printf("[i] file transmission %s is done you can check transfer folder \n",argv[6]);
}
}
void create_scoket(int * sockfd)
{
*sockfd = socket(AF_INET, SOCK_STREAM, 0);// AF_INET :IPV4 , SOCK_STREAM:TCP
if (sockfd < 0)
{
printf("\033[0;31m");
perror("[-]socket creation failed...\n");
printf("\033[0;31m");
exit(1);
}
else
{ printf("\033[0;32m");
printf("[+]Socket successfully created..\n");
printf("\033[0m");
}
}
void socket_connect(struct sockaddr_in *servaddr ,int * sockfd)
{
if (connect(*sockfd, (SA*)servaddr, sizeof(*servaddr)) <0)
{
printf("\033[0;31m");
perror("[-]connection with the server failed...\n");
printf("\033[0m");
exit(1);
}
else
{
printf("\033[0;32m");
printf("[+]connected to the server..\n");
printf("\033[0m");
}
}
int main(int argc, char **argv)
{
int sockfd, connfd;
int *ptr_sockfd;
struct sockaddr_in servaddr, client_addr;
struct sockaddr_in *ptr_servaddr;
//check argument
check_arg_client(argc,argv);
// socket create and verification
ptr_sockfd= &sockfd;
create_scoket(ptr_sockfd);
//initialize to zeo
// bzero :Set N bytes of pointer to 0.
bzero(&servaddr, sizeof(servaddr));//or you can use memset (&servaddr,'\0', sizeof(servaddr))
// assign IP, PORT
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr(argv[2]);// the adress of the serveur
servaddr.sin_port = htons(atoi(argv[4])); //htons :Functions to convert between host and network byte order
// connect the client socket to server socket
ptr_servaddr = &servaddr ;
socket_connect(ptr_servaddr ,ptr_sockfd);
// run the lisst or transfer option
if( argc > 5)
{
share_msg(ptr_sockfd,argv, argc);
}
// close the socket
close(sockfd);
}
enter code here
Related
We are working on a project where we want to communicate with a server.
This is our function to communicate with the server, but somehow it does not read the incoming messages correctly all the time.
Sometimes in the buffer there is something like:
(Server sends)"+ Client version acClient: ID 38ail6ii3s8jc"
instead of:
(Server sends)"+ Client version accepted - please send Game-ID to join"
(We send)"Client: ID 38ail6ii3s8jc"
So, I think the error is within the char *receiveAnswer(int sock) function.
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#define BUFFERSIZE 1024
#define bzeroNew(b,len) (memset((b), '\0', (len)), (void) 0) //buffer loeschen
#define VERSION "VERSION 3.4\n"
#include "functions.h"
char buffer[BUFFERSIZE];
int prologEnd = 0;
int proof;
//liest von Server eine Nachricht ein und speichert sie im buffer ab
char *receiveAnswer(int sock) {
bzeroNew(buffer, BUFFERSIZE);
if(recv(sock, buffer, sizeof(buffer), 0) < 0) {
perror("ERROR: Empfangen fehlgeschlagen\n");
}
printf("%s", buffer);
return buffer;
}
void sendResponse(int sock, char* message) {
bzeroNew(buffer, BUFFERSIZE);
strcpy(buffer, message);
proof = send(sock, buffer, strlen(buffer), 0);
if(proof < 0) {
perror("ERROR: Senden fehlgeschlagen\n");
}
printf("Client: %s\n", buffer);
receiveAnswer(sock);
}
int performConnection(int sock, char* gameID) {
bzeroNew(buffer, BUFFERSIZE);
receiveAnswer(sock);
while(strncmp(buffer, "+", 1) == 0 && prologEnd == 0) {
if(strncmp(buffer, "+ MNM Gameserver", 16) == 0) {
receiveAnswer(sock);
sendResponse(sock, VERSION);
}
else if(strncmp(buffer, "+ Client", 8) == 0) {
sendResponse(sock, gameID);
}
else if(strncmp(buffer, "+ PLAYING", 9) == 0) {
sendResponse(sock, "PLAYER\n");
receiveAnswer(sock);
}
else if(strncmp(buffer, "+ YOU", 5) == 0) {
receiveAnswer(sock);
printf("\n");
prologEnd = 1;
}
else if(strncmp(buffer, "+ TOTAL", 7) == 0) {
receiveAnswer(sock);
receiveAnswer(sock);
prologEnd = 1;
}
}
bzeroNew(buffer, BUFFERSIZE);
return 0;
}
This is our main() function, but I think the error is within the file above:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h> // für Warten auf Kindprozess
#include <unistd.h>
#include <netdb.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <limits.h>
#include <signal.h>
// für Shared Memory:
#include <sys/ipc.h>
#include <sys/shm.h>
#include "functions.h"
#include "sharedMemory.h"
// dublicat, brauchen wir das?
#define GAMEKINDNAME "NMMorris"
#define HOSTNAME "sysprak.priv.lab.nm.ifi.lmu.de"
#define PORTNUMBER 1357
int main (int argc, char *argv[]) {
char gamekindname[256] = "NMMorris";
char hostname[256] = "sysprak.priv.lab.nm.ifi.lmu.de";
int portnumber = 1357;
char* gameID = argv[2];
char playerNumber[256];
char configFile[256] = "client.conf" ;
int fd[2]; // TODO: fd und client_fd vereinen
//gameID formatieren
char bufferGameID[64];
strcpy(bufferGameID, "ID ");
strcat(bufferGameID, gameID);
strcpy(gameID, bufferGameID);
strcat(gameID, "\n");
int i;
char tmp[256];
//Argumente einlesen und an Variablen übergeben
for(i = 3; i < 7; i++) {
strcpy(tmp, argv[i]);
if (strcmp(tmp, "-p") == 0){
strcpy(playerNumber, argv[i+1]);
} else if (strcmp(tmp, "-conf") == 0){
strcpy(configFile, argv[i+1]);
}
}
config configMain = readConfig(configFile);
strcpy(gamekindname, configMain.gameKind);
strcpy(hostname, configMain.hostServerName);
portnumber = configMain.portNmbr;
printf("\n>>>Config File Data<<<\n");
printf("HostServerName: %s\n", hostname);
printf("PortNumber: %d\n", portnumber);
printf("GameKind: %s\n\n ", gamekindname);
//From here: sockets
int sock, client_fd;
struct sockaddr_in serv_addr;
struct hostent *server;
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("\nERROR: Socket creation error \n");
return - 1;
}
//ipAdresse nachschauen
server = gethostbyname(hostname);
if (server == NULL)
{
perror("ERROR: no such host\n");
}
memset(&serv_addr,0,sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(portnumber);
memcpy(&serv_addr.sin_addr.s_addr,server->h_addr,server->h_length);
if ((client_fd = connect(sock, (struct sockaddr*) &serv_addr, sizeof(serv_addr))) < 0) {
perror("ERROR: Connection Failed \n");
return -1;
}
printf(">>> Mit Host : %s verbunden <<<\n", hostname);
if(performConnection(sock, gameID) != 0) {
perror("performConnection Failed\n");
} // TODO: verlagern
close(client_fd);
return 0;
// Shared Memory Segment erstellen
int shmid_game = shmget(KEY, sizeof(gameInfo), IPC_CREAT | SHM_R | SHM_W);
if (shmid_game == -1) {
perror("Error while creating shared memory segment");
exit(EXIT_FAILURE);
} else {
printf("Creation successful\n");
}
int shmid_player = shmget(KEY, sizeof(playerInfo), IPC_CREAT | SHM_R | SHM_W);
if (shmid_player == -1) {
perror("Error while creating shared memory segment");
exit(EXIT_FAILURE);
} else {
printf("Creation successful\n");
}
// Prozess mit SHM verbinden
void* shm_game = shmat(shmid_game, 0, 0);
if (shm_game == NULL) {
perror("Error while attaching shared memory segment");
exit(EXIT_FAILURE);
} else {
printf("Attachment successful\n");
}
void* shm_player = shmat(shmid_player, 0, 0);
if (shm_player == NULL) {
perror("Error while attaching shared memory segment");
exit(EXIT_FAILURE);
} else {
printf("Attachment successful\n");
}
// Kindprozess (Connector) erstellen
pid_t pid;
pid = fork();
if (pid < 0) {
fprintf(stderr, "Fehler bei Erstellung des Kindprozesses.\n");
} else if (pid == 0) { // Kindprozess (Connector)
close(fd[1]);
performConnection(sock, gameID);
} else { // Elternprozess (Thinker)
close(fd[0]);
}
return 0;
}
TCP is a stream-oriented protocol, not a message-oriented one. A message sent as 100 bytes can be received as 1 100-byte read or as 100 1-byte reads, or any combination in between. This means that you must keep looping on the recv() until you have the whole message. That, in turn, means you need to know when a message is completely received. Either prepend the message's length before the message, use a fixed-size message, or have a unique recognizable terminator at the end of the message.
recv() returns the number of bytes that it has written into your buffer -- which is to say, it returns the number of bytes that it currently has available to give to you at the time you called it. Importantly, that will often be less than the number of bytes you requested, so it is mandatory that you check the return value of recv() to find out how many bytes you actually received, and not just assume that the value returned by recv() is equal to sizeof(buffer).
OTOH if you want recv() to not return until sizeof(buffer) bytes have been successfully read, you can pass the MSG_WAITALL flag to recv() in the fourth argument.
From the recv man page:
This flag requests that the operation block until the full
request is satisfied. However, the call may still return
less data than requested if a signal is caught, an error
or disconnect occurs, or the next data to be received is
of a different type than that returned. This flag has no
effect for datagram sockets.
It is not guaranteed that recv() will get all of the bytes sent at once. The convention is to call it in a loop until you've read all the bytes.
NB that recv() returns 0 when the client is stalling or closed the connection, and -1 on a read error.
Handling partial send()s:
int sendall(int s, char *buf, int *len)
{
int total = 0; // how many bytes we've sent
int bytesleft = *len; // how many we have left to send
int n;
while(total < *len) {
n = send(s, buf+total, bytesleft, 0);
if (n == -1) { break; }
total += n;
bytesleft -= n;
}
*len = total; // return number actually sent here
return n==-1?-1:0; // return -1 on failure, 0 on success
}
— From Beej's guide to Network Programming
The above code snippet calls send() in a loop until all the data has been sent.
You can now write a similar recv_all function that calls recv() in a loop until it has read all the data.
Handling partial recv()s:
Perhaps something like this:
/* Synopsis: Calls recv() in a loop to ensure
* len bytes have been read. Stores
* the total number of bytes sent in len.
*
* Returns: 0 on failure, 1 otherwise.
*/
static int recv_all(int sockfd, char *buf, size_t *len)
{
size_t bytes_left = *len;
size_t total = 0;
ssize_t rv = 0;
errno = 0;
while (total < *len) {
rv = recv(sockfd, buf + total, bytes_left, 0);
if (rv == 0) { /* Client closed the connection or is stalling */
return 0;
} else if (rv == -1) { /* A read error */
perror("recv");
return 0;
}
total += rv;
bytes_left -= rv;
}
*len = total;
return 1;
}
recv() may also return 0 when 0 characters were read. In that case, len can be compared against the original len to see if the call to recv() was successful.
Note: The above recv_all function has not been tested, and hence is not guaranteed to be bug free. It's meant to be an example.
I have a client program and a server program. There could be multiple servers and multiple
clients that can connect to multiple servers of there choice
The client program lists a menu
connect 4000 // connects to server on port 4000
bid 1000 4000 // send a bid value of 1000 to the server at port 4000
Now a server may recieve bids from several clients connected to it and keeps track of the highest
bid till now. Whenever a new bid is placed the server sends a broadcast to each client connected
to it one by one like - write(users[i].sock_fd, msg, size).
How do I listen to this message on the client side ?
There are two things here
The client needs to listen to the message sent by server.
The client is also reading the text or menu items (connect and bid) from command line from the user.
I have coded the part 2) But confused how to code 1) into client and simultaneously make the 2) also working
Client code :
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#define BUF_SIZE 128
#define MAX_AUCTIONS 5
#ifndef VERBOSE
#define VERBOSE 0
#endif
#define ADD 0
#define SHOW 1
#define BID 2
#define QUIT 3
/* Auction struct - this is different than the struct in the server program
*/
typedef struct auction_data
{
int sock_fd;
char item[BUF_SIZE];
int current_bid;
} auction_data;
auction_data *auction_data_ptr;
/* Displays the command options available for the user.
* The user will type these commands on stdin.
*/
void print_menu()
{
printf("The following operations are available:\n");
printf(" show\n");
printf(" add <server address> <port number>\n");
printf(" bid <item index> <bid value>\n");
printf(" quit\n");
}
/* Prompt the user for the next command
*/
void print_prompt()
{
printf("Enter new command: ");
fflush(stdout);
}
/* Unpack buf which contains the input entered by the user.
* Return the command that is found as the first word in the line, or -1
* for an invalid command.
* If the command has arguments (add and bid), then copy these values to
* arg1 and arg2.
*/
int parse_command(char *buf, int size, char *arg1, char *arg2)
{
int result = -1;
char *ptr = NULL;
if (strncmp(buf, "show", strlen("show")) == 0)
{
return SHOW;
}
else if (strncmp(buf, "quit", strlen("quit")) == 0)
{
return QUIT;
}
else if (strncmp(buf, "add", strlen("add")) == 0)
{
result = ADD;
}
else if (strncmp(buf, "bid", strlen("bid")) == 0)
{
result = BID;
}
ptr = strtok(buf, " "); // first word in buf
ptr = strtok(NULL, " "); // second word in buf
if (ptr != NULL)
{
strncpy(arg1, ptr, BUF_SIZE);
}
else
{
return -1;
}
ptr = strtok(NULL, " "); // third word in buf
if (ptr != NULL)
{
strncpy(arg2, ptr, BUF_SIZE);
return result;
}
else
{
return -1;
}
return -1;
}
/* Connect to a server given a hostname and port number.
* Return the socket for this server
*/
int add_server(char *hostname, int port)
{
// Create the socket FD.
int sock_fd = socket(AF_INET, SOCK_STREAM, 0);
if (sock_fd < 0)
{
perror("client: socket");
exit(1);
}
// Set the IP and port of the server to connect to.
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(port);
struct addrinfo *ai;
/* this call declares memory and populates ailist */
if (getaddrinfo(hostname, NULL, NULL, &ai) != 0)
{
close(sock_fd);
return -1;
}
/* we only make use of the first element in the list */
server.sin_addr = ((struct sockaddr_in *)ai->ai_addr)->sin_addr;
// free the memory that was allocated by getaddrinfo for this list
freeaddrinfo(ai);
// Connect to the server.
if (connect(sock_fd, (struct sockaddr *)&server, sizeof(server)) == -1)
{
perror("client: connect");
close(sock_fd);
return -1;
}
if (VERBOSE)
{
fprintf(stderr, "\nDebug: New server connected on socket %d. Awaiting item\n", sock_fd);
}
return sock_fd;
}
/* ========================= Add helper functions below ========================
* Please add helper functions below to make it easier for the TAs to find the
* work that you have done. Helper functions that you need to complete are also
* given below.
*/
/* Print to standard output information about the auction
*/
void print_auctions(struct auction_data *a, int size)
{
printf("Current Auctions:\n");
for (int i = 0; i < size; i++)
{
struct auction_data auction_data = a[i];
printf("(%d) %s bid = %d\n", i, auction_data.item, auction_data.current_bid);
}
/* TODO Print the auction data for each currently connected
* server. Use the follosing format string:
* "(%d) %s bid = %d\n", index, item, current bid
* The array may have some elements where the auction has closed and
* should not be printed.
*/
}
/* Process the input that was sent from the auction server at a[index].
* If it is the first message from the server, then copy the item name
* to the item field. (Note that an item cannot have a space character in it.)
*/
void update_auction(char *buf, int size, struct auction_data *a, int index)
{
// TODO: Complete this function
// fprintf(stderr, "ERROR malformed bid: %s", buf);
// printf("\nNew bid for %s [%d] is %d (%d seconds left)\n", );
}
int main(void)
{
char name[BUF_SIZE];
int size = 0;
// Declare and initialize necessary variables
// TODO
// Get the user to provide a name.
printf("Please enter a username: ");
fflush(stdout);
int num_read = read(STDIN_FILENO, name, BUF_SIZE);
printf("%s-name\n", name);
if (num_read <= 0)
{
fprintf(stderr, "ERROR: read from stdin failed\n");
exit(1);
}
print_menu();
// TODO
char server_reply[2000];
while (1)
{
print_prompt();
char *command;
scanf("%m[^\n]s", &command);
getchar();
char arg1[100];
char arg2[100];
int commandNumber = parse_command(command, 1000, arg1, arg2);
char dest[100] = "";
strcpy(dest, name);
dest[strlen(dest) - 1] = '\0';
if (commandNumber == ADD)
{
printf("%s-name4\n", dest);
int port = atoi(arg2);
int sock_fd = add_server(arg1, port);
printf("%s-server\n", server_reply);
write(sock_fd, dest, strlen(dest));
auction_data_ptr = (auction_data *)realloc(auction_data_ptr, (size + 1) * sizeof(auction_data_ptr));
auction_data_ptr[size].sock_fd = sock_fd;
size++;
}
else if (commandNumber == SHOW)
{
print_auctions(auction_data_ptr, size);
}
else if (commandNumber == BID)
{
int itemIndex = atoi(arg1);
int bidValue = atoi(arg2);
printf("%d-test\n", auction_data_ptr[itemIndex].sock_fd);
send(auction_data_ptr[itemIndex].sock_fd, arg2, strlen(arg2), 0);
}
else if (commandNumber == QUIT)
{
}
// TODO
}
return 0; // Shoud never get here
}
Server Code :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#ifndef PORT
#define PORT 30000
#endif
#define MAX_BACKLOG 5
#define MAX_CONNECTIONS 20
#define BUF_SIZE 128
#define MAX_NAME 56
int verbose = 0;
struct user
{
int sock_fd;
char name[MAX_NAME];
int bid;
};
typedef struct
{
char *item;
int highest_bid; // value of the highest bid so far
int client; // index into the users array of the top bidder
} Auction;
/*
* Accept a connection. Note that a new file descriptor is created for
* communication with the client. The initial socket descriptor is used
* to accept connections, but the new socket is used to communicate.
* Return the new client's file descriptor or -1 on error.
*/
int accept_connection(int fd, struct user *users)
{
int user_index = 0;
while (user_index < MAX_CONNECTIONS && users[user_index].sock_fd != -1)
{
user_index++;
}
if (user_index == MAX_CONNECTIONS)
{
fprintf(stderr, "server: max concurrent connections\n");
return -1;
}
int client_fd = accept(fd, NULL, NULL);
if (client_fd < 0)
{
perror("server: accept");
close(fd);
exit(1);
}
users[user_index].sock_fd = client_fd;
users[user_index].name[0] = '\0';
return client_fd;
}
/* Remove \r\n from str if the characters are at the end of the string.
* Defensively assuming that \r could be the last or second last character.
*/
void strip_newline(char *str)
{
if (str[strlen(str) - 1] == '\n' || str[strlen(str) - 1] == '\r')
{
if (str[strlen(str) - 2] == '\r')
{
str[strlen(str) - 2] = '\0';
}
else
{
str[strlen(str) - 1] = '\0';
}
}
}
/*
* Read a name from a client and store in users.
* Return the fd if it has been closed or 0 otherwise.
*/
int read_name(int client_index, struct user *users)
{
int fd = users[client_index].sock_fd;
/* Note: This is not the best way to do this. We are counting
* on the client not to send more than BUF_SIZE bytes for the
* name.
*/
int num_read = read(fd, users[client_index].name, MAX_NAME);
if (num_read == 0)
{
users[client_index].sock_fd = -1;
return fd;
}
users[client_index].name[num_read] = '\0';
strip_newline(users[client_index].name);
if (verbose)
{
fprintf(stderr, "[%d] Name: %s\n", fd, users[client_index].name);
}
/*
if (num_read == 0 || write(fd, buf, strlen(buf)) != strlen(buf)) {
users[client_index].sock_fd = -1;
return fd;
}
*/
return 0;
}
/* Read a bid from a client and store it in bid.
* If the client does not send a number, bid will be set to -1
* Return fd if the socket is closed, or 0 otherwise.
*/
int read_bid(int client_index, struct user *users, int *bid)
{
printf("inside bid\n");
int fd = users[client_index].sock_fd;
char buf[BUF_SIZE];
char *endptr;
int num_read = read(fd, buf, BUF_SIZE);
if (num_read == 0)
{
return fd;
}
buf[num_read] = '\0';
if (verbose)
{
fprintf(stderr, "[%d] bid: %s", fd, buf);
}
// Check if the client sent a valid number
// (We are not checking for a good bid here.)
errno = 0;
*bid = strtol(buf, &endptr, 10);
if (errno != 0 || endptr == buf)
{
*bid = -1;
}
return 0;
}
void broadcast(struct user *users, char *msg, int size)
{
for (int i = 0; i < MAX_CONNECTIONS; i++)
{
if (users[i].sock_fd != -1)
{
if (write(users[i].sock_fd, msg, size) == -1)
{
// Design flaw: can't remove this socket from select set
close(users[i].sock_fd);
users[i].sock_fd = -1;
}
}
}
}
int prep_bid(char *buf, Auction *a, struct timeval *t)
{
// send item, current bid, time left in seconds
printf("robin2-%s-%d\n", a->item, a->highest_bid);
printf("robin-%ld\n", t->tv_sec);
sprintf(buf, "%s %d %ld", a->item, a->highest_bid, t->tv_sec);
printf("robin-bid2\n");
return 0;
}
/* Update auction if new_bid is higher than current bid.
* Write to the client who made the bid if it is lower
* Broadcast to all clients if the bid is higher
*/
int update_bids(int client_index, struct user *users,
int new_bid, Auction *auction, struct timeval *t)
{
char buf[BUF_SIZE];
if (new_bid > auction->highest_bid)
{
auction->highest_bid = new_bid;
auction->client = client_index;
prep_bid(buf, auction, t);
if (verbose)
{
fprintf(stderr, "[%d] Sending to %d:\n %s\n",
getpid(), users[client_index].sock_fd, buf);
}
broadcast(users, buf, strlen(buf) + 1);
}
else
{
fprintf(stderr, "Client %d sent bid that was too low. Ignored\n",
client_index);
}
return 0;
}
int main(int argc, char **argv)
{
argc = 7;
argv[1] = "-v";
argv[2] = "-t";
argv[3] = "5";
argv[4] = "-p";
argv[5] = "4000";
argv[6] = "robin";
Auction auction;
int opt;
int port = PORT;
struct timeval timeout;
struct timeval *time_ptr = NULL;
int minutes = 0;
while ((opt = getopt(argc, argv, "vt:p:")) != -1)
{
switch (opt)
{
case 'v':
verbose = 1;
break;
case 't':
minutes = atoi(optarg);
timeout.tv_sec = minutes * 60;
timeout.tv_usec = 0;
time_ptr = &timeout;
break;
case 'p':
port = atoi(optarg);
break;
default:
fprintf(stderr, "Usage: auction_server [-v] [-t timeout] [-p port] item\n");
exit(1);
}
}
if (optind >= argc)
{
fprintf(stderr, "Expected argument after options\n");
exit(1);
}
auction.item = argv[optind];
auction.client = -1;
auction.highest_bid = -1;
struct user users[MAX_CONNECTIONS];
for (int index = 0; index < MAX_CONNECTIONS; index++)
{
users[index].sock_fd = -1;
users[index].name[0] = '\0';
}
// Create the socket FD.
int sock_fd = socket(AF_INET, SOCK_STREAM, 0);
if (sock_fd < 0)
{
perror("server: socket");
exit(1);
}
// Set information about the port (and IP) we want to be connected to.
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = INADDR_ANY;
// This sets an option on the socket so that its port can be reused right
// away. Since you are likely to run, stop, edit, compile and rerun your
// server fairly quickly, this will mean you can reuse the same port.
int on = 1;
int status = setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR,
(const char *)&on, sizeof(on));
if (status == -1)
{
perror("setsockopt -- REUSEADDR");
}
// This should always be zero. On some systems, it won't error if you
// forget, but on others, you'll get mysterious errors. So zero it.
memset(&server.sin_zero, 0, 8);
// Bind the selected port to the socket.
if (bind(sock_fd, (struct sockaddr *)&server, sizeof(server)) < 0)
{
perror("server: bind");
close(sock_fd);
exit(1);
}
// Announce willingness to accept connections on this socket.
if (listen(sock_fd, MAX_BACKLOG) < 0)
{
perror("server: listen");
close(sock_fd);
exit(1);
}
if (verbose)
{
fprintf(stderr, "[%d] Ready to accept connections on %d\n",
getpid(), port);
}
// The client accept - message accept loop. First, we prepare to listen
// to multiple file descriptors by initializing a set of file descriptors.
int max_fd = sock_fd;
fd_set all_fds;
FD_ZERO(&all_fds);
FD_SET(sock_fd, &all_fds);
while (1)
{
// select updates the fd_set it receives, so we always use a copy
// and retain the original.
fd_set listen_fds = all_fds;
int nready;
if ((nready = select(max_fd + 1, &listen_fds, NULL, NULL, time_ptr)) == -1)
{
perror("server: select");
exit(1);
}
if (nready == 0)
{
char buf[BUF_SIZE];
sprintf(buf, "Auction closed: %s wins with a bid of %d\r\n",
users[auction.client].name, auction.highest_bid);
printf("%s", buf);
broadcast(users, buf, BUF_SIZE);
exit(0);
}
// Is it the original socket? Create a new connection ...
if (FD_ISSET(sock_fd, &listen_fds))
{
int client_fd = accept_connection(sock_fd, users);
if (client_fd != -1)
{
if (client_fd > max_fd)
{
max_fd = client_fd;
}
FD_SET(client_fd, &all_fds);
if (verbose)
{
fprintf(stderr, "[%d] Accepted connection on %d\n",
getpid(), client_fd);
}
}
}
// Next, check the clients.
for (int index = 0; index < MAX_CONNECTIONS; index++)
{
if (users[index].sock_fd > -1 && FD_ISSET(users[index].sock_fd, &listen_fds))
{
int client_closed = 0;
int new_bid = 0;
if (users[index].name[0] == '\0')
{
client_closed = read_name(index, users);
if (client_closed == 0)
{
char buf[BUF_SIZE];
prep_bid(buf, &auction, time_ptr);
if (verbose)
{
fprintf(stderr, "[%d] Sending to %d:\n %s\n",
getpid(), users[index].sock_fd, buf);
}
if (write(users[index].sock_fd, buf, strlen(buf) + 1) == -1)
{
fprintf(stderr, "Write to %d failed\n", sock_fd);
close(sock_fd);
}
}
}
else
{ // read a bid
client_closed = read_bid(index, users, &new_bid);
if (client_closed == 0)
{
update_bids(index, users, new_bid, &auction, time_ptr);
}
}
if (client_closed > 0)
{
FD_CLR(client_closed, &all_fds);
printf("Client %d disconnected\n", client_closed);
}
}
}
}
// Should never get here.
return 1;
}
Caveat: Because you've only posted partial code for server and client, this will be some suggestions.
Your client can attach/connect to multiple bid servers simultaneously. As such, it must be able to keep track of the multiple connections in a manner similar to a server.
Your main [stated] issue is that you're blocking the client on a user prompt (e.g. from stdin via scanf et. al.). Presently, this means that the client is "stuck" at user input prompt and can not field messages from the servers it is connected to. More on how to fix this below.
So, you'll have a bunch of code from the server that needs to be in the client with some minor differences. You may wish to generalize some of the server code a bit, so it can work both in server and client (e.g. you may want to move it to common.c).
You already have code in the server to handle multiple connections. The server needs a select mask that is the OR of the listen fd and all active client fds.
Likewise, your client needs a select mask that is the OR of the fd for user input (e.g. 0) and all active server connections.
Doing select on fd 0 and using stdio.h streams won't work too well. So, replace access to stdin with (e.g.) read(0,line_buffer,sizeof(line_buffer)). You do this if fd 0 is set in the select mask. The role is very similar to what your server does for the accept on sock_fd.
You'll need to allow for partial reads and append to the buffer until you see a newline. So, you'll have to do the work that fgets would normally do in assembling a whole line. Then, you can call parse_command.
Because read doesn't understand newline demarcations, the user could enter more than one line before you can do a read.
So, for user input of:
connect 4000\n
bid 100 4000\n
connect 5000\n
You may get partial reads of:
conn
ect
4000\nbid 100 4000
\nconnect
5000\n
You may also need to use the FIONREAD ioctl on the fd 0 to prevent blocking. And, you may need to set the kernel TTY layer into raw mode via termios calls.
The client now becomes very similar to your server code. It will handle [asynchronously] actions by any connected servers and user input.
A tip: Under the DRY principle ["don't repeat yourself"] ...
You already have a struct user in the server. The client will need something similar/identical, such as struct server. When generalizing the code, rather than having two distinct structs that do essentially the same thing, consider renaming the existing struct to (e.g.) struct connection
I have created a client-server file sharing system with multi threading. The client code is working correctly for a single client. When I increase the number of threads in client, segmentation fault is occurred in server code.
When I executed the code on gdb, it shows the error segmentation fault occurred, no such file or directory. Is this because of the threads sharing file descriptor? How to resolve the segmentation fault?
----------edit-----------
I considered all your suggestions. Most of the errors are resolved, but when I try to send a >10mb file, some send-recv call does not execute fully while sending it out with threads(It works fine with a single thread). I believe this is the reason memory leakage is happening and ultimately results in segmentation fault(file pointers not closed). The same is happening in gdb.
How to resolve this send receive blocking error?
client code
#include <time.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<string.h>
#include<stdio.h>
#include <stdlib.h>
#include<pthread.h>
#include <semaphore.h>
#define PORT 8029
#define SIZE 1024
#define SERVER_ADDR "192.168.43.158" //"10.15.36.112"
//defining number of threads
struct ser_data
{
int sockfd;
int n;
};
void *client_req(void * data){
// printf("inside thread\n");
//sleep(1);
int s,c,n,read_size,r;
//login_id and password of the user
//array to choose file names randomly
//char f_name[20][20]={"f0.txt","f1.txt","f2.txt","f3.txt","f4.txt","f5.txt","f6.txt","f7.txt","f8.txt","f9.txt","f10.txt\0","f11.txt\0","f12.txt\0" ,"f13.txt\0","f14.txt\0","f15.txt\0","f16.txt\0","f17.txt\0","f18.txt","f19.txt"};
//socket address for client and server
//used for generation of random no
time_t t;
struct sockaddr_in cli,serv;
FILE *f;
char fname[SIZE]="file_cli/";
char f_name[SIZE];
char login_id[21], pswd[21], choice[2];
//msg_cli_rec= message recieved form server
char msg_cli_rec[SIZE];
//msg_cli_send =message sent by client
char msg_cli_send[SIZE];
time_t start, stop;
int brk=0;
start = time(NULL);
s=socket(AF_INET,SOCK_STREAM,0);
bzero((char*)&serv,sizeof(cli));
cli.sin_family=AF_INET;
cli.sin_port=htons(PORT);
cli.sin_addr.s_addr = inet_addr(SERVER_ADDR);
connect(s,(struct sockaddr*)&cli,sizeof(cli));
//printf("\nConnected with server");
strcpy(choice, "1");
/*msg_cli_rec = (char *) malloc(1000* sizeof(char));
msg_cli_send = (char *) malloc(1000* sizeof(char));*/
//if user wants to login
if(strcmp(choice,"1")==0)
{
strcpy(login_id, "prach");
send(s, login_id, sizeof(login_id), 0);
strcpy(pswd, "prach");
send(s, pswd, sizeof(pswd), 0);
}
//making default choice download 1
do {
strcpy(choice, "1\0");
strcpy(msg_cli_send, choice);
//send(s, choice, sizeof(choice), 0);
send(s,msg_cli_send,sizeof(msg_cli_send),0);
//random number generation
srand((unsigned) time(NULL));
//r=((unsigned)rand()*(i++))%20;
r=15;
if(strcmp(choice,"1")==0)
{
/*if(recv(s, msg_cli_rec, sizeof(msg_cli_rec), 0))
{
//if((strcmp("end",msg_cli_rec))==0)break;
printf("\n%s", msg_cli_rec);
}*/
/*printf("\nEnter the file name you want:");
scanf("%s", msg_cli_send);*/
// to select file name with index of the random number
sprintf(f_name,"file (%d).txt",r);
strcpy(msg_cli_send, "");
strcpy(msg_cli_send,f_name);
// printf("\n%s",msg_cli_send);
// printf("\n rand =%d\n", r );
send(s,msg_cli_send,sizeof(msg_cli_send),0);
// printf("\nThe received file content is:");
//receiving the file names
f = fopen(strcat(fname,f_name),"w");
bzero( msg_cli_rec, sizeof(msg_cli_rec));
while((recv(s, msg_cli_rec, sizeof(msg_cli_rec), 0)> 0)&&(*msg_cli_rec!='\0'))
{//fflush(stdout);
if((strcmp("quit",msg_cli_rec))==0)break;
fprintf(f, "%s", msg_cli_rec);
//printf("\n%s", msg_cli_rec);
bzero( msg_cli_rec, sizeof(msg_cli_rec));
}
// printf("File recieved");
fclose(f);
strcpy(fname,"\0" );
//sem_post(&sem);
}
stop = time(NULL);
// printf("\n%s\n", ctime(&stop));
//printf("%ld", (stop-start));
//set the timer to 300 seconds
}while(*choice == '1' && (stop-start)<10);
//tell the server that we are done with sending files
strcpy(choice, "0");
send(s, choice, sizeof(choice), 0);
printf("%ld\n", (stop-start) );
/* free(msg_cli_rec);
free(msg_cli_send);*/
close(s);
//pthread_exit(NULL);
}
int main()
{
int N_Threads=2, count =0;
struct ser_data data;
/*while(N_Threads<=2)
{
pthread_t t;
pthread_create( &t , NULL , client_req , NULL);
N_Threads++;
if ( ! pthread_detach(t) )
printf("Thread detached successfully !!!\n");
//pthread_join(t, NULL);
}*/
while(count != N_Threads){
pthread_t handle;
count = count+1;
data.sockfd = count;
if(pthread_create(&handle, NULL, client_req,(void *)&data)<0)
error("Error creating thread");
else
printf("Thread allocation successful for fd: %d\n",data.sockfd);
}
pthread_exit(NULL);
}
server code
#include <time.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<string.h>
#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>
#include<dirent.h>
#include <mysql/mysql.h>
#include <semaphore.h>
#define PORT 8029
#define SIZE 1024
#define QUERY_SIZE 200
#define N_Threads 5
#define SERV_ADDR "192.168.43.158"
clock_t start, stop;
//login id and password of the user
int file_id=1;
/*Database variables*/
MYSQL *db_conn;
char *db_server = "localhost";
char *db_user = "root";
char *db_password = "root";
char *database = "file_db";
//for synchronization while accessing the db
sem_t sem;
/* A function which generates the and returns login query statement*/
char* query_login(char *query, char *login_id, char *pswd)
{
//generating query
strcpy(query,"SELECT * FROM user_info WHERE user_id='");
strcat(query, login_id);
strcat(query, "' AND pswd='");
strcat(query, pswd);
strcat(query, "'");
return query;
}
/* A function which generates and returns the register query statement*/
char* query_register(char *query, char *login_id, char *pswd)
{
strcpy(query, "INSERT INTO user_info VALUES ( '");
strcat(query, login_id);
strcat(query, "', '");
strcat(query, pswd);
strcat(query, "' )");
return query;
}
void *connect_client(void *socket)
{ int sock=*(int*)socket;
printf("\nFD %d",sock);
char msg_c_r[SIZE], msg_s_s[SIZE];
//for the choice given to the user to login or register
char choice='0';
char msg_serv_send[SIZE],msg_serv_rec[SIZE];
char msg_cli_rec[SIZE];
char fpath[SIZE] = "file_serv/";
char fname[SIZE];
int read_size;
int num_fields=0;
char * line = NULL;
size_t len = 0;
ssize_t read;
MYSQL_ROW row;
MYSQL_RES *db_res;
char login_id[21], pswd[21];
FILE *f;
FILE *fc;
char name[SIZE];
char query1[SIZE];
char query[QUERY_SIZE];
/*locking the database for mutual exclusion*/
//sem_wait(&sem);
//executing a query
choice = '1';
strcpy(query, "\0");
switch(choice)
{
//1 = login
case '1':
/*to find the login id and password of the user*/
bzero(login_id, sizeof(login_id));
recv(sock, login_id, sizeof(login_id), 0);
bzero(pswd, sizeof(pswd));
recv(sock, pswd, sizeof(pswd), 0);
printf("The login id is: %s\nThe Password is: %s\n", login_id, pswd);
//lock for accessing db in mutual exclusion
sem_wait(&sem);
query_login(query, login_id, pswd);
//checking the details given by client
if (mysql_query(db_conn, query)!=0) {
fprintf(stderr, "%s\n", mysql_error(db_conn));
}
strcpy(query, "\0");
strcat(query,"select * from user_info where user_id='");
strcat(query,login_id);
strcat(query,"'");
mysql_query(db_conn, query);
db_res = mysql_store_result(db_conn);
row = mysql_fetch_row(db_res);
if (row!=0) {
//send(sock,"T",sizeof("T"),0);
printf("\nT");
}
//freeing the result variable so it can be used further
mysql_free_result(db_res);
//release lock
sem_post(&sem);
break;
}//switch case
/*send(sock, "\nPlease enter your choice \n 1- File Download \n 2-File Upload\n 3-Rating\n", sizeof("\nPlease enter your choice \n 1- File Download \n 2-File Upload\n 3-Rating\n"), 0);*/
int nu=1;
do{
bzero(msg_serv_rec,sizeof(msg_serv_rec));
if(recv(sock, msg_serv_rec,sizeof(msg_serv_rec), 0)>0)
{
choice = msg_serv_rec ? *msg_serv_rec : '0';
printf("\n choice = %c\n", choice);
strcpy(query, "\0");
//printf("Client's choice is file Download\n" );
/*Sending File to the client line by line
checking the database connection*/
if(choice == '1'){
/*if(mysql_query(db_conn, "SELECT name FROM file_info")==0)
{
db_res = mysql_store_result(db_conn);
num_fields = mysql_num_fields(db_res);
if(num_fields>0)
{
while ((row = mysql_fetch_row(db_res)))
{
for(int i = 0; i < num_fields; i++)
{
char *fname1=row[i] ? row[i] : "NULL";
strcat(name,fname1);
strcat(name, "\n");
//send(sock,name,sizeof(name),0);
//printf("\n%s",name);
}
}
//sending list of all files to client
send(sock,name,sizeof(name),0);*/
/*emptying the name!!
strcpy(name, "");*/
//freeing the result variable so it can be used further
/*mysql_free_result(db_res);
sem_post(&sem);*/
bzero(msg_serv_rec,sizeof(msg_serv_rec));
if(recv(sock, msg_serv_rec,sizeof(msg_serv_rec), 0)>0)
{//which file recieved
printf("%s\n", msg_serv_rec );
// sem_wait(&sem);
f = fopen(strcat(fpath, msg_serv_rec),"r");
while(fgets(msg_serv_send, sizeof(msg_serv_send), f) !=NULL)
{
if((*msg_serv_send!=EOF || *msg_serv_send!='\n'))
{
send(sock, msg_serv_send, sizeof(msg_serv_send), 0);
//printf("\n%s", msg_serv_send);
}
else
break;
}
send(sock,"quit",sizeof("quit"),0);
fclose(f);
strcpy(fpath, "file_serv/");
//sem_post(&sem);
printf("\nFile sent to the client\n");
}
}
else if (choice == '0')
break;
strcpy(msg_serv_rec, "");
//stop = clock();
//time(NULL);
}
else
{
choice = '0';
}
}while ( choice != 'f' && choice != '0');
nu++;
/* unblocking the semaphores to allow other threads to access*/
//sem_post(&sem);
if(read_size == 0)
{
puts("\nClient disconnected\n");
fflush(stdout);
}
/*else if(read_size == -1)
{perror("recv failed");}
fclose(f);*/
close(sock);
pthread_exit(NULL);
}
int main()
{ int s,n,i, clilen;
int c;
int newsockfd;
int *new_sock;
start = clock();
//pthread_t handle;
struct sockaddr_in cli,serv;//socket address for client and server
MYSQL_ROW row;
MYSQL_RES *db_res;
//initializing the semaphore
sem_init(&sem, 0, 1);
//synchronization in DB
sem_wait(&sem);
/*Database connectivity*/
db_conn = mysql_init(NULL);
/* Connect to database */
if (!mysql_real_connect(db_conn, db_server, db_user, db_password, database, 0, NULL, 0)) {
fprintf(stderr, "%s\n", mysql_error(db_conn));
exit(1);
}
/* send SQL query */
if (mysql_query(db_conn, "show tables")) {
fprintf(stderr, "%s\n", mysql_error(db_conn));
exit(1);
}
db_res = mysql_use_result(db_conn);
/* output table name */
printf("MySQL Tables in mysql database:\n");
while ((row = mysql_fetch_row(db_res)) != NULL)
printf("%s \n", row[0]);
//freeing the result variable so it can be used further
mysql_free_result(db_res);
sem_post(&sem);
//Server socket
s=socket(AF_INET,SOCK_STREAM,0);
bzero((char*)&serv,sizeof(serv));
serv.sin_family=AF_INET;
serv.sin_port=htons(PORT);
serv.sin_addr.s_addr=inet_addr( SERV_ADDR);//"10.15.36.112");
/*printf("\nServer is waiting for client to respond");
i=0*/
//accept the incomming connections from client
bind(s,(struct sockaddr *)&serv,sizeof(serv));
printf("\nAddress bind successful");
listen(s,3000);//4 is the limit of the number of outstanding connections
n=sizeof(cli);
/*
i=0;
//accept the incomming connections from client
while( (c = accept(s, (struct sockaddr *)&cli, (socklen_t*)&n))) //&& (stop-start)<300 )
{ puts("Connection accepted\n");
pthread_t t;
printf("sock =%d\n", c);
if( pthread_create( &t , NULL , connect_client , (void*) c) < 0)
{
perror("could not create thread");
return 1;
}
i++;
/*Now detach the thread ,When a detached thread terminates, its resources are
automatically released back to the system without the need for
another thread to join with the terminated thread.*/
/* if ( ! pthread_detach(t) )
printf("Thread detached successfully !!!\n");
puts("Handler assigned");
stop = clock();
}*/
clilen=sizeof(cli);
while(newsockfd = accept(s, (struct sockaddr *) &cli, &clilen))
{
if(newsockfd < 0)
error("ERROR on accept");
else{
pthread_t handle;
new_sock = malloc(1);
*new_sock = newsockfd;
if(pthread_create(&handle, NULL,connect_client ,(void *)new_sock)<0)
error("Error creating thread");
else
printf("Thread fd: %d\n",newsockfd);
if ( ! pthread_detach(handle) )
printf("Thread detached successfully !!!\n");
}
}
/* close database connection */
mysql_free_result(db_res);
mysql_close(db_conn);
close(s);
/*destroying the mutex */
sem_destroy(&sem);
return 0;
}
I am trying to programm a small HTTP-Server with fork(). When I connect to it via firefox, it doesn't show the the page, until I terminate the Server.
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdbool.h>
#include <sys/socket.h>
#include <signal.h>
#define LISTEN_MAX 5
#define CONT_MAX 10000
#define PORT 8081
#define MAX_FILE 2
#define S_SHORT 50
#define MAX_CONTENT 1000
#define MAX_HEADER 200
const size_t BUF_LEN = 1024; //was 128
const size_t REQUEST_LEN=1024;
char file_names[MAX_FILE][S_SHORT];
FILE *file_deskriptors[MAX_FILE];
int file_sizes[MAX_FILE];
char file_contents[MAX_FILE][MAX_CONTENT];
// Something unexpected happened. Report error and terminate.
void sysErr( char *msg, int exitCode ) {
fprintf( stderr, "%s\n\t%s\n", msg, strerror( errno ) );
exit( exitCode );
}
// get_line was borrowed from Tiny HTTPd under GPLv2
// https://sourceforge.net/projects/tinyhttpd/?source=typ_redirect
int get_line(int sock, char *buf, int size) {
int i = 0;
char c = '\0';
int n;
while ((i < size - 1) && (c != '\n'))
{
n = recv(sock, &c, 1, 0);
/* DEBUG printf("%02X\n", c); */
if (n > 0)
{
if (c == '\r')
{
n = recv(sock, &c, 1, MSG_PEEK);
/* DEBUG printf("%02X\n", c); */
if ((n > 0) && (c == '\n'))
recv(sock, &c, 1, 0);
else
c = '\n';
}
buf[i] = c;
i++;
}
else
c = '\n';
}
buf[i] = '\0';
return(i);
}
void copyHeaderToBuffer(char *tx_buff, int *status) {
switch(*status) {
case 200: strcpy(tx_buff,"HTTP/1.0 200 OK\r\nContentÂtype: text/html\r\n\r\n"); break;
}
return;
}
void answer(int *accfd, char *request ) {
int file_size, file_index, status, sent_bytes;
file_size, file_index, status = 0;
char method[S_SHORT], ressource[S_SHORT], proto[S_SHORT];
char tx_buff[MAX_CONTENT+MAX_HEADER];
//rehash query
splitRequest(request, method, ressource, proto);
//check for <GET>
checkMethod(method);
//search the file and get index
getFileIndexByName(ressource, &file_index);
file_size = file_sizes[file_index];
status = getFileStatus(&file_index);
createAnswerMessage(tx_buff, &status, &file_index);
//send the answer
if ( (sent_bytes= write( accfd, tx_buff, strlen(tx_buff))) == -1 ) {
sysErr( "[-] Client Fault: SEND", -4 );
}
return;
}
void createAnswerMessage(char *tx_buff, int *status, int *file_index) {
copyHeaderToBuffer(tx_buff, status);
strcat(tx_buff,file_contents[*file_index]);
strcat(tx_buff,"\r\n");
return;
}
int getFileStatus(int *file_index) {
return 200;
}
void splitRequest(char *request, char *method, char *ressource, char *proto) {
char *temp;
if ((temp = strtok(request, " ")) != NULL) {
strcpy(method, temp);
}
if ((temp = strtok(NULL, " ")) != NULL) {
strcpy(ressource, temp);
}
if ((temp = strtok(NULL, " ")) != NULL) {
strcpy(proto, temp);
}
//remove leading "/" from ressource
cleanRessource(ressource);
return;
}
void cleanRessource(char *ressource) {
if (*ressource == '/') {
printf("\nstr_len_ressource: %i",strlen(ressource));
for ( int i=0; i < strlen(ressource); i++ ) {
ressource[i]=ressource[i+1];
}
}
return;
}
void checkMethod(char *method){
if (strcmp(method, "GET") ) {
printf("\n[-] Error: Method \"%s\" not known .",method);
exit(0);
}
printf("\nincheckMethod method = %s",method);
return;
}
void getFileIndexByName (char *ressource, int *file_index) {
for (int i=0; i<MAX_FILE; i++) {
if ( !strcmp(ressource, file_names[i]) ) {
*file_index = i;
return;
}
}
printf("\[-] Error: File \"%s\" not known.",ressource);
exit(0);
}
void filesInit () {
memset(file_names, '\0', sizeof(file_names));
memset(file_contents, '\0', sizeof(file_contents));
//define your files here:
strcpy(file_names[0],"index.htm");
for (int i=0; i<MAX_FILE; i++) {
//choose only existing files
if (file_names[i][0]!='\0') {
//open file
file_deskriptors[i] = fopen(file_names[i],"r");
//get file size
fseek(file_deskriptors[i], 0, SEEK_END);
file_sizes[i] = ftell(file_deskriptors[i]);
//read the file content to file_contents
fseek(file_deskriptors[i], 0, SEEK_SET);
fread(file_contents[i], 1, CONT_MAX, file_deskriptors[i]);
}
}
return;
}
void filesClose() {
return;
}
int main(int argc, char **argv)
{
//kill childs if recieving SIGCHLD
signal(SIGCHLD,SIG_IGN);
int connfd, accfd;
struct sockaddr_in server_addr, client_addr;
socklen_t sockaddr_len = sizeof(struct sockaddr_in);
//initial the available files on server
filesInit();
// create socket
if ( ( connfd = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0) {
sysErr( "Server Fault : SOCKET", -1 );
}
// Set params so that we receive IPv4 packets from anyone on the specified port
memset( &server_addr, 0, sockaddr_len );
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons( PORT );
//bind socket to port
if ( bind( connfd, (struct sockaddr *) &server_addr, sockaddr_len ) < 0 ) {
sysErr( "\n[-] Server Fault : BIND", -2 );
}else{printf("[+] SERVER ONLINE");}
//let server listen for incoming connections
if ( listen( connfd, LISTEN_MAX) < 0 ) {
sysErr( "[-] Server Fault : LISTEN", -3 );
}
//main loop for accepting clients
while ( true ) {
pid_t pid;
//connecting specific client
if ( (accfd=accept( connfd, (struct sockaddr *) &client_addr, &sockaddr_len )) < 0 ) {
sysErr( "[-] Server Fault : ACCEPT", -4 );
}
//fork & answer
else {
printf("\n[+] CLIENT CONNECTED\n");
switch ( pid = fork() ) {
case -1: {
printf("\n[-] Error while fork()");
return EXIT_FAILURE;
}
case 0: {
int req_line_len=1; //length of request line
int first_line_on = 1; //set first line parameter
char req_line[S_SHORT]; //current read line
char first_line[S_SHORT]; //save first line
memset(req_line, 0, S_SHORT);
memset(first_line, 0, S_SHORT);
printf("\n[+] HTTP REQUEST on accfd: %i",accfd);
//reading line by line from socket
while((req_line_len > 0) && strcmp("\n", req_line)){
req_line_len = get_line( accfd, req_line, S_SHORT-1);
//get first line and save it
if (first_line_on) { first_line_on = 0; strcpy(first_line,req_line); }
if((req_line_len > 0) && strcmp("\n", req_line)) printf("%s",req_line);
}
//answering to client
answer(accfd, first_line);
//close connection
if (!close(accfd)) {printf("\n[+] CONNECTION CLOSED");}
exit(0);
break;
}
default: {
//main process
break;
}
}
}
}
//close listening socket
close( connfd );
//close server files
filesClose();
return 0;
}
The child is terminated, and I get the answer CONNECTION CLOSED
Is there a logical mistake in my Code?
EDIT:
I added a full minimum code.
The "\r\n" I add at to the transmitting msg.
It works fine if I add
close(accfd);
to the main(), but I think it is not actually the problem(only a side effect solution)
the index.htm could be:
<html><body><b>index</b><br>C is a interesting language!</body></html>
When you call fork() the file descriptors of the parent in copied to the child, this is why you can still access the socket in the child process. The network stack will keep the socket alive as long as you have at least one file descriptor open to the socket. You close the socket in the child process but still have it open in the parent.
In other words adding a call to close(accfd) in the parent should fix your problem.
My C program is not writing to a file the same data that it is displaying. how do i save what is outputted to the screen in a file. I am trying to save a webpage, the file name is defined by the third option, [site] [page] [path]
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <netdb.h>
#include <string.h>
int create_tcp_socket();
char *get_ip(char *host);
char *build_get_query(char *host, char *page);
void usage();
#define HOST "coding.debuntu.org"
#define PAGE "/"
#define PORT 80
#define USERAGENT "HTMLGET 1.0"
#define OS "mac osx"
int main(int argc, char **argv)
{
struct sockaddr_in *remote;
int sock;
int tmpres;
char *ip;
char *get;
char buf[BUFSIZ+1];
char *host;
char *page;
char *HTMLfile;
if(argc == 1){
usage();
exit(2);
}
host = argv[1];
if(argc > 2){
page = argv[2];
}else{
page = PAGE;
}
HTMLfile = argv[3];
sock = create_tcp_socket();
ip = get_ip(host);
fprintf(stderr, "<!--\nIP is %s\n", ip);
remote = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in *));
remote->sin_family = AF_INET;
tmpres = inet_pton(AF_INET, ip, (void *)(&(remote->sin_addr.s_addr)));
if( tmpres < 0)
{
perror("Can't set remote->sin_addr.s_addr");
exit(1);
}else if(tmpres == 0)
{
fprintf(stderr, "%s is not a valid IP address\n", ip);
exit(1);
}
remote->sin_port = htons(PORT);
if(connect(sock, (struct sockaddr *)remote, sizeof(struct sockaddr)) < 0){
perror("Could not connect");
exit(1);
}
get = build_get_query(host, page);
fprintf(stderr, "nQuery is:\n<<START>>\n%s<<END>>\n-->\n", get);
//Send the query to the server
int sent = 0;
while(sent < strlen(get))
{
tmpres = send(sock, get+sent, strlen(get)-sent, 0);
if(tmpres == -1){
perror("Can't send query");
exit(1);
}
sent += tmpres;
}
//now it is time to receive the page
memset(buf, 0, sizeof(buf));
int htmlstart = 0;
char * htmlcontent;
while((tmpres = recv(sock, buf, BUFSIZ, 0)) > 0){
if(htmlstart == 0)
{
/* Under certain conditions this will not work.
* If the \r\n\r\n part is splitted into two messages
* it will fail to detect the beginning of HTML content
*/
htmlcontent = strstr(buf, "\r\n\r\n");
if(htmlcontent != NULL){
htmlstart = 1;
htmlcontent += 4;
}
}else{
htmlcontent = buf;
}
if(htmlstart){
fprintf(stdout, "%s", htmlcontent);
}
FILE *f;
f = fopen(HTMLfile, "w");
fprintf(f, "%s", htmlcontent); //stderr, "%s"
fclose(f);
memset(buf, 0, tmpres);
}
if(tmpres < 0)
{
perror("Error receiving data");
}
free(get);
free(remote);
free(ip);
close(sock);
return 0;
}
void usage()
{
fprintf(stderr, "USAGE: htmlget host [page]\n\
\thost: the website hostname. ex: coding.debuntu.org\n\
\tpage: the page to retrieve. ex: index.html, default: /\n");
}
int create_tcp_socket()
{
int sock;
if((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0){
perror("Can't create TCP socket");
exit(1);
}
return sock;
}
char *get_ip(char *host)
{
struct hostent *hent;
int iplen = 15; //XXX.XXX.XXX.XXX
char *ip = (char *)malloc(iplen+1);
memset(ip, 0, iplen+1);
if((hent = gethostbyname(host)) == NULL)
{
herror("Can't get IP");
exit(1);
}
if(inet_ntop(AF_INET, (void *)hent->h_addr_list[0], ip, iplen) == NULL)
{
perror("Can't resolve host");
exit(1);
}
return ip;
}
char *build_get_query(char *host, char *page)
{
char *query;
char *getpage = page;
char *tpl = "GET /%s HTTP/1.0\r\nHost: %s\r\nUser-Agent: %s\r\n\r\n";
if(getpage[0] == '/'){
getpage = getpage + 1;
fprintf(stderr,"Removing leading \"/\", converting %s to %s\n", page, getpage);
}
// -5 is to consider the %s %s %s in tpl and the ending \0
query = (char *)malloc(strlen(host)+strlen(getpage)+strlen(USERAGENT)+strlen(OS)+strlen(tpl)-5);
sprintf(query, tpl, getpage, host, USERAGENT);
return query;
// FILE *f;
// f = fopen(HTMLfile, "w");
// fprintf(f, htmlcontent);
// fclose(f);
}
Here is where i am saving the file:
FILE *f;
f = fopen(HTMLfile, "w");
fprintf(f, "%s", htmlcontent); //stderr, "%s"
fclose(f);
Here is the result that it saves for my question (This Page)
(['_setCustomVar', 1, 'tags', '|c|file|networking|']);
_gaq.push(['_trackPageview']);
var _qevents = _qevents || [];
(function () {
var ssl='https:'==document.location.protocol,
s=document.getElementsByTagName('script')[0],
ga=document.createElement('script');
ga.type='text/javascript';
ga.async=true;
ga.src=(ssl?'https://ssl':'http://www')+'.google-analytics.com/ga.js';
s.parentNode.insertBefore(ga,s);
var sc=document.createElement('script');
sc.type='text/javascript';
sc.async=true;
sc.src=(ssl?'https://secure':'http://edge')+'.quantserve.com/quant.js';
s.parentNode.insertBefore(sc,s);
})();
_qevents.push({ qacct: "p-c1rF4kxgLUzNc" });
</script>
</body>
</html>
FILE *f;
f = fopen(HTMLfile, "w");
fprintf(f, "%s", htmlcontent); //stderr, "%s"
fclose(f);
Rather than opening and closing the file each time through the loop, you should open
it once before the loop, keep it open while you're writing into it, then close it after
the loop.
Instead of opening the file with "w" use "a". Better yet, only open the file once.
f = fopen(HTMLfile, "a");
w" write: Create an empty file for output operations. If a file with the same name already exists, its contents are discarded and the file is treated as a new empty file.
"a" append: Open file for output at the end of a file. Output operations always write data at the end of the file, expanding it. Repositioning operations (fseek, fsetpos, rewind) are ignored. The file is created if it does not exist.