Multiple clients conflict - c

I have a problem with multiple clients sending a notification, every interval of time, with some kind of information to a server. The problem occurs when more than one client sends the notification at the same moment, only one will be sent.
Specifically, they both print "Sending nofication", but after that only one prints "Sent ...", the server receives only one aswell.
This is my client thread function
void* Notification_Handler (void* args) {
int nc = *((int*)args); // id of the client
struct sockaddr_un addr;
memset(&addr, '0', sizeof(addr));
addr.sun_family= AF_UNIX;
strncpy(addr.sun_path, SOCKNAME_MANAGER, strlen(SOCKNAME_MANAGER)+1);
int fd_socket;
SYSCALL(fd_socket, socket(AF_UNIX, SOCK_STREAM, 0), "socket");
int notused;
SYSCALL(notused, connect(fd_socket, (struct sockaddr*)&addr, sizeof(addr)), "connect");
int res;
struct timespec *ts_notification = (struct timespec *)malloc(sizeof(struct timespec));
ts_notification->tv_sec = (4000)/1000;
ts_notification->tv_nsec = ((4000)%1000)*1000000;
while (c_status[nc-1]==1) { // while this client is open (1: open, 0:closed)
do {
res = nanosleep(ts_notification, ts_notification); // notification every interval
} while (res && errno==EINTR);
if (c_status[nc-1]==0) break;
sendToManager(nc, fd_socket);
}
free(ts_notification);
close(fd_socket);
pthread_exit((void*)EXIT_SUCCESS);
}
and this is the SendToManager function for sending the data
void sendToManager (int nc, int fd_socket) {
printf("Handler[%d]: sending notification\n", nc);
char message[64];
snprintf(message, sizeof(message), "Cashier:%d", nc);
int len= strlen(message);
int n;
if ((n=write_h(fd_socket, &len, sizeof(int)))==-1) {
fprintf(stderr, "write len failed\n");
pthread_exit((void*)EXIT_FAILURE);
}
if ((n=write_h(fd_socket, message, len))==-1) {
fprintf(stderr, "write info failed\n");
pthread_exit((void*)EXIT_FAILURE);
}
printf("Sent: %s\n", message);
}
SYSCALL and write_h are just some macro/function from an header file
#define SYSCALL(r, sc, str) \
if ((r=sc) == -1) { \
perror(str); \
exit(errno); \
}
static inline int write_h (long fd, void* buffer, size_t size) {
int res;
size_t left = size;
char *bufptr = (char*)buffer;
while(left>0) {
if ((res=write((int)fd ,bufptr,left))==-1) {
if (errno == EINTR) continue;
return -1;
}
if (res==0) return 0;
left -= res;
bufptr += res;
}
return 1;
}
The server spawns a thread for every connect request he receives. Is my function not thread-safe or some info/variables are shared?

Related

Socket send from server failing, error: Socket operation on non-socket

I have below functions written for a server side socket implementation -
void SetUpServerSocket()
{
/* Setting up Server socket*/
struct sockaddr_in srv_addr;
int yes=1;
/* Open datagram socket */
if((bind_my_socket = socket(AF_INET,SOCK_STREAM,0)) < 0)
{
print_log("Bind socket failed");
return ;
}
bzero((char*) &srv_addr,sizeof(srv_addr));
srv_addr.sin_family = AF_INET;
srv_addr.sin_addr.s_addr = inet_addr(my_ip);
srv_addr.sin_port = htons(my_port);
if(setsockopt(bind_my_socket,SOL_SOCKET,SO_REUSEPORT,&yes,sizeof(yes))!=0)
{
print_log("Can't set socket options'SO_REUSEPORT'");
return;
}
if(bind(bind_my_socket,(struct sockaddr*) &srv_addr,sizeof(srv_addr)) < 0)
{
print_log("Bind failed");
return ;
}
if (listen (bind_my_socket,1024) < 0)
{
print_log("Cannot listen on socket\n");
return;
}
}
void* AcceptMsgConnFromClient()
{
/*This will accept connection from client*/
struct sockaddr_in client_addr;
int client_addr_len, r;
my_socket=0;
client_addr_len=sizeof(client_addr);
r=accept(bind_my_socket,(struct sockaddr *)&client_addr,&client_addr_len);
my_socket=r;
return NULL;
}
void* ReceiveClientMsg()
{
/* This will accept messages from client */
u_char buf[2000];
struct sockaddr_in client_addr;
int client_addr_len;
int len;
pthread_t thread;
int connfd;
u_char* pCmd[100];
AcceptMsgConnFromClient();
//Working here
/*if(my_socket>0){
if(send(my_socket, "Server Hello", strlen("Server Hello"), 0) < 0)
{
print_log("Send data failed\n");
print_log(strerror(errno));
print_log("\n");
}
}*/
memset(buf,0,2000);
for(;;)
{
len=recvfrom(my_socket,buf,2000,0,(struct sockaddr *)&client_addr,&client_addr_len);
if(len<=0)
{
AcceptMsgConnFromClient();
continue;
}
//my logic to handle buffer
} // ;; for
usleep(1000);
close(bind_my_socket);
return NULL;
}
void SendMsgtoClient()
{
if(send(my_socket, "Server Hello to Client", strlen("Server Hello to Client"), 0) < 0)
{
print_log("Send data to client failed\n");
print_log(strerror(errno));
print_log("\n");
return;
}
}
From main(in different file) I've called 'SetUpServerSocket()' once and 'ReceiveClientMsg()' in a thread(required to keep processing the buffer).
From a different function I'm calling 'SendMsgtoClient()' whenever I want to send something to Client. However, this fails with error as 'Socket operation on non-socket'.
But when I send something on same my_socket from ReceiveClientMsg thread, it works, and not when I do it from another function. I tried and printed value of my_socket in SendMsgtoClient(), it has an integer which is same as what is being assigned from AcceptMsgConnFromClient().
I have declared the socket variables used as-
static int bind_my_socket = 0, my_socket = 0;
Any help would be appreciated, thank you!
You're not printing the correct error message. The first call to print_log() is likely to change errno, so you're printing that error message, not the error from send(). Save errno in another variable.
void SendMsgtoClient()
{
if(send(my_socket, "Server Hello to Client", strlen("Server Hello to Client"), 0) < 0)
{
int saved_errno = errno;
print_log("Send data to client failed\n");
print_log(strerror(saved_errno));
print_log("\n");
return;
}
}

Create a client server calculator program in C using UDP socket programming

I would like to add the functionality of evaluating arithmetic expressions for my simple client server application but do not know how. A client should be asked to input an arithmetic expression and the server should return an evaluation of that expression. The expression should separated into operation(+,-,/,*) and two non negative integer arguments. Server: This must implement an “Arithmetic Service” consisting of a dispatcher and the four operations
add, subtract, multiply and divide which should have identical prototypes:
Status op( int , int , int *); // the last argument is for the result
CLIENT CODE
#include "connection.h"
int clientSocket, z;
SocketAddress serverAddr, clientAddr, rSA;
socklen_t addr_size;
char _message[SIZE], reply[SIZE];
void main(int argc, char **argv)
{
int aPort = IPPORT_RESERVED + getuid();
int rPort = IPPORT_RESERVED + getuid() + 1;
if (argc <= 1)
{
printf("\nUsage: client server_name ??\n example client 127.0.0.1\n");
printf("Use q to close the session.\n");
exit(BAD);
}
z = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
makeReceiverSA(&rSA, rPort);
clientSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (clientSocket < 0)
{
perror("Socket creation failed!");
exit(BAD);
}
else
{
makeLocalSA(&clientAddr);
}
bind(z, (struct sockaddr *)&rSA, sizeof(SocketAddress));
if (bind(clientSocket, (struct sockaddr *)&clientAddr, sizeof(SocketAddress)) != 0)
{
perror("Socket binding failed!");
close(clientSocket);
exit(BAD);
}
printSA(clientAddr);
makeDestSA(&serverAddr, argv[1], aPort);
makeReceiverSA(&rSA, rPort);
printSA(serverAddr);
while (strlen(_message) != 1 && _message[0] != 'q')
{
printf("\nEnter message to send: ");
fgets(_message, SIZE, stdin);
Message m, r;
memcpy(m.data, _message, strlen(_message));
m.length = strlen(_message);
r.length = SIZE;
if (DoOperation(&m, &r, clientSocket, serverAddr) == OK)
{
memcpy(r.data, reply, strlen(reply));
printf("\nResponse: %s\n", r.data);
}
}
}
Status DoOperation(Message *message, Message *reply, int s, SocketAddress serverSA)
{
Status ret;
if (message->length > SIZE)
{
printf("\nError: \n\tCode: %d\n\tMessage: BAD Message Length\n", WRONGLENGTH);
return WRONGLENGTH;
}
ret = UDPsend(s, message, serverSA);
if (ret == BAD)
return BAD;
ret = UDPreceive(z, reply, &rSA);
if (ret == BAD)
return BAD;
return OK;
}
Status UDPsend(int s, Message *m, SocketAddress dest)
{
ssize_t n;
n = sendto(s, m->data, m->length, 0, (struct sockaddr *)&dest, sizeof(SocketAddress));
if (n < 0)
{
printf("\nError: \n\tCode: %d\n\tMessage: Unrecoverable error\n", BAD);
return BAD;
}
if (n != m->length)
return OK;
}
Status UDPreceive(int s, Message *m, SocketAddress *origin)
{
ssize_t n;
socklen_t a = sizeof(SocketAddress);
n = recvfrom(s, reply, SIZE, 0, (struct sockaddr *)&origin, &a);
if (n < 0)
{
printf("\nError: \n\tCode: %d\n\tMessage: Unrecoverable error\n", BAD);
return BAD;
}
if (strlen(reply) > SIZE)
{
printf("\nError: \n\tCode: %d\n\tMessage: BAD Message Length\n", WRONGLENGTH);
return WRONGLENGTH;
}
return OK;
}
HEADER FILE
#include <stdio.h> /* standard C i/o facilities */
#include <unistd.h> /* Unix System Calls */
#include <sys/types.h> /* system data type definitions */
// #include <sys/wait.h> /* System Socket wait definitions */
#include <sys/socket.h> /* socket specific definitions */
#include <netinet/in.h> /* INET constants and stuff */
#include <arpa/inet.h> /* IP address conversion stuff */
#include <string.h>
#include <stdlib.h> /* needed for atoi() */
#include <netdb.h>
struct hostent *gethostbyname() ;
#ifndef SIZE
#define SIZE 1000
#endif
typedef enum {
OK, // operation successful
BAD, // unrecoverable error
WRONGLENGTH // BAD message length supplied
} Status;
typedef struct sockaddr_in SocketAddress;
typedef struct
{
unsigned int length;
unsigned char data[SIZE];
} Message;
extern void printSA(SocketAddress sa) ;
extern void makeDestSA(SocketAddress * sa, char *hostname, int port) ;
extern void makeLocalSA(SocketAddress *sa) ;
extern void receiver(int port) ;
extern void sender(char *message1, char *machine, int port);
extern Status DoOperation(Message *message, Message *reply, int s, SocketAddress serverSA);
extern Status GetRequest(Message *callMessage, int s, SocketAddress *clientSA);
extern Status SendReply(Message *replyMessage, int s, SocketAddress clientSA);
/*
* To return BAD if sendto/recvfrom return negatives
*/
extern Status UDPsend(int s, Message *m, SocketAddress dest);
extern Status UDPreceive(int s, Message *m, SocketAddress *origin);
/*print a socket address */
void printSA(SocketAddress sa)
{
printf("sa = %d, %s, %d\n",
sa.sin_family, inet_ntoa(sa.sin_addr), ntohs(sa.sin_port));
}
/* make a socket address for a destination whose machine and port
are given as arguments */
void makeDestSA(SocketAddress * sa, char *hostname, int port)
{
struct hostent *host;
sa->sin_family = AF_INET;
if((host = gethostbyname(hostname))== NULL) {
printf("Unknown host name\n");
exit(-1);
}
sa->sin_addr = *(struct in_addr *) (host->h_addr);
sa->sin_port = htons(port);
}
/* make a socket address using any of the addressses of this computer
for a local socket on any port */
void makeLocalSA(SocketAddress *sa)
{
sa->sin_family = AF_INET;
sa->sin_port = htons(0);
sa->sin_addr.s_addr = htonl(INADDR_ANY);
}
/* make a socket address using any of the addressses of this computer
for a local socket on given port */
void makeReceiverSA(SocketAddress *sa, int port)
{
sa->sin_family = AF_INET;
sa->sin_port = htons(port);
sa->sin_addr.s_addr = htonl(INADDR_ANY);
}
/*receive two messages via s new socket,
print out the messages received and close the socket
bind to any of the addresses of this computer
using port given as argument */
void receiver(int port)
{
char message1[SIZE], message2[SIZE];
SocketAddress mySocketAddress, aSocketAddress;
int s, n;
socklen_t aLength;
int i;
if((s = socket(AF_INET, SOCK_DGRAM, 0))<0) {
perror("socket failed");
return;
}
makeReceiverSA(&mySocketAddress, port);
if( bind(s, (struct sockaddr *)&mySocketAddress, sizeof(SocketAddress))!= 0){
perror("Bind failed\n");
close(s);
return;
}
printSA(mySocketAddress);
aLength = sizeof(aSocketAddress);
aSocketAddress.sin_family = AF_INET;
if((n = recvfrom(s, message1, SIZE, 0, (struct sockaddr *)&aSocketAddress, &aLength))<0)
perror("Receive 1") ;
else{
printSA(aSocketAddress);
for(i=0; i<n; i++) printf("M:%d", message1[i]);
printf(" Received Message:(%s)length = %d \n",
message1,n);
}
if((n = recvfrom(s, message2, SIZE, 0, (struct sockaddr *)&aSocketAddress, &aLength))<0)
perror("Receive 2");
else {
printf("Received Message:(%s)length = %d \n",
message2,n);
}
close(s);
}
/*do send after receive ready, open socket
bind socket to local internet port
use any of the local computer's addresses
send two messages with given lengths to machine and port
close socket
*/
void sender(char *message1,char *machine, int port)
{
int s, n;
char message[SIZE];
SocketAddress mySocketAddress, yourSocketAddress;
if(( s = socket(AF_INET, SOCK_DGRAM, 0))<0) {
perror("socket failed");
return;
}
/*
if((x = setsockopt(s, SOL_SOCKET, SO_BROADCAST, &arg, sizeof(arg))<0)
perror("setsockopt SO_BROADCAST---");
exit(-1);
*/
makeLocalSA(&mySocketAddress);
if( bind(s, (struct sockaddr *)&mySocketAddress, sizeof(SocketAddress))!= 0){
perror("Bind failed\n");
close (s);
return;
}
printSA(mySocketAddress);
makeDestSA(&yourSocketAddress,machine, port);
printSA(yourSocketAddress);
strcpy(message,message1);
if( (n = sendto(s, message, strlen(message), 0, (struct sockaddr *)&yourSocketAddress,
sizeof(SocketAddress))) < 0)
perror("Send failed\n");
if(n != strlen(message)) printf("sent %d\n",n);
close(s);
}
#include <sys/time.h>
/* use select to test whether there is any input on descriptor s*/
int anyThingThere(int s)
{
unsigned long read_mask;
struct timeval timeout;
int n;
timeout.tv_sec = 1; /*seconds wait*/
timeout.tv_usec = 0; /* micro seconds*/
read_mask = (1<<s);
if((n = select(32, (fd_set *)&read_mask, 0, 0, &timeout))<0)
perror("Select fail:\n");
// else printf("n = %d\n", n);
return n;
}
SERVER CODE
#include "connection.h"
int serverSocket;
SocketAddress serverAddr, clientAddr;
socklen_t addr_size, n;
int i;
char _message[SIZE];
int main(int argc, char **argv)
{
int aPort = IPPORT_RESERVED + getuid();
serverSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (serverSocket < 0)
{
perror("Socket creation failed!\n");
exit(BAD);
}
else
{
makeReceiverSA(&serverAddr, aPort);
}
if (bind(serverSocket, (struct sockaddr *)&serverAddr, sizeof(SocketAddress)) != 0)
{
perror("Socket binding failed!\n");
close(serverSocket);
exit(BAD);
}
printSA(serverAddr);
addr_size = sizeof(clientAddr);
makeDestSA(&clientAddr, "127.0.0.1", aPort+1);
// clientAddr.sin_family = AF_INET;
while (strlen(_message) != 1 && _message[0] != 'q')
{
Message m, r;
char* art = "Message received!";
memcpy(r.data, art, strlen(art));
r.length = strlen(art);
if (anyThingThere(serverSocket) > 0)
if (GetRequest(&m, serverSocket, &clientAddr) == OK)
{
memcpy(_message, m.data, m.length);
printf("\nReceived Message: %s\n", m.data);
Status ret = SendReply(&r, serverSocket, clientAddr);
}
}
}
Status SendReply(Message *replyMessage, int s, SocketAddress clientSA)
{
printSA(clientSA);
Status ret;
ret = UDPsend(s, replyMessage, clientSA);
return OK;
}
Status GetRequest(Message *callMessage, int s, SocketAddress *clientSA)
{
Status ret = UDPreceive(s, callMessage, clientSA);
if (ret == BAD)
return BAD;
if (strlen(_message) > SIZE)
{
printf("\nError: \n\tCode: %d\n\tMessage: BAD Message Length\n", WRONGLENGTH);
return WRONGLENGTH;
}
else
return OK;
}
Status UDPsend(int s, Message *m, SocketAddress dest)
{
ssize_t n;
n = sendto(s, m->data, m->length, 0, (struct sockaddr *)&dest, sizeof(SocketAddress));
if (n < 0)
{
perror("Send Error:");
printf("\nError: \n\tCode: %d\n\tMessage: Unrecoverable error\n", BAD);
return BAD;
}
if (n != m->length)
return OK;
}
Status UDPreceive(int s, Message *m, SocketAddress *origin)
{
ssize_t n;
socklen_t a = sizeof(SocketAddress);
n = recvfrom(s, _message, SIZE, 0, (struct sockaddr *)&origin, &a);
// printf("%ld\n", n);
// printf("%s\n", _message);
// memcpy(&m->data, _message, strlen(_message));
// printf("%s\n", m->data);
// m->length = strlen(_message);
if (n < 0)
{
printf("\nError: \n\tCode: %d\n\tMessage: Unrecoverable error\n", BAD);
return BAD;
}
if (strlen(_message) > SIZE)
{
printf("\nError: \n\tCode: %d\n\tMessage: BAD Message Length\n", WRONGLENGTH);
return WRONGLENGTH;
}
return OK;
}

Server doesn't alloc a thread for every new client (sockets)

I made a small program server client using sockets. I'll will explain what it needs to do and then the bug.
Application has a server witch wait's for clients. It supports max 6 clients at the same time. For each client server launch a thread in DETASH_STATE and then it come back and listen.
A client will submit the context of a file to the server. (i chose to send line by line)
The server will receive the content sent by a client and save it into a file, with a unique name like: __ft_"Any random string".txt
I hope all is clear till now.
The bug:
Well if i launch the client let say 20 times. On server side i don't have 20 files. Sometimes i have 10, sometimes 12,5,7(unpredictable). It writes in a single file the content sent by 3 or 4 or 5 clients ( here i need to have 3-4-5 files). I don't get where is the bug or what i made wrong. If you need additional information please tell me.
This is the server code (a part of it):
/**********ASSING A PROTOCOL TO A SOCKET (BIND)************/
if(bind(sock_dest, (struct sockaddr *)&server,sizeof (server))<0)
{
printf("Bind failed\n");
return 1;
}
/**********************************************************/
/*************** LISTEN FOR CONNECTIONS ********************/
listen(sock_dest,6);
printf("Waiting for connections\n");
/**********************************************************/
/****ACCEPT CONNECTION AND MAKE ATHREAD FOR EVERY CLIENT***/
c = sizeof ( struct sockaddr_in);
pthread_t thread_id;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
while( ( client_socket = accept( sock_dest, ( struct sockaddr *)&client, (socklen_t *) &c)) )
{
printf("Connection accepted.\n");
if(client_socket < 0)
{
printf("Accepting connection failed.\n");
return 1;
}
if(pthread_create( &thread_id, &attr, connection_handler, (void*) &client_socket ) < 0)
{
printf("Couldn't create a thread for the new client.\n");
return 1;
}
else
printf("Handler assigned\n");
}
return 0;
}
void *connection_handler (void *socket_dest)
{
char *dest_file_name;
char buffer[300];
int sock = *( int *) socket_dest;
char *exit_signal="EXIT";
if((dest_file_name=create_random_name())==NULL)
{
printf("Generating a random name failed\n");
return NULL;
}
int i=0;
while(1)
{
while(i<299)
{
recv(sock,buffer+i,1,0);
if(buffer[i]=='\n')
{
i=0; // setting i to 0 because next time when we read a path(string) it need to be stored from 0 pozition in array.
break;
}
++i;
}
if((strcmp(buffer,exit_signal))==0)
{
printf("Exit signal received.\n");
return NULL;
}
if((write_line_in_file(buffer,dest_file_name))==1)
{
printf("Failed to write one of the lines in %s\n",dest_file_name);
}
printf("Linie primita:%s\n",buffer);
bzero(buffer,256); // put all bytes to 0 from buffer
}
return 0;
}
char *create_random_name(void)
{
const char charset[] = "abcdefghijklmnopqrstuvwxyz";
char *file_name;
int i=0;
int key;
struct stat stbuf;
time_t t;
while(1)
{
srand((unsigned) time(&t));
if((file_name = malloc(16 * sizeof ( char )) ) == NULL)
{
printf("Failed to alloc memory space\n");
return NULL;
}
strcpy(file_name,"__ft_");
for(i=5 ; i<11 ; i++)
{
key = rand() % (int)(sizeof(charset)-1);
file_name[i]=charset[key];
}
strcat(file_name,".txt");
file_name[15] = '\0';
if(stat(file_name,&stbuf)==-1)
{
break;
}
}
return file_name;
}
/************* RETURN 0 IF SUCCES AND 1 IF FAILS ***********/
int write_line_in_file(char *line,char *file_name)
{
FILE *file;
if((file=fopen(file_name, "a")) == NULL)
{
printf("Can't open %s.\n");
return 1;
}
fprintf(file,"%s",line);
fclose(file);
return 0;
}
And this is the client code (i don't think here is the problem):
#include <stdio.h>
#include <stdlib.h>
#include<netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
int main(int argc, char *argv[])
{
/***************CHECKING THE ARGUMENT*************/
if (argc < 2)
{
printf("Usage: %s hostname\n", argv[0]);
return 1;
}
/*************************************************/
int sock_dest;
struct sockaddr_in server_addr;
char line[300];
/******************CREATE SOCKET*****************/
sock_dest = socket(AF_INET, SOCK_STREAM, 0);
if(sock_dest == -1)
{
printf("Couldn't create socket.\n");
return 1;
}
struct hostent *server;
server = gethostbyname(argv[1]);
if (server == NULL)
{
printf("ERROR, no such host\n");
return 1;
}
/***** SETTING FIELDS OF SERVER SOCKADDR_IN STRUCTURE *****/
bzero((char *) &server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,(char *)&server_addr.sin_addr.s_addr,server->h_length);
server_addr.sin_port = htons ( 31000 );
/**********************************************************/
/*********TRYING TO CONNECT TO THE SERVER******************/
if (connect(sock_dest,(struct sockaddr *) &server_addr,sizeof(server_addr)) < 0)
{
printf("ERROR:(Can't connect to the server. Please check if it's online)\n");
return 1;
}
/***********************************************************/
char path_read[200];
int read_len,n;
FILE *f_read;
char *exit_signal = "\nEXIT\0";
if((f_read=fopen("test.txt","r"))==NULL)
{
printf("Failed to open path.txt.\n");
return 0;
}
while((fgets(path_read,200,f_read))!=NULL)
{
path_read[strlen(path_read)+1]='\n';
n = write(sock_dest,path_read,strlen(path_read));
if(n<0)
error("ERROR writing to socket");
bzero(path_read,200);
}
n=write(sock_dest,exit_signal,strlen(exit_signal));
fclose(f_read);
close(sock_dest);
printf("All lines in the file were sent to the server.\nExiting...\n");
return 0;
}
This is one bug:
(void*) &client_socket
Firstly, no need to cast to void*. Secondly, it looks like client_socket is a local variable, who's address you pass to the thread as context. In the starting thread, you then continue to overwrite its value with the next iteration.

C: How do you read and unpack a message over a socket?

I am trying to receive an updated message over the socket and unpack the
data. I want to use the update_client function to update the server's
internal representation of the client co-ordinates and respond to the
client with the required value.
I think I should use recv to read the full message (of length UPDATE_CMD_LEN) into buffer.
Then unpack data having message in the following format:
U<id><fields of gpscoords>
Character 'U' (meaning update), followed by ID of the client (unsigned char)
and then the gpscoord structure in network format.
This is a rough idea of how to do it but I don't know how:
[1] Unpack ID
[2] Unpack coordinates with int update_client(unsigned char id, gpscoords *pos
which takes ID and pointer to position struct, returns -1 on error and 0 on success
The server should then respond to client using sendto function and reply
NO_RES on error and SUCC_RES on success.
void do_update(int sockfd, struct sockaddr_in *clientaddr) {
char msg[UPDATE_CMD_LEN];
recv(sockfd, msg, UPDATE_CMD_LEN, flags);
fprintf(stderr, "do_update not implemented!\n");
exit(-1);
}
client.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include "gps.h"
#define CMD_LEN 10
#define LINE_LEN NAME_LEN + 15
#define FIREFOX "/usr/bin/firefox"
void make_route_url(char *url, gpscoords *pos, gpscoords *target) {
char pos_sign_n;
char pos_sign_e;
char tar_sign_n;
char tar_sign_e;
pos_sign_n = pos->north ? '+' : '-';
pos_sign_e = pos->east ? '+' : '-';
tar_sign_n = target->north ? '+' : '-';
tar_sign_e = target->east ? '+' : '-';
sprintf(url,
"http://map.project-osrm.org/?z=13&loc=%c%u.%u,%c%u.%u&loc=%c%u.%u,%c%u.%u",
pos_sign_n, pos->lat, pos->lat_frac,
pos_sign_e, pos->lon, pos->lon_frac,
tar_sign_n, target->lat, target->lat_frac,
tar_sign_e, target->lon, target->lon_frac);
}
void show_route(gpscoords *pos, gpscoords *target) {
// char url[75];
fprintf(stderr, "show_route not implemented!\n");
exit(-1);
}
int run_client(char *name, char *serverip) {
char *cmdline;
size_t line_len;
char cmd[11];
gpsinfo info;
gpscoords pos, targetpos;
char targetname[NAME_LEN];
bzero(targetname, NAME_LEN);
bzero(&info, sizeof(info));
bzero(&pos, sizeof(pos));
bzero(&targetpos, sizeof(targetpos));
if (register_client(serverip, name, &info) == -1) {
perror("Error registering client.");
return -1;
}
find_self(&pos);
if (update_position(&info, &pos) == -1) {
printf("Failed to send initial position to server.\n");
exit(-1);
}
for (;;) {
printf("Command: ");
line_len = 0;
cmdline = NULL;
getline(&cmdline, &line_len, stdin);
if (strncmp(cmdline, "update", 3) == 0) {
find_self(&pos);
if (update_position(&info, &pos) == -1) {
printf("Failed to update.\n");
}
} else if (strncmp(cmdline, "find", 3) == 0) {
sscanf(cmdline, "%10s %25s", cmd, targetname);
if (get_position(&info, targetname, &targetpos) == -1) {
printf("Couldn't find target.\n");
} else {
show_route(&pos, &targetpos);
}
} else if (strncmp(cmdline, "quit", 4) == 0) {
free(cmdline);
break;
}
free(cmdline);
}
if (unregister_client(&info) == -1) {
perror("Error unregistering client.");
return -1;
}
return 0;
}
int main(int argc, char **argv) {
if (argc < 2) {
printf("Usage: ./client <client name> <server_ip>\n");
return 0;
}
return run_client(argv[1], argv[2]);
}
socket.c
#include <sys/socket.h>
#include <stdint.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include "sockets.h"
int create_dg_socket(in_port_t port) {
// Create the socket
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1) {
printf("create_dg_socket cannot create socket!");
return -1;
}
// Bind the socket port
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
printf("create_dg_socket cannot bind socket!");
close(sockfd);
return -1;
}
return sockfd;
}
int open_dg_socket(char *ipaddr, in_port_t port, struct sockaddr_in *addr) {
// Create the socket
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1) {
return -1;
}
// Setup
addr->sin_family = AF_INET;
addr->sin_port = htons(port);
addr->sin_addr.s_addr = inet_addr(ipaddr);
return sockfd;
}
int dg_sendrecv(int sockfd,
struct sockaddr_in *addr,
char *message, size_t out_len,
char *response, size_t in_len) {
if (sendto(sockfd, message, out_len, 0, (struct sockaddr *)&addr, sizeof(*addr)) == -1) {
printf("dg_sendrecv cannot send data!");
return -1;
}
int ret = recvfrom(sockfd, response, in_len, 0, NULL, NULL);
if (ret == -1) {
printf("dg_sendrecv cannot read data!");
return -1;
}
return ret;
}
/*
int dg_sendrecv(int sockfd,
struct sockaddr_in *addr,
char *message, size_t out_len,
char *response, size_t in_len) {
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(ipaddr);
return dg_sendrecv_addr(sockfd, &addr, message, out_len, response, in_len);
}
*/
server.c
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include "sockets.h"
#include "gps.h"
#include "server.h"
#define NUM_CLIENTS 5
char clients[NUM_CLIENTS][NAME_LEN];
gpscoords coords[NUM_CLIENTS];
void do_register(int sockfd, struct sockaddr_in *clientaddr) {
char msg[REGISTER_CMD_LEN];
char *name;
unsigned char id, i;
if (recv(sockfd, msg, REGISTER_CMD_LEN, 0) == -1) {
perror("Error receiving register command.");
exit(-1);
}
// first byte is server command, rest is name
name = &msg[1];
id = NO_RES;
for (i = 0; i < NUM_CLIENTS; ++i) {
if (clients[i][0] == '\0') {
strncpy(clients[i], name, NAME_LEN);
clients[i][NAME_LEN - 1] = '\0';
bzero(&coords[i], sizeof(coords[i]));
id = i + 1;
break;
}
}
if (sendto(sockfd,
&id, sizeof(id),
0,
(struct sockaddr *)clientaddr, sizeof(*clientaddr)) == -1) {
perror("Error replying to client.");
exit(-1);
}
}
void do_unregister(int sockfd, struct sockaddr_in *clientaddr) {
unsigned char msg[UNREGISTER_CMD_LEN];
unsigned char id;
char res = NO_RES;
if (recv(sockfd, &msg, UNREGISTER_CMD_LEN, 0) == -1) {
perror("Error receiving unregister command.");
exit(-1);
}
id = msg[1] - 1;
if (id < NUM_CLIENTS) {
clients[id][0] = '\0';
res = SUCC_RES;
}
if (sendto(sockfd,
&res, sizeof(res),
0,
(struct sockaddr *)clientaddr, sizeof(*clientaddr)) == -1) {
perror("Error responding to client.");
exit(-1);
}
}
int update_client(unsigned char id, gpscoords *pos) {
id -= 1;
if (id >= NUM_CLIENTS)
return -1;
memcpy(&coords[id], pos, sizeof(coords[id]));
return 0;
}
void do_update(int sockfd, struct sockaddr_in *clientaddr) {
/**
* Receive an update message over the socket and unpack the
* data. Then use the update_client function to update the server's
* internal representation of the client co-ordinates. Then respond to the
* client with the required value.
* Use recv to read the full message (of length UPDATE_CMD_LEN) into buffer.
* Unpack data, message of following format:
* U<id><fields of gpscoords>
* Character 'U' (meaning update), followed by ID of the client (unsigned char)
* and then the gpscoord structure in network format.
*
* 1. Unpack ID
* 2. Unpack coordinates with (int update_client(unsigned char id, gpscoords *pos)
* which takes ID and pointer to position struct, returns -1 on error and 0 on success
* Server should then respond to client using sendto function and reply
* NO_RES on error and SUCC_RES on success.
*/
char msg[UPDATE_CMD_LEN];
recv(sockfd, msg, UPDATE_CMD_LEN, flags);
fprintf(stderr, "do_update not implemented!\n");
exit(-1);
}
static gpscoords *get_client(char *name) {
for (int i = 0; i < NUM_CLIENTS; ++i) {
if (strcmp(name, clients[i]) == 0) {
return &coords[i];
break;
}
}
return NULL;
}
void do_get(int sockfd, struct sockaddr_in *clientaddr) {
char msg[GET_CMD_LEN];
char res[GET_RES_LEN];
char *name;
if (recv(sockfd, msg, GET_CMD_LEN, 0) == -1) {
perror("Error receiving get command.");
exit(-1);
}
name = &msg[1];
name[NAME_LEN - 1] = '\0';
gpscoords *pos = get_client(name);
if (pos == NULL) {
res[0] = NO_RES;
} else {
res[0] = SUCC_RES;
pack_gpscoords(pos, &res[1]);
}
if (sendto(sockfd,
&res, GET_RES_LEN,
0,
(struct sockaddr *)clientaddr, sizeof(*clientaddr)) == -1) {
perror("Error sending result to client.");
exit(-1);
}
}
int serve(int sockfd) {
char cmd;
struct sockaddr_in clientaddr;
socklen_t clientaddrlen = sizeof(clientaddr);
for (;;) {
if (recvfrom(sockfd,
&cmd, sizeof(cmd),
MSG_PEEK,
(struct sockaddr *)&clientaddr, &clientaddrlen) == -1) {
exit(-1);
}
switch (cmd) {
case CMD_REGISTER:
do_register(sockfd, &clientaddr);
break;
case CMD_UNREGISTER:
do_unregister(sockfd, &clientaddr);
break;
case CMD_UPDATE:
do_update(sockfd, &clientaddr);
break;
case CMD_GET:
do_get(sockfd, &clientaddr);
break;
default:
break;
}
}
}
void init_info() {
int i;
for (i = 0; i < NUM_CLIENTS; ++i) {
clients[i][0] = '\0';
}
}
int main(int argc, char **argv) {
int sockfd = create_dg_socket(SERVER_PORT);
if (sockfd == -1) {
fprintf(stderr, "Error creating socket!\n");
return -1;
}
init_info();
printf("Server ready.\n");
serve(sockfd);
// Note: server never terminates, we're relying on the system to clean up
// our open socket file descriptor (and shut it down)
return 0;
}
If you are looking for a way to safe and read data from char arrays that maybe will help you:
char buffer[5+sizeof(gpscoords)];
int *int_pointer;
gpscoords *gps_pointer;
int id=1;
gpscoords gps="some gps contend";
int id_frombuffer;
gpscoords gps_frombuffer;
char c_frombuffer;
buffer[0]='U';
int_pointer=(int*)&buffer;
int_pointer+=1;
*int_pointer=id;
gps_pointer=(gpscoords*)&buffer;
gps_pointer+=5;
*gpspointer=gps;
//send buffer
c_frombuffer=buffer[0];//c_frombuffer now contains 'U'
int_pointer=(int*)&buffer;
int_pointer+=1;
id_frombuffer=*int_pointer;//id_frombuffer now contains 1
gps_pointer=(gpscoords*)&buffer;
gpscoords+=5;
gps_frombuffer=*pointer;//gps_frombuffer now contains "some gps contend"
As an example if your client code looks like that:
void sendupdate(unsigned char id,gpscoords gps)
{
char buffer[2+sizeof(gpscoords)];
gpscoords *gps_pointer;
buffer[0]='U';
buffer[1]=id;
gps_pointer=(gpscoords*)&buffer;
gps_pointer+=2;
*gpspointer=gps;
send(socket, buffer, 2+sizeof(gpscoords), flags);
}
your server function should look like that:
void do_update(int sockfd, struct sockaddr_in *clientaddr)
{
char buffer[2+sizeof(gpscoords)];
recv(sockfd, buffer, 2+sizeof(gpscoords), flags);
unsigned char id_frombuffer=buffer[1];
gpscoords *gpspointer=(gpscoords*)&buffer;
gpspointer+=2;
update_client(id_frombuffer, gpspointer);
}

Select function behavior - Multi Client Quiz

I have to build a quiz application.
Details about the application:
1. Each client has to register to server before participating in Quiz. The server will ask
username from each user and generate temporary id for each user.
2. After Registration process clients, who are successfully connected to server will get
Question from server.
3. The client will reply with answer.
4. Server will receive answer from different clients with time stamps, and it will calculate
time difference of each client which is called ∆t.
Define such as:
∆t = (Time Question sent - Time answer received) - RTT
Where RTT is Round Trip Time
Server will select client, whose ∆t is minimum to all and reply with whatever score client will gain remains will not gain any score.
After sending Question server will wait Answer for a particular time periods called (T). If client did not reply within ‘T’ time period Server will skip that Question and goes to next Question.
Pseudocode of main loop in my server code
A. A main while loop which runs once for each question.
B. Inside this first I am accepting login for 10 seconds.
Here I am assigning user Id and all other initialization stuff.
C. Then using `select` to check which are available for writing.
To available connections I am checking `RTT` and then sending question to each user.
D. Then I am waiting for some time to get answers.
Here I am using `select` to determine where the answer is available to read.
E. Then I am repeating steps C. and D.
Problem:
When I connect only to a single client my code works fine for any number of question.
But when I test this code on multiple client with the same client code:
Login for everyone is OK.
Sending First Question to everyone works fine.
Then while waiting for the answer I only received answer from one client. Each client shows that answer is been sent. For second client the second select function doesn't return with readable data availability.
Why for multi-client my code is not working. (According to me the error is somewhere in getting answer).
My Code:
The structure of the packets send can be understand easily from the variable names.
Server.c:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <error.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#include <time.h>
#define PORT "3490" //the port user will be connecting to
#define BACKLOG 10 //how many pending connection queue will hold
#define maxUser 10
#define LOGIN_OK "OK"
#define LOGIN_WrongPassword "NP"
#define LOGIN_WrongUsername "NU"
#define MAX_USERS 10
#define MAX_ANSWER_TIME 10
#define LOGIN_WAIT 10
#define TOTAL_QUES "3"
int users[MAX_USERS][3] = {}; //index is userID, 0 is no user
void sigchld_handler(int s)
{
while(waitpid(-1, NULL, WNOHANG) > 0);
}
//get sockaddr, IPv4 or IPv6
int timer;
void alarm_handler(int s) {
timer = 0;
}
wrongRecv(ssize_t recvd, ssize_t expctd)
{
if(recvd != expctd)
{
printf("Recvd(%zd) bytes not equal to expected(%zd) bytes\n",recvd,expctd);
//getchar();
}
}
//void nextQues(char* quesMsg, char* ques, char* optA, char* optB, char* optC, char* optD)
int nextQues(char* quesMsg, int QID)
{
char ques[40], optA[10], optB[10], optC[10], optD[10], quesId[5];
sprintf(quesId,"%d",QID);
strncpy(ques, "This is the question?",22);
strncpy(optA, "OptionA", 7); strncpy(optB, "OptionB", 7); strncpy(optC, "OptionC", 7); strncpy(optD, "OptionD", 7);
strncpy(quesMsg,quesId,5);
strncpy(quesMsg + 05,ques,40);
strncpy(quesMsg + 45,optA,10);
strncpy(quesMsg + 55,optB,10);
strncpy(quesMsg + 65,optC,10);
strncpy(quesMsg + 75,optD,10);
return 0;
}
//void answerCheck(char* ques, char* optA, char* optB, char* optC, char* optD, char* usrResponse, int rtt, int timeTaken)
void answerCheck(int fd, char usrResponse[6], int rtt, int timeTaken)
{
int responseTime, i;
char actualAnswer[1];
char quesId[5];
printf("fd(%d) quesid(%s) response(%c) rtt(%d) timeTaken(%d)\n", fd, usrResponse, usrResponse[5], rtt, timeTaken );
strncpy(quesId, usrResponse, 5);
actualAnswer[0] = 'B';//we have quesId we can find actual answer on basis of it
if(actualAnswer[0] == usrResponse[5])
{
//printf("%s\n","+++++" );
responseTime = timeTaken - rtt;
//printf("Response Time(%d)\n",responseTime);
//save it with user id
//finding userid
for(i = 0; i < MAX_USERS; i++) {
if(users[i][1] == fd) {
users[i][2] = responseTime;//saving it
//printf("%d\n",i );
}
}
}
}
int compareAnswer() {
int i, min = 2 * MAX_ANSWER_TIME, userIndex;
for(i = 0; i < MAX_USERS; i++) {
if(users[i][2] < min) {
min = users[i][2];
userIndex = i;
}
}
//Increasing Score
users[userIndex][0]++;
//returning fd
return users[userIndex][1];
}
void users_deleteFd(int fd) {
int i;
for (i = 0; i < MAX_USERS; ++i)
{
if(users[i][1] == fd) {
users[i][1] =0;
return;
}
}
}
int rtt_check(int new_fd)
{
ssize_t send_ret, recv_ret;
char rtt_check[1];
time_t rtt1, rtt2;
rtt1 = time(NULL);
send_ret = send(new_fd, "r", 1, 0);
if(send_ret == 0)
{
return -2;
}
wrongRecv(send_ret, 1);
//printf("%s\n","Between two phase of rttCheck" );
recv_ret = recv(new_fd, rtt_check, 1,0);
rtt2 = time(NULL);
if(recv_ret == 0)
{
return -2;
}
wrongRecv(recv_ret,1);
//printf("diff(%d)\n",(int) difftime(rtt2,rtt1));
return (int) difftime(rtt2,rtt1);
}
int login(char user[], char pass[])
{
//for user
static int Id = 0; //when have function getUserID, make it not static and also remove Id++;
if(!strcmp(user,"abhishek") && !strcmp(pass,"abhishek")) {
//Id = getUserID(user);
return ++Id;
}else if(!strcmp(user,"abhishek")){
return 0; //wrong password
}
return -1; //wrong username
}
int totalQues;
int login_setup(int new_fd)
{
//login inititalizations
char login_det[16];
char username[9],password[9], login_statMsg[7], totalQuesMsg[5] = TOTAL_QUES;
totalQues = atoi(totalQuesMsg);
//for user
int userId;
//for wrongRecv
ssize_t send_ret,recv_ret;
//getting username and password
recv_ret = recv(new_fd,login_det,16,0);
if(recv_ret == 0)
{
return -2;
}
wrongRecv(recv_ret,16);
//extracting username nad password
strncpy(username,login_det,8);
strncpy(password,login_det+8,8);
username[8]='\0'; password[8]='\0';
//printf("username(%s) and password(%s)\n",username,password);
if( (userId = login(username,password)) > 0) {
//printf("%d\n",userId);
//sending status
strncpy(login_statMsg, LOGIN_OK, 2);
strncpy(login_statMsg + 2, totalQuesMsg , 5);
send_ret = send(new_fd, login_statMsg,7,0);
if(send_ret == 0)
{
return -2;
}
wrongRecv(send_ret,7);
//TODO error checking then handling if error
//users[userId][0] = 0; //score
users[userId][1] = new_fd; //file descriptor associated with this user
//users[userId][2] = 0; //answer time
return 1;
}
else if(userId == -1) { //wrong username
strncpy(login_statMsg, LOGIN_WrongUsername, 2);
strncpy(login_statMsg + 2, totalQuesMsg , 5);
send_ret = send(new_fd, login_statMsg,7,0);
if(send_ret == 0)
{
return -2;
}
wrongRecv(send_ret,7);
return 0;
}
else{
strncpy(login_statMsg, LOGIN_WrongPassword, 2);
strncpy(login_statMsg + 2, totalQuesMsg , 5);
send_ret = send(new_fd, login_statMsg,7,0);
if(send_ret == 0)
{
return -2;
}
wrongRecv(send_ret,7);
return 0;
}
//TODO erorr handling of above two case
//TODO make login a loop
}
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(void)
{
int listen_fd, new_fd; // listen on sock_fd, new connection on new_fd
struct addrinfo hints, *servinfo, *p;
struct sockaddr_storage their_addr;//connection's address info
socklen_t sin_size;
int yes=1;
char s[INET6_ADDRSTRLEN];
int rv;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;//IPv4 or IPv6
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; // use my IP
if((rv = getaddrinfo(NULL,PORT, &hints, &servinfo)) != 0){ //getting which IPv server supports
fprintf(stderr, "getaddrinfo: %s\n",gai_strerror(rv));
return 1;
}
//loop through all the result and bind to the first we can
for(p = servinfo; p != NULL; p = p->ai_next){
if((listen_fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1){
perror("server : socket");
continue;
}
if(setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1){
perror("set sockopt");
exit(1);
}
if(bind(listen_fd, p->ai_addr, p->ai_addrlen) == -1){
close(listen_fd);
perror("server: bind");
continue;
}
break;
}
if(p == NULL) {
fprintf(stderr, "server:failed to bind\n");
return 2;
}
freeaddrinfo(servinfo);//all done with this structure
if(listen(listen_fd, BACKLOG) == -1){
perror("listen");
exit(1);
}
//printf("listen_fd(%d)\n",listen_fd );
// sa.sa_handler = sigchld_handler; // reap all dead processes
// sigemptyset(&sa.sa_mask);
// sa.sa_flags = SA_RESTART;
// if(sigaction(SIGCHLD, &sa, NULL) == -1){
// perror("sigaction");
// exit(1);
// }
printf("server waiting for connections.....\n");
fd_set master; //master file descriptor list
fd_set read_fds; //temp file descriptor list for select()
int fdmax;
FD_ZERO(&master); //clear the master and temp sets
FD_ZERO(&read_fds);
FD_SET(listen_fd, &master);
//keep track of the bigge file descriptor
fdmax = listen_fd; // so far it is this one
ssize_t recv_ret, send_ret;
//for login
int loginStatus;
struct sigaction sa;
sa.sa_handler = alarm_handler;
sigemptyset(&sa.sa_mask);
//sa.sa_flags = SA_RESTART;
if(sigaction(SIGALRM, &sa, NULL) == -1){
perror("sigaction");
exit(1);
}
//login while
alarm(LOGIN_WAIT);//accepting login only for 10 seconds
timer = 1;
printf("\n-----------------------------Waiting for users to login for %d seconds.-----------------------------\n",LOGIN_WAIT);
while(timer) {
sin_size = sizeof their_addr;
new_fd = accept(listen_fd, (struct sockaddr *)&their_addr, &sin_size);
if(new_fd == -1){
//perror("accept");
break;// this break is very important , as we are using alarm(Signals) and accept is a blocking function
//If accept is in blocked sate and our signal comes then accept will exit returning error. So
//if error then we have to break else next satements will run on falsy values.
//In reality we dont need this as I alredy set the SA_RESTART flag in sigaction which means
//after returning from the signal handler restart the activity on which you are previously
//instead of starting execution from next line.
}else {
inet_ntop(their_addr.ss_family, get_in_addr((struct sockaddr *)&their_addr), s, sizeof s);
printf("server : got connection from %s\n", s);
//LOGIN //need to call login function via thread because this
//may stop the function if user doesnot respond
loginStatus = login_setup(new_fd);
//adding to select checkup
if(loginStatus) {
printf("User Loginned Succesfully\n");
}
}
}
printf("-----------------------------Login Closed. Now starting the QUIZ.-----------------------------\n");
//for randome seek
srand(time(NULL));
//for main loop counter
int i, win_fd;
//for questions
int QID = 0;
int maxQues_Len = 40, maxOpt_len = 10, maxQuesId_len = 5;//including '\0' this time
char quesMsg[80], answer[6];//score doesnot include \0
//char ques[40], optA[10], optB[10], optC[10], optD[10];
//for time calculation of each answer
ssize_t time_ques, time_ans;
//getting all avialable participants
fdmax = 0;
FD_ZERO(&master);
for(i = 0; i < MAX_USERS; i++) {
if( (new_fd = users[i][1]) != 0){
FD_SET(new_fd, &master);
if(new_fd > fdmax)
fdmax = new_fd;
//printf("%d\n",new_fd);
}
}
int current_rtt;
//while for main quiz
while(totalQues--) {
//checking who are ready for witing
if(select(fdmax+1, NULL, &master, NULL, NULL) == -1){//here select will return withh all the descriptors which are
//ready to write , all others have to miss this question
perror("select");
exit(1);
}
//setting which question to send
QID++;
//for sending questions to all
for(i = 0; i <= fdmax; i++) {
if(FD_ISSET(i, &master)) {
//rtt check
current_rtt = rtt_check(i);
if(current_rtt == -2) {//connection closed
FD_CLR(i, &master);
users_deleteFd(i);
continue;
}
//setting question
//nextQues(quesMsg, ques, optA, optB, optC, optD);
nextQues(quesMsg, QID);
printf("Sending Question QID(%s) fd(%d)\n",quesMsg,i);
//send a question
time_ques = time(NULL);
send_ret = send(i, quesMsg, maxQues_Len + 4 * maxOpt_len + maxQuesId_len, 0);
if(send_ret == 0) {//connection closed
FD_CLR(i, &master);
users_deleteFd(i);
continue;
}
wrongRecv(send_ret, maxQues_Len + 4 * maxOpt_len + maxQuesId_len);
}
}
//ASSUMING Question is send ot all the users at same time
//receiving and waiting for answers
alarm(MAX_ANSWER_TIME);
timer = 1;
FD_ZERO(&read_fds);
read_fds = master;
// unsigned int qq = read_fds.fd_count;
// for (int ii = 0; ii < qq; ++ii)
// {
// printf("%d\n",read_fds.fd_array[i] );
// }
while(timer) {
//printf("HURRAY\n");
if(select(fdmax+1, &read_fds, NULL, NULL, NULL) <=0){
perror("select");
//exit(4);
break;//break is important. Explained above
}
for(i = 0; i <= fdmax; i++) {
//printf("Recving answer I(%d)\n",i);
if(FD_ISSET(i, &read_fds)) {
//receiving answer
//TODO if we get answer to wrong ques
printf("Recving answer I(%d) fdmax (%d)\n",i,fdmax);
recv_ret = recv(i,answer,6,0);
time_ans = time(NULL);
wrongRecv(recv_ret,6);
printf("%s\n",answer );
if(recv_ret == 0)//connection closed
{
FD_CLR(i, &read_fds);
FD_CLR(i, &master);
users_deleteFd(i);
continue;
}else if(recv_ret > 0){
if(QID == atoi(answer)) { //we have received the answer to this question so remove the user from wait answer loop
FD_CLR(i, &read_fds);
//printf("%s i(%d)\n","#######",i );
answerCheck(i ,answer, current_rtt, (int) difftime(time_ans,time_ques));
//printf("Answer(%c)\n",answer[0]);
}
else{//we have recvd something unexpectable so ignore for NOW
}
}
//time_t cccc = time(NULL);
//printf("%s I(%d)\n",ctime(&cccc),i);
}
}
}
//comparing answers
win_fd = compareAnswer();
//sending score
}
return 0;
}
Client.c:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define PORT "3490" //the port client will be connecting to
#define MAXDATASIZE 100 // max number of bytes we can get at once
//get sockaddr ,IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
if(sa->sa_family ==AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
wrongRecv(ssize_t recvd, ssize_t expctd)
{
if(recvd != expctd)
{
printf("Recvd(%zd) bytes not equal to expected(%zd) bytes\n",recvd,expctd);
getchar();
}
}
void rtt_check(int sockfd)
{
ssize_t send_ret, recv_ret;
char rtt_check[1];
recv_ret = recv(sockfd, rtt_check, 1,0);
wrongRecv(recv_ret,1);
sleep(1);//to check
send_ret = send(sockfd, "r", 1, 0);
wrongRecv(send_ret, 1);
return;
}
int main(int argc, char *argv[])
{
int sockfd, numbytes;
char buf[MAXDATASIZE];
struct addrinfo hints, *servinfo, *p;
int rv;
char s[INET6_ADDRSTRLEN];
if(argc != 2) {
fprintf(stderr,"usage: client hostname\n");
exit(1);
}
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if((rv = getaddrinfo(argv[1], PORT, &hints, &servinfo)) != 0) {
fprintf(stderr,"getaddrinfo: %s\n",gai_strerror(rv));
return 1;
}
//lopp through all the results and connect to the first we can
for(p = servinfo; p != NULL; p = p->ai_next) {
if((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1){
perror("client: socket");
continue;
}
if(connect(sockfd, p->ai_addr, p->ai_addrlen) == -1){
close(sockfd);
perror("client: connect");
continue;
}
break;
}
if(p ==NULL) {
fprintf(stderr,"client: failed to connect\n");
return 2;
}
inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr), s, sizeof s);
printf("client : connecting to %s\n", s);
freeaddrinfo(servinfo); // all done with this structure
char login_det[17] = "abhishekabhishek";
char login_retMsg[7], login_stat[3], totalQuesMsg[5];
int totalQues;
//sending login details
ssize_t send_ret,recv_ret;
send_ret = send(sockfd, login_det,16,0);
wrongRecv(send_ret,16);
//receiving login status
recv_ret = recv(sockfd,login_retMsg,7,0);
wrongRecv(recv_ret,7);
strncpy(login_stat, login_retMsg, 2);
login_stat[2] = '\0';
printf("Login Status(%s)\n",login_stat);
strncpy(totalQuesMsg, login_retMsg + 2, 5);
totalQues = atoi(totalQuesMsg);
printf("totalQues(%d)\n",totalQues);
if(!strcmp(login_stat,"OK")) { //login ok
char quesId[5];
int maxQues_Len = 40, maxOpt_len = 10, maxQuesId_len = 5;//including '\0' this time
char quesMsg[80], scoreMsg[1];//score doesnot include \0
char ques[40], optA[10], optB[10], optC[10], optD[10];
char answer[6];
while(totalQues--) {
//checking rtt
rtt_check(sockfd);
//receving question
recv_ret = recv(sockfd, quesMsg, maxQues_Len + 4 * maxOpt_len + maxQuesId_len ,0);
wrongRecv(recv_ret, maxQues_Len + 4 * maxOpt_len + maxQuesId_len);
strncpy(quesId,quesMsg,5);
strncpy(ques, quesMsg + 05, 40);
strncpy(optA, quesMsg + 45, 10);
strncpy(optB, quesMsg + 55, 10);
strncpy(optC, quesMsg + 65, 10);
strncpy(optD, quesMsg + 75, 10);
printf("QUESID(%s) Question(%s), A(%s) , B(%s) , C(%s) , D(%s)\n", quesId, ques, optA, optB, optC, optD);
//choose answer
scoreMsg[0] = 'B';
strncpy(answer,quesId, 5);
answer[5] = scoreMsg[0];
sleep(5);
//sending answer
send_ret = send(sockfd, answer,6,0);
wrongRecv(send_ret,6);
printf("%s\n","Answer Message Sent" );
// if((numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1) {
// perror("recv");
// exit(1);
// }
// buf[numbytes] = '\0';
// printf("client: received '%s'\n",buf);
}
}
//TODO wrong login
close(sockfd);
return 0;
}
The problem is that the call to select in the answer getting loop is modifying read_fds to hold just the file descriptor of the first client(s) to respond. Since you don't reset read_fds before calling select again, it will not recognize the other clients' response.

Resources