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;
}
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
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
EDIT: the problem is that scanf (and other function I tried here) doesn't wait for the input, the program doesn't pause.
Using Ubuntu 18 on Virtual Box on Mac
I am writing a server/client using POSIX. I am not able to read keyboard input in client.c
char action_type[1];
printf("Chose action: T to request time, S to shut down\n");
scanf(" %c",action_type);
printf("%s", action_type);
if I put the same code as the first thing in main.c it works fine.
full code for server / client and commons is:
server
#include <stdio.h>
#include "mqueue.h"
#include "commons.h"
#include "errno.h"
#include "stdlib.h"
#include <string.h>
#include <time.h>
int status_closing = 0;
void send_time(char* clients_pid);
void send_activation(char* clients_pid);
//VARIABLES related to SERVERS QUEUE
mqd_t server; // server
struct mq_attr servers_attributes; // server creation attributes
struct mq_attr receiving_attributes; // server receiving attributes
// set up attributes
void set_servers_attributes(){
// set up server's attributes
servers_attributes.mq_maxmsg = QUEUE_SIZE;
servers_attributes.mq_msgsize = MESSAGE_SIZE;
printf("attributes set \n");
};
// open server
void open_servers_queue() {
server = mq_open (servers_path,
O_CREAT | O_RDWR | O_EXCL ,
0666, &servers_attributes);
if (server == -1) {
printf("failed to open server's queue\n");
printf(errno);
exit(-1);
} else {
printf("opened servers queue as: %d\n",server);
}
};
// check attributes
void check_attributes(){
if ((mq_getattr(server,&receiving_attributes)) == -1) {
printf("cannot read server's queue\n exit \n");
exit(-1);
}
};
void close_and_unlink_queue(){
printf("At exit closing and unlinking queue\n");
mq_close(server);
mq_unlink(servers_path);
};
int check_for_messages_in_the_queue(){
//printf("checking for messages\n");
int messages_in_queue;
messages_in_queue = receiving_attributes.mq_curmsgs;
//printf("there are %d message in the servers queue\n",messages_in_queue);
// printf("message in the queue!\n");
return messages_in_queue;
};
char* receive_message(){
char *receiving_buffer = malloc(sizeof(char)*MESSAGE_SIZE);
if ((mq_receive(server,receiving_buffer,MESSAGE_SIZE,NULL))>0){
return receiving_buffer;
}
else {
printf("Server failed to receive message");
mq_close(server);
mq_unlink(servers_path);
exit(-1);
}
};
void respond(char *message_type, char* clients_pid) {
printf("responding\n");
char* type_one = "1";
char* type_two = "2";
char *type_three ="3";
if (strcmp(message_type, type_one) == 0) {
printf("TYPE 1\n");
send_activation(clients_pid);
}
if (strcmp(message_type, type_two) == 0) {
printf("TYPE 2\n");
send_time(clients_pid);
}
if (strcmp(message_type, type_three) == 0) {
printf("type 3 - SHUTDOWN INITIATED\n");
}
}
void send_time(char* clients_pid) {
time_t mytime = time(NULL);
char *time_str = ctime(&mytime);
time_str[strlen(time_str)-1] = '\0';
char *clientpath[20];
int clients_pid_int = atoi(clients_pid);
sprintf(clientpath,"/%d",clients_pid_int);
printf("clients path: %s\n",clientpath);
mqd_t client;
client = mq_open(clientpath,O_RDWR , 0666, &servers_attributes);
if (client == -1) {
printf("failes opening client's queue \n");
exit(-1);
} else {
printf("connected to client's queue: %d\n",client);
}
};
void send_activation(char* clients_pid) {
char *clientpath[20];
int clients_pid_int = atoi(clients_pid);
sprintf(clientpath,"/%d",clients_pid_int);
printf("clients path: %s\n",clientpath);
mqd_t client;
client = mq_open(clientpath,O_RDWR , 0666, &servers_attributes);
if (client == -1) {
printf("failes opening client's queue \n");
exit(-1);
} else {
printf("connected to client's queue: %d\n",client);
char* activation = malloc(sizeof(char)*MESSAGE_SIZE);
char* activation_literal = "activation";
sprintf(activation,"%s",activation_literal);
int message_sent = mq_send(client,activation,MESSAGE_SIZE,0);
printf("message sent with: %d",message_sent);
}
};
int main() {
// clean remainings of previous trials
mq_close(server);
mq_unlink(servers_path);
// define atexit behaviour
atexit(close_and_unlink_queue);
//set servers attributes:
set_servers_attributes();
// open server's queue
open_servers_queue();
// receiving messages in the loop
int condition = 1;
while (1) {
check_attributes();
if (check_for_messages_in_the_queue() > 0) {
char *received_message = receive_message();
char *tok_one = strtok(received_message," ");
char *tok_two = strtok(NULL, " ");
//int clients_pid = atoi(tok_two);
respond(tok_one,tok_two);
} else if ((check_for_messages_in_the_queue() ==0) && (status_closing == 1)) {
printf("Server's queue is empty - work finished. closing down\n");
exit(0);
}
}
printf("Hello, World!\n");
return 0;
}
client
#include <stdio.h>
#include <mqueue.h>
#include <unistd.h>
#include "commons.h"
#include <stdlib.h>
#include <errno.h>
#include <string.h>
mqd_t client;
mqd_t server;
char clientpath[20];
char* sending_buffer[MESSAGE_SIZE];
struct mq_attr clients_attributes;
struct mq_attr receiving_attributes;
void connect_to_server(){
server = mq_open(servers_path,O_WRONLY);
if(server == -1) {
printf("connection to server failed\n");
} else {
printf("connected to server with id: %d \n",server);
}
};
void set_clients_attributes(){
// deal with attributes
clients_attributes.mq_maxmsg = QUEUE_SIZE;
clients_attributes.mq_msgsize = MESSAGE_SIZE;
};
void create_clients_queue(){
// create clients path
pid_t client_pid = getpid();
sprintf(clientpath, "/%d", client_pid);
// open clients queue
client = mq_open(clientpath,O_RDONLY | O_CREAT | O_EXCL, 0666, &clients_attributes);
// printf(errno);
if (client == -1) {
printf("failes opening client's queue \n");
exit(-1);
} else {
printf("connected to client's queue: %d\n",client);
}
};
void register_at_server(){
message message;
message.mtype = 1;
int client_pid = getpid();
message.sender = client_pid;
char separator = ' ';
snprintf(sending_buffer,MESSAGE_SIZE,"%ld%c%d",message.mtype,separator,message.sender);
if ((mq_send(server,sending_buffer, MESSAGE_SIZE,0)) == -1) {
printf("failed to send registration request\n");
exit(-1);
}
else {
printf("%s",sending_buffer);
printf("sent registration request\n");
}
};
void close_and_unlink_queue(){
printf("At exit closing and unlinking queue\n");
mq_close(client);
mq_unlink(clientpath);
};
void check_attributes(){
if ((mq_getattr(client,&receiving_attributes)) == -1) {
printf("cannot read own's queue\n exit \n");
exit(-1);
}
};
int check_for_messages_in_the_queue(){
//printf("checking for messages\n");
int messages_in_queue;
messages_in_queue = receiving_attributes.mq_curmsgs;
//printf("there are %d message in the servers queue\n",messages_in_queue);
// printf("message in the queue!\n");
return messages_in_queue;
};
char* receive_message(){
char *receiving_buffer = malloc(sizeof(char)*MESSAGE_SIZE);
if ((mq_receive(client,receiving_buffer,MESSAGE_SIZE,NULL))>0){
return receiving_buffer;
}
else {
printf("Server failed to receive message");
mq_close(client);
mq_unlink(clientpath);
exit(-1);
}
};
void choose_action(){
char action_type[1];
printf("Chose action: T to request time, S to shut down\n");
scanf(" %c",action_type);
printf("%s", action_type);
};
int main() {
mq_close(client);
mq_unlink(clientpath);
connect_to_server();
set_clients_attributes();
create_clients_queue();
register_at_server();
int condition = 1;
int client_active = 0;
while (condition) {
check_attributes();
if (check_for_messages_in_the_queue() > 0) {
char *received_message = receive_message();
if ((strcmp(received_message, "activation")) == 0) {
client_active = 1;
condition = 0;
free(received_message);
}
}
}
char action_type[1];
printf("Chose action: T to request time, S to shut down\n");
scanf(" %c",action_type);
printf("%s", action_type);
printf("Hello, World!\n");
return 0;
}
commons
#ifndef SERVER_COMMONS_H
#define SERVER_COMMONS_H
#include <signal.h>
// define values of server queue attributes
//define message struct
typedef struct messgae {
char content[4096];
pid_t sender;
long mtype;
} message;
#define QUEUE_SIZE 10
#define MESSAGE_SIZE sizeof(message)
// define servers path
const char servers_path[] = "/server";
#endif //SERVER_COMMONS_H
``
this happens because the buffer is not empty and this function read from it.
to empty buffer just try this code:
while( getchar() != '\n');
it will empty the buffer and after it the functions will wait for input.
printf( "Enter a value :");
c = getchar( );
or
#include <stdio.h>
int main( ) {
char str[100];
int i;
printf( "Enter a value :");
scanf("%s %d", str, &i);
printf( "\nYou entered: %s %d ", str, i);
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.
//SERVER SIDE SCRIPT for Diffie-Hellman using sockets.
#include<stdio.h>
#include<netinet/in.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netdb.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#define MAX 80
#define PORT 43461
#define SA struct sockaddr
char* itoa(int value, char* str, int radix) {
static char dig[] =
"0123456789"
"abcdefghijklmnopqrstuvwxyz";
int n = 0, neg = 0;
unsigned int v;
char* p, *q;
char c;
if (radix == 10 && value < 0) {
value = -value;
neg = 1;
}
v = value;
do {
str[n++] = dig[v%radix];
v /= radix;
} while (v);
if (neg)
str[n++] = '-';
str[n] = '\0';
for (p = str, q = p + (n-1); p < q; ++p, --q)
c = *p, *p = *q, *q = c;
return str;
}
void func(int sockfd)
{
printf("hello"); //This statement is not being displayed and rest of the code not executed
char buff[MAX],uname[MAX],pass[MAX];
int n,clen,a1,a2,b2,val,key;
struct sockaddr_in cli;
clen=sizeof(cli);
xx:
//RECIEVING USERNAME
bzero(uname,MAX);
recvfrom(sockfd,uname,sizeof(buff),0,(SA *)&cli,&clen);
printf("Username received");
//RECEIVING PASSWORD
bzero(pass,MAX);
recvfrom(sockfd,pass,sizeof(buff),0,(SA *)&cli,&clen);
if(strcmp(uname,"admin") == 10 && strcmp(pass,"admin") == 10)
{
printf("Accepted");
//RECEIVING NUMBER FROM CLIENT
recvfrom(sockfd,buff,sizeof(buff),0,(SA *)&cli,&clen);
b2=atoi(buff);
printf("Received from client\n");
//GENERATING SERVER SIDE NUMBER
a1=(rand() % 19) + 1; // Random value selected by Server
a2=pow(7,a1);
a2=a2 % 11; // Server Generating value to be sent G:7 , P:11
//Sending the value-a2
bzero(uname,MAX);
itoa(a2,buff,10);
sendto(sockfd,buff,sizeof(buff),0,(SA *)&cli,clen);
printf("Server side number sent\n");
//GENERATING KEY AND THE DATA
key=pow(b2,a1);
key=key % 11; // G:7 , P:11
val=key*1024; // DATA: 7060
//Sending the data required
bzero(uname,MAX);
itoa(a1,buff,10);
sendto(sockfd,buff,sizeof(buff),0,(SA *)&cli,clen);
printf("Data sent \n");
}
else
{
printf("Incorrect Username-Password combination. Waiting for next try \n");
strcpy(buff,"wrong");
sendto(sockfd,buff,sizeof(buff),0,(SA *)&cli,clen);
goto xx;
}
}
int main()
{
int sockfd;
struct sockaddr_in servaddr;
sockfd=socket(AF_INET,SOCK_DGRAM,0);
if(sockfd==-1)
{
printf("socket creation failed...\n");
exit(0);
}
else
printf("Socket successfully created..\n");
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family=AF_INET;
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
servaddr.sin_port=htons(PORT);
if((bind(sockfd,(SA *)&servaddr,sizeof(servaddr)))!=0)
{
printf("socket bind failed...\n");
exit(0);
}
else
{
printf("%d",sockfd);// This value is displayed in the output screen
printf("Socket successfully binded..\n");}
func(sockfd);
close(sockfd);
}
When the script is executed, The binding is done successfully and the same message is displayed on the output screen. But the function call for func() is not executed.I do not get the first statement of the function call-'Hello' in the execution.Please suggest the changes required in this code.
If bind() was successful then the func() will be called. The reason why you are not seeing your output is because stdout is usually buffered and it will flush it once the internal buffer is full.
Add \n to your debug printf() calls which will force it to flush the output.
printf("hello\n");
Similarly, other debug printf's. You could also use fflush(stdout); to flush stdout.
Obviously, you need to client code as server is waiting for it in your code.