Related
In our project we have to make a game (that is already done) and allow a multiplayer way to play (with a P2P method). I have made "client" and "server" programs to begin (I think that in the future the programs will be the same) using the select method in order to allow them to send and receive messages to each other. When I tried to send a message (a number written in the terminal) from the server to the client, it's ok, but, when I tried to do the same from the client to the server, nothing happened. Moreover, when I start sending a message from the client to the server, it works but the server can't send nothing (more precisely the client doesn't receive anything).
I don't understand this behaviour, and so I've tried to use threads but my profesor said that I don't need it if I use well select...
You will find below the code for the "server"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h>
#define FALSE 0
#define TRUE 1
typedef struct Element Element;
struct Element
{
int data_i;
Element *suivant;
};
typedef struct
{
Element *premier;
} File;
void initialise(File *file)
{
file->premier = NULL;
}
int enfiler(File *file, long long nbre)
{
if (file == NULL)
{
printf("Il faut initialiser la file");
return EXIT_FAILURE;
}
Element *new_el = malloc(sizeof(Element));
new_el->suivant = NULL;
new_el->data_i = nbre;
if (file->premier != NULL)
{
Element *elementActuel = file->premier;
while (elementActuel->suivant != NULL)
{
elementActuel = elementActuel->suivant;
}
elementActuel->suivant = new_el;
printf("j'ai bien enfilé le message\n");
return EXIT_SUCCESS;
}
else
{
file->premier = new_el;
printf("j'ai bien enfilé le message\n");
return EXIT_SUCCESS;
}
return EXIT_FAILURE;
}
Element defiler(File *file)
{
if (file != NULL && file->premier != NULL)
{
Element *el = malloc(sizeof(Element));
el = file->premier;
file->premier = file->premier->suivant;
free (el);
return *el;
}
//voir quoi retourner lors d'erreurs
}
void stop(char * msg){
perror(msg);
exit(EXIT_FAILURE);
}
typedef struct {
int fd;
}client_info;
int main(int argc,char *argv[]){
//Variables
int opt = TRUE;
int master_socket=0, new_socket=0, max_client = 30, activity=0, i=0;
int max_sd = 0;
client_info client_tab[max_client];
struct sockaddr_in address;
int addr_len=0;
fd_set readfds;
long long message=0;
int64_t buffer=0;
int smess = 0;
int sd =0;
write(0,"initialisation\n",15);
//initializing the "file"
File file_mess, file_recus;
initialise(&file_mess);
initialise(&file_recus);
//Initializing files descriptors
for (i = 0; i < max_client; i++)
{
client_tab[i].fd = -1;
}
//create a master socket
if( (master_socket = socket(AF_INET , SOCK_STREAM , 0)) == 0)
{
perror("socket failed");
exit(EXIT_FAILURE);
}
if( setsockopt(master_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) < 0 )
{
perror("setsockopt");
exit(EXIT_FAILURE);
}
//Initializing address
address.sin_family = AF_INET;
inet_aton("127.0.0.1", &address.sin_addr);
address.sin_port = htons( 1234 );
addr_len = sizeof(address);
//Configurating master_socket to listen to new connections .
if(bind(master_socket,(const struct sockaddr *)&address,addr_len)<0) stop("binding error");
if(listen(master_socket,3)<0) stop("Problem initializing master_socket");
printf("Enterring while\n");
while(TRUE){
//clear the socket set
FD_ZERO(&readfds);
//add master socket to set
FD_SET(master_socket, &readfds);
FD_SET(STDIN_FILENO,&readfds);
max_sd = master_socket;
//add child sockets to set
for ( i = 0 ; i < max_client ; i++)
{
//socket descriptor
sd = client_tab[i].fd;
//if valid socket descriptor then add to read list
if(sd > 0)
FD_SET( sd , &readfds);
//highest file descriptor number, need it for the select function
if(sd > max_sd)
max_sd = sd;
}
activity = select( max_sd + 1 , &readfds , NULL , NULL , NULL);
if ((activity < 0) && (errno!=EINTR)) stop("select error");
if (FD_ISSET(master_socket, &readfds))
{
if ((new_socket = accept(master_socket, (struct sockaddr *)&address, (socklen_t*)&addr_len))<0) stop("accepting problem");
for (i = 0; i < max_client; i++)
{
//if position is empty
if( client_tab[i].fd == -1 )
{
client_tab[i].fd = new_socket;
printf("Adding to list of sockets as %d\n\n" , i);
// Après avoir ajouté le client dans le tableau, le serveur lui renvoie un id (valeur de i)
if(send(client_tab[i].fd, &i, sizeof(int), 0) == -1) stop("recv() : envoi de l'id");
break;
}
}
}
//else its some IO operation on some other socket :)
for (i = 0; i < max_client; i++)
{
sd = client_tab[i].fd;
if (FD_ISSET( sd , &readfds) && sd!=-1)
{
//Check if it was for closing , and also read the incoming message
if ((smess = recv( sd,(char *)&buffer,__SIZEOF_LONG_LONG__,0)) == 0)
{
//Somebody disconnected , get his details and print
getpeername(sd , (struct sockaddr*)&address , (socklen_t*)&addr_len);
printf("%i disconnected.\n",i);
//Close the socket and mark as 0 in list for reuse
close( sd );
client_tab[i].fd = -1;
}
else{
message = ntohl(buffer);
buffer=0;
printf("Message reçu de %i : %lli\n",i,message);
enfiler (&file_recus, message);
message = 0;
}
}
}
if(FD_ISSET(STDIN_FILENO,&readfds)){
scanf("%lli",&message);
enfiler(&file_mess,message);
buffer = htonl(file_mess.premier->data_i);
for (i = 0; i < max_client; i++)
{
if(client_tab[i].fd != -1) send(client_tab[i].fd,&buffer,sizeof(buffer),0);
}
printf("J'ai bien envoyé : %lli\n",message);
defiler(&file_mess);
buffer = 0;
message=0;
}
if (file_mess.premier != NULL)
{
printf("regarde si des trucs à envoyer\n");
buffer = htonl(file_mess.premier->data_i);
//envoie à tout le monde
for (i = 0; i < max_client; i++)
{
if (client_tab[i].fd != -1)
{
send(client_tab[i].fd, &buffer, sizeof(buffer), 0);
}
}
printf("envoyé\n");
defiler(&file_mess);
buffer=0;
}
}
}
And here the "client" :
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#define BUFSIZE 100
#define TRUE 1
#define FALSE 0
typedef struct Element Element;
struct Element
{
int data_i;
Element *suivant;
};
typedef struct
{
Element *premier;
} File;
void initialise(File *file)
{
file->premier = NULL;
}
int enfiler(File *file, long long nbre)
{
if (file == NULL)
{
printf("Il faut initialiser la file");
return EXIT_FAILURE;
}
Element *new_el = malloc(sizeof(Element));
new_el->suivant = NULL;
new_el->data_i = nbre;
if (file->premier != NULL)
{
Element *elementActuel = file->premier;
while (elementActuel->suivant != NULL)
{
elementActuel = elementActuel->suivant;
}
elementActuel->suivant = new_el;
printf("j'ai bien enfilé le message\n");
return EXIT_SUCCESS;
}
else
{
file->premier = new_el;
printf("j'ai bien enfilé le message\n");
return EXIT_SUCCESS;
}
return EXIT_FAILURE;
}
Element defiler(File *file)
{
if (file != NULL && file->premier != NULL)
{
Element *el = malloc(sizeof(Element));
el = file->premier;
file->premier = file->premier->suivant;
free(el);
return *el;
}
}
void stop(char *msg)
{
perror(msg);
exit(EXIT_FAILURE);
}
int main(int argc, char *argv[])
{
//Creating a TCP|IPV4 socket
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1)
stop("Probleme de socket");
//Creating the socket
struct sockaddr_in serv_addr;
bzero(&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(1234);
inet_aton("127.0.0.1", &serv_addr.sin_addr);
//initializing the "file"
File file_mess, file_recus;
initialise(&file_mess);
initialise(&file_recus);
//initiliazing the file descriptor set
fd_set readfds;
FD_ZERO(&readfds);
if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
stop("Connection error");
int id = 0;
if(recv(sockfd, &id, sizeof(int), 0) == -1) stop ("recv() : reception de l'id"); // Le client récupère son id
printf("Mon id : %i\n", id);
FD_SET(sockfd, &readfds);
FD_SET(STDIN_FILENO, &readfds);
//Variables
int nSelect = 0;
int n;
long long mess = 0;
int64_t fmess = 0;
while (TRUE)
{
nSelect = select(sockfd + 1, &readfds, NULL, NULL, NULL);
if (nSelect < 0)
stop("Select error");
if (FD_ISSET(STDIN_FILENO, &readfds))
{
scanf("%lli", &mess);
fmess = htonl(mess);
send(sockfd, &fmess, sizeof(fmess), 0);
printf("J'ai bien envoyé : %lli\n", mess);
mess = 0;
}
if (file_mess.premier != NULL)
{
send(sockfd, &file_mess.premier->data_i, sizeof(file_mess.premier->data_i), 0);
defiler(&file_mess);
}
if (FD_ISSET(sockfd, &readfds))
{
printf("reçu\n");
if ((n=recv(sockfd, &mess, sizeof(long long), 0)) < 0)
stop("recv(");
else if (n==0)
{
printf("déconnexion...\n");
close(sockfd);
return EXIT_SUCCESS;
}
else
{
printf("cc\n");
mess = ntohl(fmess);
fmess = 0;
printf("Message reçu: %lli\n", mess);
enfiler(&file_recus, mess);
mess = 0;
}
}
}
exit(0);
}
Here, you will find my tests:
1-The client begins the conversation by sending 13, but doesn't receive what the server tries to send
client
server
2-Then, the server begins the conversation sending 15, the client doesn't receive it and he sends nothing
client, before stopping
server, before stopping
client, stopped
server, stopped
PS: the use of file is to allow a good treatment for the data (I will made a protocol [using long long numbers] and so I will have to process the data before sending and after receiving). And to finish, this code also permits to give a number to identify the players (and to know who the data receive is for).
The code below is a chatroom. First I run the server, and then the clients. The clients reach the server with sockets. Then the server accepts the connection and the client has to enter his nickname.
I use threads because this way, the fgets is not blocking and multiple clients can reach the server even if a client is slow to enter his nickname.
Until here, there is no problem and everything works, even the select.
After this, the client can introduce a message which is send to all the clients (this is the principle of a chat :P). The problem is that from here, the select doesn't react and stay blocked. Maybe it's because of the FD_set or the threads but actually I don't know and that is the problem.
server.c :
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <pthread.h>
#define MYPORT 5555
#define PSEUDO_MAX 30
#define MESSAGE_MAX 1000
#define BACKLOG 10
struct User {
char pseudo[PSEUDO_MAX];
int socket;
struct User *next;
};
struct Thread {
struct User* lst;
fd_set* readfds;
int* max;
int socket;
pthread_mutex_t* mutex;
};
void add(struct User** pp, const char *t, const int sock)
{
struct User *p = malloc(sizeof(*p));
strcpy(p->pseudo, t);
p->socket = sock;
p->next = NULL;
while (*pp)
pp = &(*pp)->next;
*pp = p;
}
void print(const struct User* n)
{
for ( ; n; n = n->next ){
printf("LISTE : %s\n", n->pseudo);
printf("LISTE : %d\n", n->socket);
}
printf("\n");
}
void *thread_pseudo(void *arg)
{
struct Thread* ps_thread = (struct Thread*)arg;
int nsock = ps_thread->socket;
struct User* lst = ps_thread->lst;
int* max = ps_thread->max;
pthread_mutex_t* mutex = ps_thread->mutex;
pthread_mutex_lock(mutex);
fd_set* readfds = ps_thread->readfds;
pthread_mutex_unlock(mutex);
char pseudo[PSEUDO_MAX];
if (send(nsock, "Bienvenue sur le chat !\n",24,0)==-1){
perror("Serveur: send");
}
if (recv(nsock, pseudo, PSEUDO_MAX, 0) == -1) {
perror("Serveur: recv 2: ");
}
pthread_mutex_lock(mutex);
FD_SET(nsock, readfds); // Ajout du nouveau socket au select
*max = (nsock < *max ? *max : nsock);
pthread_mutex_unlock(mutex);
add(&lst, pseudo, nsock);
print(lst);
pthread_exit(NULL);
}
int findSender(fd_set* readfds, const struct User* n){
int socket = 0;
for ( ; n; n = n->next ){
if(FD_ISSET(n->socket, readfds)){
socket = n->socket;
}
}
return socket;
}
int main()
{
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int sockfd2, new_fd; // listen on sock_fd, new connection on new_fd
int max;
struct sockaddr_in my_addr; // my address information
struct sockaddr_in their_addr; // connector's address information
unsigned int sin_size;
int yes=1;
struct User *lst = NULL; // Initialisation de la liste des Users
struct Thread *ps_thread = malloc(sizeof(*ps_thread)); // Initialisation du struct qui contient les paramètres pour le thread
fd_set readfds;
if ((sockfd2 = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
perror("Serveur: socket 2");
return EXIT_FAILURE;
}
if (setsockopt(sockfd2,SOL_SOCKET,SO_REUSEADDR, &yes,sizeof(int)) == -1) {
perror("Serveur: setsockopt 2");
return EXIT_FAILURE;
}
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(MYPORT);
my_addr.sin_addr.s_addr = INADDR_ANY;
memset(&(my_addr.sin_zero), '\0', 8);
if (bind(sockfd2, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {
perror("Serveur: bind 2");
return EXIT_FAILURE;
}
if (listen(sockfd2, BACKLOG) == -1) {
perror("Serveur: listen 2");
return EXIT_FAILURE;
}
//Initialisation du fd_set et du max
FD_ZERO(&readfds);
FD_SET(sockfd2, &readfds);
max = sockfd2;
while(1){
if (select(max+1, &readfds, NULL, NULL, NULL) < 0){
printf("error select\n");
}
int sock = findSender(&readfds, lst);
if(FD_ISSET(sockfd2, &readfds)){
new_fd = accept(sockfd2, (struct sockaddr *)&their_addr, &sin_size);
if (new_fd == -1) {
perror("Serveur: accept");
}
pthread_t thread;
ps_thread->lst = lst;
ps_thread->readfds = &readfds;
ps_thread->max = &max;
ps_thread->socket = new_fd;
ps_thread->mutex = &mutex;
if (pthread_create(&thread, NULL, thread_pseudo, ps_thread)) {
perror("pthread_create");
return EXIT_FAILURE;
}
}
else if(FD_ISSET(sock, &readfds)) {
char* message;
int sock = findSender(&readfds, lst);
if (recv(sock, message, MESSAGE_MAX, 0) == -1) {
perror("Serveur: recv 2: ");
}
}
else{
printf("ERROR\n");
}
}
return EXIT_SUCCESS;
}
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 <pthread.h>
#define PORT 5555
#define PSEUDO_MAX 30
#define MESSAGE_MAX 1000
void getPseudo(char* pseudo) {
size_t ln = -1;
while (ln <= 0 || ln > PSEUDO_MAX-1) {
printf("Entrez votre pseudo : ");
fgets(pseudo, PSEUDO_MAX, stdin);
ln = strlen(pseudo) - 1;
}
if (pseudo[ln] == '\n')
pseudo[ln] = '\0';
}
void getMessage(char* message) {
size_t ln = -1;
while (ln <= 0 || ln > MESSAGE_MAX-1) {
printf(">");
fgets(message, MESSAGE_MAX, stdin);
ln = strlen(message) - 1;
}
if (message[ln] == '\n')
message[ln] = '\0';
}
void *thread_message(void *arg)
{
printf("Bonjour\n");
char* message;
message = malloc (sizeof(char) * MESSAGE_MAX);
int* sockfd = (int*)arg;
printf("%d\n", *sockfd);
while (1) {
getMessage(message);
if (send(*sockfd, message, strlen(message), 0) == -1){
perror("Client: send message");
}
}
pthread_exit(NULL);
}
int main(int argc, char *argv[])
{
int sockfd, numbytes;
struct sockaddr_in their_addr;
// connector's address information
struct hostent *he;
char buf[MESSAGE_MAX];
long int term1, term2, res;
int demande_pseudo = 0;
char* pseudo;
pseudo = malloc (sizeof(char) * PSEUDO_MAX);
if (argc != 2) {
fprintf(stderr, "Donner le nom du serveur.");
return EXIT_FAILURE;
}
if ((he=gethostbyname(argv[1])) == NULL) {
perror("Client: gethostbyname");
return EXIT_FAILURE;
}
if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
perror("Client: socket");
return EXIT_FAILURE;
}
their_addr.sin_family = AF_INET;
their_addr.sin_port = htons(PORT);
their_addr.sin_addr = *((struct in_addr*)he->h_addr);
memset(&(their_addr.sin_zero), '\0', 8);
if (connect(sockfd, (struct sockaddr *)&their_addr, sizeof(struct sockaddr)) == -1) {
perror("Client: connect");
return EXIT_FAILURE;
}
while (1) {
if ((numbytes=recv(sockfd, buf, MESSAGE_MAX-1, 0)) == -1) {
perror("Client: recv");
return EXIT_FAILURE;
}
if (demande_pseudo == 0) {
buf[numbytes] = '\0';
printf("%s",buf);
getPseudo(pseudo);
printf("Tu as choisi comme pseudo : %s\n", pseudo);
demande_pseudo++;
printf("%d\n", sockfd);
if (send(sockfd, pseudo, strlen(pseudo), 0) == -1){
perror("Client: send pseudo");
return EXIT_FAILURE;
}
pthread_t thread;
if (pthread_create(&thread, NULL, thread_message, &sockfd)) {
perror("pthread_create");
return EXIT_FAILURE;
}
}
else
{
}
}
close(sockfd);
return EXIT_SUCCESS;
}
Thank you so much for your help
First, your question is confusing, try to be more specific giving some examples.
If I understood your question, your problem is that your select is configured to operate on blocking mode.
This is an example on how to set your socket flags to non-blocking mode.
flags = fcntl(sock, F_GETFL, 0);
if(flags < 0)
err(1, "%s: fcntl", __FUNCTION__);
ret = fcntl(sock, F_SETFL, flags | O_NONBLOCK);
if(ret < 0)
err(1, "%s: fcntl:", __FUNCTION__);
Answer Update
Well, one of your problems is that your main function doesn't wait your thread update readfds and max, thus getting blocked on select with the wrong values for those variables. You could solve that by either adding pthread_join(thread, NULL); after you create your thread OR , as I said first, setting your select as non-blocking mode.
With the second method(non-blocking mode) there will be times you
have nothing to process from select so you need to handle this and not crash. I would use that.
Using the first method (pthread_join) you'll not be able to process incoming
requests while waiting for your thread to finish,hence invalidating the whole purpose of having threads: being available to process incoming requests.
Try to develop those ideas and you'll make that code work! (:
Client code
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdio.h>
int main ()
{
struct sockaddr_in server ;
struct socklen_t;
int sockid,status,count,count1 ;
char buffer[1024];
char buffer1[1024];
/* socket */
sockid = socket( AF_INET, SOCK_STREAM,0);
if (sockid == -1)
{
printf("could not create socket");
}
else
{
printf(" socket created\n");
}
memset((char *) &server, 0, sizeof(server));
server.sin_addr.s_addr = inet_addr("127.0.0.1");
server.sin_family =AF_INET;
server.sin_port = htons(20143);
/* connection */
status = connect(sockid ,(struct sockaddr *)&server, sizeof(struct sockaddr));
if (status == -1)
{
printf ("error in connection\n ");
}
else
{
printf("no error \n");
}
/* send*/
strcpy(buffer, "hello \n"),
printf("message: %s\n", buffer);
if(send(sockid, buffer ,strlen("buffer"),0) < 0 )
{
puts("sends failed");
return 1;
}
puts("data send");
/* receive
count1 = recv(sockid,,buf,0 );*/
if(recv(sockid, buffer1, 1024, 0) < 0 )
{
puts("receive failed ");
return 1;
}
puts("receive success");
puts(buffer1);
/*---- Print the received message ----*/
printf("Data received: %s",buffer1);
close (sockid);
}
server code is
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
struct sockaddr_in server ;
struct socklen_t ;
int s,sockid,status;
char buffer[1024];
char buffer1[1024];
/* socket */
sockid = socket(AF_INET, SOCK_STREAM,0);
if(sockid == -1)
{
printf("could not create socket");
}
{
printf(" socket created\n");
}
memset((char *)&server, 0, sizeof(server));
server.sin_addr.s_addr =inet_addr("127.0.0.1");
server.sin_family = AF_INET;
server.sin_port = htons(20143);
if((bind(sockid,(struct sockaddr *)&server, sizeof(struct sockaddr)))== -1)
{
puts("failure ");
return 1;
}
puts("success");
listen(sockid,5);
s = accept(sockid,(struct sockaddr *)&server, (socklen_t *)sizeof(server));
if(recv(sockid,buffer, 1024, 0)< 0 )
{
puts("receive failed ");
return 1;
}
puts("receive success");
puts(buffer1);
/*---- Print the received message ----*/
printf("Data received: %s",buffer);
enter code here
strcpy(buffer1,"Hello World\n");
if(send(sockid,buffer1,13,0) < 0 )
{
puts("failed ");
return 1;
}
puts("success");
close (sockid);
}
here i am trying to make two way connection between client and the server but i am unbale to finish it beacuse i am facing the problem of bind that is server did not bind with the client, every time it show error in binding . plz provide me the sufficient solution for that ..
Here you have a way to do sockets in "C", Comments are in Spanish but I hope it helps.
Link to my Github: https://github.com/MarcosAguayo/sockets-c
Client
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
/**
* Función que usa socket INET para conectarse con un servidor.
* #params char *hostServer, char *service
* #return res
*/
int abrirConexion (char *hostServer, char *service){
struct sockaddr_in dir;
struct servent *puerto;
struct hostent *host;
int res;
puerto = getservbyname (service, "tcp");
if(puerto == NULL) return -1;
host = gethostbyname (hostServer);
if(host == NULL) return -1;
dir.sin_family = AF_INET;
dir.sin_addr.s_addr = ((struct in_addr *)(host->h_addr))->s_addr;
dir.sin_port = puerto->s_port;
res = socket (AF_INET, SOCK_STREAM, 0);
if(res == -1) return -1;
if(connect (res, (struct sockaddr *)&dir, sizeof (dir)) == -1){
return -1;
}
return res;
}
/**
* Función para leer los datos del socket. Devuelve el total de bytes que
* ha leído, un -1 si da algun error o un 0 si se cierra.
* #params int fd, char *data, int longitud
* #return total
*/
int leerSocket (int fd, char *data, int longitud){
int total = 0;
int temp = 0;
// Validación de los parámetros de entrada
if ((fd == -1) || (data == NULL) || (longitud < 1)) return -1;
// Bucle que se ejecuta siempre que no hayamos leido todos los datos
while (total < longitud){
temp = read (fd, data + total, longitud - total);
if (temp > 0){
// Si se han leido los datos incrementamos la variable que después devolveremos
total = total + temp;
}else{
// Si devuelve 0, es que se ha cerrado el socket por lo que terminamos u devolvemos total
if (temp == 0) return total;
if (temp == -1){
switch (errno){
case EINTR:
case EAGAIN:
usleep (100);
break;
default:
return -1;
}
}
}
}
return total;
}
/**
* Escribe datos en el socket del cliente y devuelve el total de bytes que ha escrito
* #params int fd, char *data, int longitud
* #return num (Total bytes escritos) o -1
*/
int escribirSocket (int fd, char *data, int longitud){
int num = 0;
int temp = 0;
// Validar los parámetros
if ((fd == -1) || (data == NULL) || (longitud < 1)) return -1;
while (num < longitud){
temp = write (fd, data + num, longitud - num);
if (temp > 0){
num = num + temp;
}else{
if (temp == 0)
return num;
else
return -1;
}
}
return num;
}
/**
* Función MAIN
*/
void main (void){
int socketServer;
char cad[100];
// Abrimos la conexión con el server pasandole "localhost" y el nombre del servicio (/etc/services)
socketServer = abrirConexion ("localhost", "aguayo");
if (socketServer == 1){
printf ("No puedo establecer conexion con el servidor\n");
exit (-1);
}
strcpy(cad, "Hola");
escribirSocket(socketServer, cad, 5);
leerSocket (socketServer, cad, 6);
printf ("Hola buenas soy el cliente y he recibido: %s\n", cad);
close (socketServer);
}
Server
#include <string.h>
#include <stdlib.h>
#include <netdb.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <sys/un.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
/**
* Función para aceptar la conexion del socket
* #param int res
* #return int ch
*/
int aceptarConexion (int res){
socklen_t long_cl;
struct sockaddr cl;
int ch;
long_cl = sizeof (cl);
ch = accept (res, &cl, &long_cl);
if (ch == -1)return -1;
return ch;
}
/**
* Función que usa socket INET
* #params char *servicio
* #return res
*/
int abrirConexion (char *servicio){
struct sockaddr_in dir;
struct sockaddr cl;
struct servent *puerto;
socklen_t long_cl;
int res;
res = socket (AF_INET, SOCK_STREAM, 0);
if (res == -1) return -1;
// obtenemos el servicio del fichero /etc/services
puerto = getservbyname (servicio, "tcp");
if (puerto == NULL) return -1;
// Se comletan los campos de la estructura
dir.sin_family = AF_INET;
dir.sin_port = puerto->s_port;
dir.sin_addr.s_addr =INADDR_ANY;
if (bind (res, (struct sockaddr *)&dir, sizeof (dir)) == -1){
close (res);
return -1;
}
if (listen (res, 1) == -1){
close (res);
return -1;
}
return res;
}
/**
* Función para leer los datos del socket. Devuelve el total de bytes que
* ha leído, un -1 si da algun error o un 0 si se cierra.
* #params int fd, char *data, int longitud
* #return num
*/
int leerSocket (int fd, char *data, int longitud){
int num = 0;
int temp = 0;
// Validación de los parámetros de entrada
if ((fd == -1) || (data == NULL) || (longitud < 1)) return -1;
// Bucle que se ejecuta siempre que no hayamos leido todos los datos
while (num < longitud){
temp = read (fd, data + num, longitud - num);
if (temp > 0){
num = num + temp;
}else{
if (temp == 0) return num;
if (temp == -1){
switch (errno){
case EINTR:
case EAGAIN:
usleep (100);
break;
default:
return -1;
}
}
}
}
return num;
}
/**
* Escribe datos en el socket del cliente y devuelve el total de bytes que ha escrito
* #params int fd, char *data, int longitud
* #return total (Total bytes escritos) o -1
*/
int escribirSocket (int fd, char *data, int longitud){
int total = 0;
int temp = 0;
// Validar los parámetros
if ((fd == -1) || (data == NULL) || (longitud < 1)) return -1;
while (total < longitud){
temp = write (fd, data + total, longitud - total);
if (temp > 0){
total = total + temp;
}else{
if (temp == 0) return total;
else return -1;
}
}
return total;
}
/**
* Función MAIN
*/
void main (void){
int socketServer;
int socketClient;
char cad[100];
socketServer = abrirConexion ("aguayo");
if (socketServer == -1){
printf ("No se puede abrir socket servidor\n");
exit (-1);
}
socketClient = aceptarConexion (socketServer);
if (socketServer == -1){
printf ("No se puede abrir socket de cliente\n");
exit (-1);
}
leerSocket (socketClient, cad, 5);
printf ("Soy el Servidor y he recibido: %s\n", cad);
strcpy (cad, "Adios");
escribirSocket (socketClient, cad, 6);
close (socketClient);
close (socketServer);
}
This is the server part of a chat client server program i wrote. I create a pool of thread and the server must associated a a connected client to a thread. The thread function gestisci() receives commands from clients and sends messages from client1 to client2. But, once i run it, there is nothing appearing on the terminal. Can someone help me?
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include<sys/wait.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<pthread.h>
#define BACKLOG_SIZE 5
#define SA struct sockaddr
void* gestisci_richiesta(void*dati)
int main(int argc, char* argv[]) {
printf("in main function\n");
struct sockaddr_in srv_addr, cl_addr;
int ret, sock, cn_sk, porta, t;
struct argomenti{
int sock_cl,stato;
struct sockaddr_in cl_addr;
int index;}
struct argomenti mess[BACKLOG_SIZE];
int arg_cont[BACKLOG_SIZE];
socklen_t len;
int t_free[BACKLOG_SIZE];
pthread_t tid[BACKLOG_SIZE];
if (argc < 2)
printf("errore:inserire numero porta\n");
porta = atoi(argv[1]);
printf(" %d\n", porta);
sock = socket(PF_INET, SOCK_STREAM, 0);
if (sock == -1) {
printf("server: impossibile creare un nuovo socket.\n");
return 0;
}
memset(&srv_addr, 0, sizeof(srv_addr));
srv_addr.sin_family = AF_INET;
srv_addr.sin_addr.s_addr = htonl(INADDR_ANY );/* il server si mette in ascolto suqualsiasi delle sueinerfacce di rete*/
srv_addr.sin_port = htons(porta);
ret = bind(sock, (SA*) &srv_addr, sizeof(srv_addr));
if (ret == -1) {
printf("server : impossibile eseguire il bind sul socket.\n");
return 0;
}
printf("bind con successo\n");
listen(sock, BACKLOG_SIZE);
for (t = 0; t < BACKLOG_SIZE; t++) {
t_free[t] = 0;
client[t] = 0;
}
t= 0;
while (1) {
while (t_free[t] != 0)
t = (t + 1) % BACKLOG_SIZE;
t_free[t] = 1;
len = (socklen_t) sizeof(mess[t].cl_addr);
cn_sk = accept(sock, (SA*) &mess[t].cl_addr, &len);
mess[t].sock_cl = cn_sk;
mess[t].index = t;
printf("client:%d connesso\n", t);
if (cn_sk == -1) {
printf("SERVER: errore in attesa di connessione\n");
return 0;
}
if (pthread_create(&tid[t], 0, gestisci_richiesta, (void*) &mess[t])) {
printf("server:impossibile avviare un thread dal pool\n");
return 0;
}
}
}
You are missing \n's on several of those printfs, which will cause them to be buffered instead of printing out immediately.
Other problems exist. Your error message where you call socket() is misleading. There has been no attempt yet to use the port specified. That happens at the bind(). There is no reason to assume the number of clients will equal the backlog size. The size of a sockaddr_in is always the same: no need to recalculate it each time.
you should move t = 0; before while(1).
I'm developing in C a Unix application consisting of a server that has to communicate simultaneously with at most five clients. Clients send to server a command which can be tuttomaiuscolo (alltoupper in english) or tuttominuscolo (alltolower) and a string to manipulate; the server receives the two strings and remove from the second word all the characters that are not a-z A-Z characters. If a client sends the string FINE (end) the server has to stop and die (whitout leaving zombie processes).
The problem is the connection between the client and the server. To do this I've used the function select in server and in client too, but the problem is that the select placed in the server (that monitors the reading) doesn't see the client request, so it never goes to the accept function, while the client select (that monitors the writing) returns a value that means it is ready for writing.
Now I'll post the code:
server:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <signal.h>
#include <wait.h>
#include <ctype.h>
void ripulisci (char* stringa);
void minuscola (char* orig, char* dest);
void maiuscola (char* orig, char* dest);
void handler(int);
int list;
int sock;
int main () {
int status;
//creo un socket da mettere in ascolto
list = socket (AF_INET, SOCK_STREAM, 0);
if (list < 0) {
perror("Error!");
exit(1);
}
//preparo la struct sockaddr_in
struct sockaddr_in address;
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(2770);
//effettuo il bind
status = bind(list, (struct sockaddr*) &address, sizeof(address));
if (status < 0) {
perror("Error!");
close(list);
exit(1);
}
//mi metto in ascolto
listen(list, 1);
printf("Attendo le connessioni...\n");
//preparo le variabili necessarie per gestire i figli
int esci = 1;
pid_t server[5];
char comando[15];
char lettura[512];
char scrittura[512];
struct sockaddr_in client;
int client_size = sizeof(client);
fd_set fd;
FD_ZERO(&fd);
FD_SET(list, &fd);
struct timeval timer;
//genero i quattro figli/server e mi salvo i pid in un array
int index;
for (index=0 ; index<5 ; index++) {
server[index] = fork();
if (server[index] == 0)
break;
}
//verifico quale processo sono
if (index == 5) {
pause(); //aspetto un segnale da uno dei figli
}
//sono un figlio/server
else {
while(esci) {
timer.tv_sec = 1;
timer.tv_usec = 0;
if (select(list+1, &fd, NULL, NULL, &timer) <= 0) {
printf("Nessun client da servire\n");
continue;
}
if (!FD_ISSET(list, &fd))
continue;
printf("C'è un client\n");
sock = accept(list, (struct sockaddr*) &client, (socklen_t*) &client_size);
if (sock < 0)
break;
printf("Connesso con il client\n");
recv(sock, comando, 15, 0);
recv(sock, lettura, 512, 0);
if (comando[0] == 'F' && comando[1] == 'I' && comando[2] == 'N' && comando[3] == 'E' && comando[4] == '\0')
kill(getppid(), SIGALRM); //al termine dell'esecuzione uscirò
ripulisci(lettura);
//il comando è tuttomaiuscole
if (strcmp("tuttomaiuscolo", comando) == 0) {
maiuscola(lettura, scrittura);
send(sock, scrittura, 512, 0);
}
//il comando è tuttominuscole
else if (strcmp("tuttominuscolo", comando) == 0) {
minuscola(lettura, scrittura);
send(sock, scrittura, 512, 0);
}
//c'è stato un errore
else {
printf ("Error! Command not found\n");
strcpy (scrittura, "error");
send (sock, scrittura, 512, 0);
}
printf("Devo terminare!");
close(sock);
exit(0);
}
}
//termino tutto
for(index=0 ; index<5 ; index++) {
waitpid((int)server[index], NULL, 0);
}
exit(0);
}
void handler(int sig) {
signal(sig, SIG_IGN);
printf("Il server sta terminando in seguito ad una richiesta\n");
close (list);
close (sock);
exit(0);
}
void ripulisci (char* stringa) {
int index = 0;
int app;
while (stringa[index] != '\0' && index<=511) {
if (isalpha(stringa[index])!=1) {
app = index;
do {
stringa[app] = stringa[app+1];
app++;
} while (stringa[app] != '\0');
stringa[app] = '\0';
index--;
}
index++;
}
return;
}
void minuscola (char* orig, char* dest) {
int index = 0;
do {
if (orig[index] < 91)
dest[index] = toupper(orig[index]);
else
dest[index] = orig[index];
index++;
} while (orig[index] != '\0');
dest[index] = '\0';
return;
}
void maiuscola (char* orig, char* dest) {
int index = 0;
do {
if (orig[index] > 91)
dest[index] = tolower(orig[index]);
else
dest[index] = orig[index];
index++;
} while (orig[index] != '\0');
dest[index] = '\0';
return;
}
client:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <time.h>
int main () {
int descrittoreSocket;
descrittoreSocket = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in address;
address.sin_family = AF_INET;
address.sin_port = htons(2770);
address.sin_addr.s_addr = INADDR_ANY;
printf ("Connessione in corso...\n");
int ris;
ris = connect(descrittoreSocket, (struct sockaddr*) &address, (socklen_t) sizeof(address));
fd_set fd;
FD_ZERO(&fd);
FD_SET(descrittoreSocket, &fd);
struct timeval timer;
timer.tv_sec = 1;
timer.tv_usec = 0;
if ((ris > -1) && select(descrittoreSocket+1, NULL, &fd, NULL, &timer) >= 0 && FD_ISSET(descrittoreSocket, &fd)) {
printf ("Connessione avvenuta...\n");
char buffer_r [512];
char buffer_w [512];
char command [15];
gets(command);
gets(buffer_r);
send(descrittoreSocket, command, 15, 0);
printf("Spedito!");
fflush(stdout);
send(descrittoreSocket, buffer_w, 512, 0);
printf("Spedito!");
fflush(stdout);
recv(descrittoreSocket, buffer_r, 512, 0);
printf("Trasferito!");
fflush(stdout);
if (strcmp("error", buffer_r) == 0)
printf ("ERROR!");
printf ("%s", buffer_r);
fflush(stdout);
} else {
printf ("Impossibile servire il client\n");
}
close (descrittoreSocket);
exit(0);
}
With syntax higligh:
server: http://pastebin.com/5Nd96JxC
client: http://pastebin.com/aSvR6qVM
Please don't hesitate to ask for clarifications if needed.
Your server shouldn't need to use select with only one listening socket ... instead it should listen for a connection on the listening socket for a client, and when there's a connection, accept it, and then read from the socket the command given by the client. If you want to process more than one request from a client at a time, then you can spin off a separate process or thread for each accepted connection. If you want to avoid blocking behavior during the call to accept by the listening socket, then you can always use ioctl with the FIONBIO flag on the listening socket.
On the client side I also don't see a need for select ... again, there is only one socket on the server to talk to. Simply open a connection on the server, which will block until a connection is made, and when that connection is made, you can read and write to the server.