Related
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
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.
In an exercise problem, I am required to build a client program (write first) that opens a .txt file, put each line and the total bytes of each line into a struct variable and then send it out to the server program (read first). Right after this is done, the client program will also receive a struct file (similarly only has char * and int attributes) from the server program.
// Below are global variables in both programs
#define BUFSIZE 1024
struct info_pack
{
char line[BUFSIZE]; // the line to receive messages
int bytes; // the bytes of data transferred
};
char fifo_path[] = "./my_fifo";
struct info_pack info_w; // the info_pack for writing each line in text.txt
struct info_pack info_r; // the info_pack for reading feedback info_pack sent from the server program
First is the client program:
// the main() in the client program
int main()
{
int fd;
int i = 0, index = 1, bytes = 0, line_length, fifo_read;
char *file_path = "/home/text.txt";
FILE *fd2;
mkfifo(fifo_path, 0666);
if ((fd2 = fopen(file_path, "r")) < 0)
{
perror("Opening file");
return -1;
}
else
{
printf("Successfully open the target file\n");
while (fgets(info.line, BUFSIZE, fd2) != NULL)
// the "segmentation fault" error appears right after this line
{
info_w.bytes = strlen(line);
fd = open(fifo_path, O_WRONLY);
printf("The %d th line sent out is: %s\n%d bytes are sent\n\n",
index, info_w.line, info_w.bytes);
write(fd, &info_w, sizeof(info_w) + 1);
close(fd);
fd = open(fifo_path, O_RDONLY);
fifo_read = read(fd, &info_r, sizeof(info_r));
close(fd);
if (fifo_read > 0)
{
printf("Feedback: %s\nand %d bytes are returned\n", info_r.line, info_r.bytes);
}
}
printf("All data is successfully transfered\n");
}
return 0;
}
Then is the server program
// the main() in the server program
int main()
{
int fd, fifo_read;
int line_length;
char *feedback = "SUCCESS";
strcpy(info_w.line, feedback);
info_w.bytes = strlen(feedback);
// define a constant info_pack variable to send to the client program
if (mkfifo(fifo_path, 0666) < 0)
{
perror("client end: ");
exit(-1);
}
while (1)
// This server program will wait for any one single client's message
// This server program can only be terminated by manually input signals (like ^\)
{
fd = open(fifo_path, O_RDONLY);
printf("waiting for client's message\n");
fifo_read = read(fd, &info_r, sizeof(info_r));
close(fd);
if (fifo_read > 0)
// if receive the struct variable, print all of its attributes
{
if (info_r == NULL)
printf("Found no lines sent from the client\n");
else
printf("Read from fifo:\n %s\n(in info)%d bytes read (actually)%d bytes read\n", info_r.line, info_r.bytes, fifo_read);
}
else
{
sleep(1);
printf("Fail to read data from the client\n");
}
// Because of the error in client program this server program
// always pause here
fd = open(fifo_path, O_WRONLY);
printf("Now writing feedback to the client\n");
write(fd, info_w, sizeof(info_w));
close(fd);
}
}
Could anyone explain why the segmentation fault error appears in the client program? Then I can test if the both the client and the server can co-op properly.By the way, I read this post already but, in this post, it is a one-time data stream and I cannot find any hints in it.
Well to get started, what i'm trying to do is a multi client chat service.
I have read thousands of posts related to it but most of them are implemented with threads and nothing helps me, and i need to do it using FORKS.
I have my server that supports connections of multiple clients. Every time that a client request connection the server does the following:
Sets the shared variables that are needed.
Get the proper socket to handle the connection,
When a client connects, saves data of the client in a array of clients implemented with a struct,
Forks a process to handle this connection,
Goes back and blocks in the accept() function waiting another client.
The fork does the following:
Waits commands that the user sends,
Completes the request,
Waits for another command.
The fork works with a shared array of clients protected by a semaphore. This was done (by the father process) with shm_open, mmap and shm_open, to get the array shared among the child processes.
For now, the only 3 options are:
clientlist : to see the list of connected clients,
sendchat : to send a message to a desired client,
quit_ : to quit the programm and disconnects from the server.
Saying that, the problem is that i can't in any way to notice a client that a message is ready for him. The flow of the execution is:
Client C1 connects, Client C2 connects.
C1 whants to send a message to C2, C1 tells his process that he wants to talk to C2.
The process handling the connection of C1, search in the shared array the name of C2, and then writes the message sent by C1 in the buffer of C2.
And here is where i'm get stuck..i don't know how to make that C2 notice that is a new message for im.
I know this is long for anyone to care, but if you can, I'll be glad to get some help, please.
Below are the client, and server scripts.
Note: server.c compile with -lptrhead and -lrt for binding the shared memory library.
Note: the server gets correctly the socket from the function get_tcp_listen as you will see, no need to worry about this.
How should i approach this problem? Thanks !.
client.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include "socketlib.h" // FOR BINDINGS, GET SOCKET, AND STUFF
#define SERVER_PORT "50000"
#define CLIENT_PORT "50001"
#define MAXDATASIZE 256
#define MAXTIMESIZE 30
#define NICKSIZE 25
#define MAXCLIENT 10
#define MAXMSG 1024
typedef struct{
char nick[NICKSIZE]; // NICK
char ip[NI_MAXHOST]; // IP
char port[NI_MAXSERV]; // PORT
char connTime[MAXTIMESIZE]; // TIMESTAMP
int connected; // STATE
pid_t pidConn; // PROCESS PID
char *msg; // MSG BUFFER
}connData;
int main (int argc, char **argv) {
// GET SOCKET
int sockfd;
if ((sockfd = get_tcp_connect(argv[1], SERVER_PORT, CLIENT_PORT)) == -1) {
fprintf(stderr, "Error client: client_connect\n");
exit(1);}
///////////////////////////////////////////////////////////////////////
time_t ltime;
ltime = time(NULL);
char timeStamp[MAXTIMESIZE];
strcpy(timeStamp,ctime(<ime));
printf("\n%s\n", timeStamp);
// GET MY IP : PORT
char ip_num[NI_MAXHOST];
char port_num[NI_MAXSERV];
get_socket_addr(sockfd, ip_num, port_num);
get_peer_addr(sockfd, ip_num, port_num);
///////////////////////////////////////////////////////////////////////
// WELLCOME MSG FROM SERVER
char *well = (char*) malloc(MAXDATASIZE); int numbytes;
if ((numbytes = recv(sockfd, well, MAXDATASIZE-1, 0)) == -1) {
fprintf(stderr, "Error client: recv WELLCOME\n");
exit(1);
}
well[numbytes] = '\0'; printf("%s\n", well); free(well);
//////////////////////////////////////////////////////////////////////
// SEND NICK TO SERVER
char nick[NICKSIZE];
printf("\nEnter your NickName (25 chars): "); scanf("%s",nick);
if(send(sockfd, nick, NICKSIZE, 0) == -1){
fprintf(stderr,"Error client: send NICK\n");
exit(1);
}
///////////////////////////////////////////////////////////////////////
// GET CONNECTED USERS LIST FROM SERVER
int cantClients = 0; // FIRST: QUANTITY OF USERS
if (recv(sockfd, &cantClients, sizeof(int), 0) == -1) {
fprintf(stderr, "Error client: recv CANT CLIENTs\n");
exit(1);
}
connData *tmpCl = (connData *) malloc(sizeof(connData)*MAXCLIENT);
if (recv(sockfd, tmpCl, sizeof(connData)*MAXCLIENT, 0) == -1) {
fprintf(stderr, "Error client: recv ARRAY CLIENTS\n");
exit(1);
}
printf("\n****\tConnected Users\t****\n");
int i;
for(i = 0; i < cantClients; i++){
if(tmpCl[i].connected == 1){
printf("\nNick: %s\n", tmpCl[i].nick);
printf("IP: %s\n", tmpCl[i].ip);
printf("PORT: %s\n", tmpCl[i].port);
printf("Time: %s", tmpCl[i].connTime);
printf("Connected: %d\n", tmpCl[i].connected);
printf("PID: %d\n", tmpCl[i].pidConn);
printf("**********************************\n");
}
} free(tmpCl);
///////////////////////////////////////////////////////////////////////
// THE CLIENT PROCESS WAITS UNTIL THE USER TYPES A COMMAND
char *comm = (char*)malloc(MAXDATASIZE);
printf("\nEnter one option: ");
printf("\n\t-> clientlist TO SEE THE LIST OF CONNECTED CLIENTS\n");
printf("\t-> sendchat TO SEND A MESSAGE\n");
printf("\t-> quit_ TO QUIT CHAT\n>> ");
scanf("%s",comm);
int exitvar = 0;
while(exitvar == 0){
// PARA TRAER DATOS DEL SERVIDOR, ENVIO EL COMANDO, Y ME QUEDO ESPERANDO
if(send(sockfd, comm, MAXDATASIZE-1, 0) == -1){
fprintf(stderr,"Error client: send\n");
exit(1);
}
if(strcmp(comm,"clientlist") == 0){
// GET CONNECTED USERS LIST FROM SERVER
connData *tmpCl = (connData *) malloc(sizeof(connData)*MAXCLIENT);
if (recv(sockfd, tmpCl, sizeof(connData)*MAXCLIENT, 0) == -1) {
fprintf(stderr, "Error client: recv ARRAY CLIENT\n");
exit(1);
}
printf("\n****\tConnected Users\t****\n"); int i;
cantClients = (unsigned) sizeof(*tmpCl) / (unsigned) sizeof(connData);
for(i = 0; i < MAXCLIENT; i++){
if(tmpCl[i].connected == 1){
printf("\nNick: %s\n", tmpCl[i].nick);
printf("IP: %s\n", tmpCl[i].ip);
printf("PORT: %s\n", tmpCl[i].port);
printf("Time: %s", tmpCl[i].connTime);
printf("Connected: %d\n", tmpCl[i].connected);
printf("PID: %d\n", tmpCl[i].pidConn);
printf("**********************************\n");
}
} free(tmpCl);
}else if(strcmp(comm,"sendchat") == 0){
printf("To whom you want to talk?... ");
char *chatNick = (char *) malloc(NICKSIZE);
fgets(chatNick, NICKSIZE, stdin);
fgets(chatNick, NICKSIZE, stdin);
if((strlen(chatNick)>0) && (chatNick[strlen(chatNick)-1] == '\n') ){
chatNick[strlen(chatNick)-1] = '\0';
}
if(send(sockfd, chatNick, NICKSIZE, 0) == -1){
fprintf(stderr, "Error client: send CHAT NICK\n");
}
printf("Type your message...\n");
char *chat_msg = (char *) malloc(MAXMSG);
fgets(chat_msg,MAXMSG,stdin) ;
if((strlen(chat_msg)>0) && (chat_msg[strlen(chat_msg)-1] == '\n') ){
chat_msg[strlen(chat_msg)-1] = '\0';
}
if(send(sockfd, chat_msg, MAXMSG, 0) == -1){
fprintf(stderr, "Error client: send CHAT\n");
}
free(chatNick);
free(chat_msg);
}else{
char *buf = (char*) malloc(MAXDATASIZE); int numbytes;
if ((numbytes = recv(sockfd, buf, MAXDATASIZE, 0)) == -1) {
fprintf(stderr, "Error client: recv\n");
exit(1);
}
buf[numbytes] = '\0'; printf("-> %s\n", buf);
free(buf);
}
if(strcmp(comm, "quit_") != 0){
free(comm); comm = (char*)malloc(MAXDATASIZE);
printf("\nWhats next?... "); scanf("%s",comm);
}else{
close(sockfd);
exitvar = 1;
}
}
return 0;
}
server.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <time.h>
#include "socketlib.h"
#include <semaphore.h>
#define SERVER_PORT "50000"
#define BACKLOG 10
#define MAXDATASIZE 256
#define NICKSIZE 25
#define MAXCLIENT 10
#define MAXTIMESIZE 30
#define MAXMSG 1024
// ESTRUCTURA QUE MANEJARA LA LISTA DE CLIENTES
typedef struct{
char nick[NICKSIZE]; // NICK
char ip[NI_MAXHOST]; // IP
char port[NI_MAXSERV]; // PORT
char connTime[MAXTIMESIZE]; // TIMESTAMP
int connected; // STATE
pid_t pidConn; // PROCESS PID
char *msg; // MSG BUFFER
}connData;
// NOT ZOMBIE PROCESSES
void sigchld_handler(int s) {
while (waitpid(-1, NULL, WNOHANG) > 0);
}
connData *client;
int *id;
int main (int argc, char **argv) {
// THE ARRAY OF CLIENTS IS SHARED BETWEEN THE PROCESSES
int smid = shm_open("shm1", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
ftruncate(smid, sizeof(connData)*MAXCLIENT);
// JUST FOR MAXCLIENT 10 CLIENTS AT THE MOMMENT
client = mmap(NULL, sizeof(connData)*MAXCLIENT, PROT_READ | PROT_WRITE, MAP_SHARED, smid, 0);
sem_t *sem; sem = sem_open("sem1", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR, 1);
// THE ARRAY INDEX IS ALSO SHARED
int smid2 = shm_open("shm2", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
ftruncate(smid2, sizeof(int));
id = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, smid2, 0);
sem_t *sem2; sem2 = sem_open("sem2", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR, 1);
sem_wait(sem2);
*id = 0;
sem_post(sem2);
// CONN CONFIG
struct sigaction sa;
sa.sa_handler = sigchld_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
fprintf(stderr, "Error server: sigaction\n");
exit(1);
}
int sockfd; // LISTENER
if ((sockfd = get_tcp_listen(SERVER_PORT, BACKLOG)) == -1) {
fprintf(stderr, "Error get_tcp_listen\n");
exit(1);
}
printf("server: waiting for connections...\n");
char ip_num[NI_MAXHOST];
char port_num[NI_MAXSERV];
get_socket_addr(sockfd, ip_num, port_num);
//////////////////////////////////////////////////////////////////
while (1) {
// BLOCKS UNTIL SOMEONE REQUEST CONN
int new_fd;
if ((new_fd = accept(sockfd, NULL, NULL)) == -1) {
fprintf(stderr, "Error server: accept\n");
continue;}
////////////////////////////////////////////////////////
// IP:PORT OF JUST CONNECTED USER
get_socket_addr(new_fd, ip_num, port_num);
get_peer_addr(new_fd, ip_num, port_num);
printf("server: got connection from: %s, %s\n", ip_num, port_num);
////////////////////////////////////////////////////////
// TIMESTAMP OF USER CONN
time_t ltime; ltime = time(NULL);
char timeStamp[MAXTIMESIZE]; strcpy(timeStamp,ctime(<ime));
////////////////////////////////////////////////////////////////////////
// WELLCOME MESSAGE SENT TO THE CLIENT
char *well = (char*) malloc(MAXDATASIZE);
if (send(new_fd, "Wellcome to the Chat Service!!\n", MAXDATASIZE-1, 0) == -1) {
fprintf(stderr, "Error sending WELLCOME\n");
} free(well);
///////////////////////////////////////////////////////////////
// SAVES IN THE ARRAY OF CLIENTS, THE DATA OF THE CLIENT THAT JUST CONNECTED
int idTmp1;
sem_wait(sem2);
idTmp1 = *id;
sem_post(sem2);
if(sem_wait(sem) == 0){
strcpy(client[idTmp1].ip, ip_num); // IP
strcpy(client[idTmp1].port, port_num); // PORT
strcpy(client[idTmp1].connTime, timeStamp); // TIMESTAMP
client[idTmp1].connected = 1;
}else{
fprintf(stderr, "Error SEM_WAIT\n");
}
sem_post(sem);
sem_wait(sem2); (*id)++; sem_post(sem2);
//////////////////////////////////////////////////////////////
// FORKS A PROCESS TO DEAL WITH THE JUST CONNECTED USER
if (fork() == 0) {
close(sockfd); // CLOSES THE FATHERS SOCKET
int numbytes = 0;
// SAVES THE NICK IN THE ARRAY
char userNick[NICKSIZE];
if(( numbytes = recv(new_fd, userNick, NICKSIZE, 0)) == -1){
fprintf(stderr,"Error rcv\n");
} userNick[numbytes-1] = '\0';
int idTmp2;
sem_wait(sem2);
pid_t pidAct = getpid(); // PID OF THE NEW CREATED FORK
idTmp2 = *id; // ID OF THE USER
idTmp2--;
strcpy(client[idTmp2].nick,userNick);
client[idTmp2].pidConn = pidAct;
idTmp2 = *id;
sem_post(sem2);
//////////////////////////////////////////////////////////////
// SENDS THE LIST OF CONNECTED CLIENTES
if (send(new_fd, id, sizeof(int), 0) == -1) {
fprintf(stderr, "Error send ID\n");
}
if (send(new_fd, client, sizeof(connData)*MAXCLIENT, 0) == -1) { // SEND THE WHOLE LIST
fprintf(stderr, "Error send LIST\n");
}
//////////////////////////////////////////////////////////////
// THE FORK WAITS SOME COMMAND OF THE USER
char *comm = (char*)malloc(MAXDATASIZE);
if( (numbytes = recv(new_fd, comm, MAXDATASIZE-1, 0)) == -1){
fprintf(stderr,"Error rcv COMMAND\n");
}
comm[numbytes] = '\0';
// THE FORK ENTERS IN A LOOP WAITING COMMANDS
int wait = 0;
while(wait == 0){
if(strcmp(comm,"clientlist") == 0){
if (send(new_fd, client, sizeof(connData)*MAXCLIENT, 0) == -1) {
fprintf(stderr, "Error send CLIENT LIST\n");
}
}else if(strcmp(comm,"sendchat") == 0){
char *chatNick = (char *) malloc(NICKSIZE); // WAIT FOR THE CLIENT TO TALK TO
if( (numbytes = recv(new_fd,chatNick, NICKSIZE, 0)) == -1){
fprintf(stderr,"Error server rcv CHAT NICK\n");
} chatNick[numbytes-1] = '\0';
char *chatmsg = (char *)malloc(MAXMSG); // WAIT FOR MSG
if((numbytes = recv(new_fd, chatmsg, MAXMSG, 0)) == -1){
fprintf(stderr,"Error server rcv CHAT\n");
} chatmsg[numbytes-1] = '\0';
int client_id;
sem_wait(sem2);
for(client_id = 0; client_id < *id; client_id++){
if(strcmp(client[client_id].nick, chatNick) == 0){
if(client[client_id].msg != NULL){
free(client[client_id].msg);
}
client[client_id].msg = (char * )malloc(MAXMSG); // COPY THE MESSAGE TO THE DESIRED USER
strcpy(client[client_id].msg, chatmsg);
printf("\nTHE MESSAGE TO: %s IS %s\n", client[client_id].nick, client[client_id].msg);
}
}
sem_post(sem2);
/*
HERE I HAVE THE NICK, SAY, 'client1' OF THE CLIENT TO WHICH I WANT TO TALK.
THE MSG NOW ITS IN HIS MSG BUFFER LIKE ABOVE.
HOW CAN I NOTICE THE FORKED PROCESS HANDLING THE CONNECTION of 'client1'
TO READ THE MESSAGE ?
*/
free(chatmsg);
free(chatNick);
}else if(strcmp(comm,"quit_") == 0){
if (send(new_fd, "Byee!!", MAXDATASIZE-1, 0) == -1) {
fprintf(stderr, "Error send EXIT\n");
}
wait = 1; // FOR EXIT AND CLOSE THE SOCKET
}else{
if (send(new_fd, "Invalid option!", MAXDATASIZE-1, 0) == -1) {
fprintf(stderr, "Error send INVALID\n");
}
}
if(wait == 0){
// WHEN THE FORKED PROCESS HAS FULFILL THE USERS REQUEST, IT JUST WAITS FOR OTHER REQUEST
free(comm); comm = (char*)malloc(MAXDATASIZE);
if((numbytes = recv(new_fd, comm, MAXDATASIZE-1, 0)) == -1){
fprintf(stderr,"Error rcv REQUEST\n");
} comm[numbytes] = '\0';
}
}
if(munmap(client,sizeof(connData)*MAXCLIENT) != 0){ printf("ERROR FREEING MEM\n");}
sem_unlink("sem1"); shm_unlink("shm1");
printf("Connection ended with %d \n", new_fd);
close(new_fd); exit(0);
}
printf("Keep waiting connections.....\n");
close(new_fd); // SOCKET DEL ACCEPT, DEL CLIENTE QUE SE HABIA CONECTADO
//////////////////////////////////////////////////////////////////////////////
}
if(munmap(client,sizeof(connData)*MAXCLIENT) != 0){ printf("ERROR FREEING MEM\n");}
sem_unlink("sem1");
shm_unlink("shm1");
return 0;
}
I'll start by noting that fork() and shared memory are not the best or easiest approach to creating a chat server; if you have the option, I'd recommend doing it a different way (e.g. via multiple threads in a single process, or even a single thread and select(), instead).
Assuming that you are required to use this approach (e.g. because it's stipulated in a class assignment, or something), however... what you're missing is an IPC notification mechanism, i.e. (as you say) a way for process C2 to notice that process C1 has some data for C2 to handle.
There are a couple of ways to go about implementing notification... the quick-and-dirty way (which might be good enough for getting a class assignment done) is simply to have each process poll the shared memory area; e.g. have each process check its portion of the shared memory area every 100 milliseconds and see if anything has changed since last time. In a scenario like that, C1 might write some new data to the shared memory area, and then increment an integer value in the shared memory area when it's done writing. The next time C2 wakes up to check the integer, it can notice that the integer's value is different from what it was on the previous check, and take that as its cue that there is fresh data in the shared memory area for it to handle. (side note: when using shared memory you should be serializing access to the shared memory regions somehow, otherwise you risk encountering race conditions where e.g. C2 starts reading memory at the same time C1 is still writing it. The symptom of that would be a system that works correctly 99.999% of the time but occasionally does something weird/wrong when the timing is "just right")
If you want a less hackish method of notification, however (i.e. one that doesn't eat CPU cycles 24/7 and doesn't cause an unnecessary 100mS of latency on every trip through the server), then you'll need to choose a notification mechanism. One mechanism would be to use the (arguably misnamed) kill() system call to send a UNIX signal to C2's process; C2 will then need to have a signal handler installed that causes it to do the right thing when it receives a signal of that type.
If you want to avoid Unix signals, however (and I try to avoid them because they are rather antiquated and ugly), you'll want a gentler mechanism by which the C2 process can be awoken when either (an IPC notification is received) or (I/O data is received), whichever condition happens first... a naive blocking-I/O-call mechanism is insufficient since it only allows your process to wait for one thing or the other, but not both. A good way to get both is to use select() or poll() to monitor two sockets simultaneously: one socket is the TCP connection to the client, and the other socket is a UDP socket that the process has set up specifically to receive IPC notifications. Each forked process sets up a UDP socket listening on a particular port, and when C1 wants to wake up C2, C1 does so by send()-ing a UDP packet to C2's UDP port. (The contents of the UDP packet don't matter, since its only purpose is to cause C2 to return from select() and, since the UDP socket has selected as ready-for-read, C2 then knows to read the packet from the UDP socket, throw the packet away, and then checked the shared memory region for fresh data.
(Of course, once you've done all that, you might find it easier for C1 to simply include C2's data in the UDP packet itself so C2 doesn't have to muck about with the potentially-racy shared memory region, but that's up to you)
You are almost finish #Emiliano, that's the point I also got stuck once ;).
Well, you have some options to tell to other process about message.
1. You always look for your own message buffer (this is bad, consume much CPU and also a bad idea)
Process C1 looks always in shared memory for C1, its own, buffer and check if there is new message, and send to client.
2. You use signal ( better than 1)
a. Client C2 send a message for C1.
b. Process C2 store message in C1 buffer on shared memory.(If i correctly understand your shared memory structure)
c. Process C2 send a signal to C1 to notify that I have placed a message for you in your buffer.(In this case, you need to know which pid handles which client)
d. Upon getting signal from a process, C1 check its buffer and send to its client.
EDIT:
It seems you are having trouble in signal.
Here is a simple snippet which show signal sending/catching.
recvsig.c
static void handler(int sig, siginfo_t *si, void *data)
{
printf("%s = %d\n", "Got a signal, signal number is ", sig);
//you can also code here what you want, after getting a signal
}
void init_signal()
{
struct sigaction act;
act.sa_sigaction = handler;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_SIGINFO;
sigaction(SIGRTMIN + 1, &act, NULL);
}
void main(int argc, char **argv)
{
printf("%s %d\n", "PID", getpid());
init_signal();
while(1)
{
pause();
{
printf("%s\n", "Received a signal");
//code here anything after you got signal
}
}
return;
}
sendsig.c
void main(int argc, char **argv)
{
int pid = atoi(argv[1]);
while(1)
{
sleep(5);
{
kill(pid, SIGRTMIN+1);
printf("%s %d\n", "Sent a signal to ", pid);
}
}
return;
}
In your program , call init_signal() after each forked - in child process.
Be sure you manage pid list of all forked process + connected clients.
And use kill() to signal the correct pid.
i have this code but every time i try to run it it deletes the source file without giving any output, so how can i fix my problem?
note the question is asking me this:
Write a program that takes two file names from the command line, and copies the reverse of the contents of the first file into the second file, assuming that it is able to open the first file for reading and the second one for writing. If it can’t open the first file for reading, it must neither create nor modify (as the case may be) the second file. This program must use the low-level functions
#include<stdlib.h>
#include<stdio.h>
#include<fcntl.h>
#include<string.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<unistd.h>
int main(int argc, char *argv[])
{
int source, dest, n;
char buf;
int filesize;
int i;
if (argc != 3)
{
fprintf(stderr, "usage %s <source> <dest>\n", argv[0]);
exit(-1);
}
at this par i am trying to use the following format: open("outf", O_WRONLY | O_CREAT | O_TRUNC, 0666)
if ((source = open(argv[1],O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0)
{ //read permission for user on source
fprintf(stderr, "can't open source\n");
exit(-1);
}
if ((dest = creat(argv[2], 0666)) < 0)
{ //rwx permission for user on dest
fprintf(stderr, "can't create dest");
exit(-1);
}
filesize = lseek(source, (off_t) 0, SEEK_END); //filesize is lastby +offset
printf("Source file size is %d\n", filesize);
for (i = filesize - 1; i >= 0; i--)
{ //read byte by byte from end
lseek(source, (off_t) i, SEEK_SET);
n = read(source, &buf, 1);
if (n != 1)
{
fprintf(stderr, "can't read 1 byte\n");
exit(-1);
}
n = write(dest, &buf, 1);
if (n != 1)
{
fprintf(stderr, "can't write 1 byte\n");
exit(-1);
}
}
write(STDOUT_FILENO, "DONE\n", 5);
close(source);
close(dest);
return 0;
}
thanks
I am sorry to be rude but did you even read the options you are passing to the first open call? O_CREAT | O_TRUNC?
What do you think those options do? Those options are causing your source file to be deleted.
You need to open your input file with the mode O_RDONLY, i.e. ReaD ONLY not O_WRONLY, i.e. WRite ONLY.
Check this:
int checkstatus(ifstream &in)
{
ios::iostate i;
i = in.rdstate();
if(i & ios::eofbit)
return 0;//cout << "EOF encountered\n";
else if(i & ios::failbit)
return 0;//cout<<"Non-Fatal I/O error\n";
else if(i & ios::badbit)
return 0;//cout<<"Fatal I/O error\n";
return 1;
}
int main()
{
ifstream in;
ofstream o;
in.open("test.txt");
o.open("test1.txt",ios::out);
char c;
in.seekg(0,ios::end);
while(checkstatus(in) != 0)
{
in.seekg(-1,ios::cur);
in.get(c);
in.seekg(-1,ios::cur);
if(checkstatus(in) == 0)
break;
cout<<c;
o.put(c);
}
in.close();
o.close();
return 0;
}
i have made some changes here and it worked very decent but not with very large file!!
#include<stdlib.h>
#include<stdio.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<unistd.h>
int main(int argc, char *argv[])
{
int source, dest, n;
char buf;
int filesize;
int i;
if (argc != 3)
{
fprintf(stderr, "usage %s <source> <dest>\n", argv[0]);
exit(-1);
}
if ((source = open(argv[1], 0666)) < 0)
{ //read permission for user on source
fprintf(stderr, "can't open source\n");
exit(-1);
}
if ((dest = open(argv[2],O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0)
{ //rwx permission for user on dest
fprintf(stderr, "can't create dest");
exit(-1);
}
filesize = lseek(source, (off_t) 0, SEEK_END); //filesize is lastby +offset
printf("Source file size is %d\n", filesize);
for (i = filesize - 1; i >= 0; i--)
{ //read byte by byte from end
lseek(source, (off_t) i, SEEK_SET);
n = read(source, &buf, 1);
if (n != 1)
{
fprintf(stderr, "can't read 1 byte\n");
exit(-1);
}
n = write(dest, &buf, 1);
if (n != 1)
{
fprintf(stderr, "can't write 1 byte\n");
exit(-1);
}
}
write(STDOUT_FILENO, "DONE\n", 5);
close(source);
close(dest);
return 0;
}
do i need to do something with lseek()?