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).
Related
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int port = 3008;
int listenfd;
extern void makelistener();
int main(int argc, char **argv)
{
makelistener();
int clientfd, nready;
socklen_t len;
struct sockaddr_in q;
int i;
// initialize allset and add listenfd to the
// set of file descriptors passed into select
fd_set allset;
fd_set rset;
int maxfd;
FD_ZERO(&allset);
FD_SET(listenfd, &allset); // set of file descriptors
maxfd = listenfd;
int ret;
while (1)
{
// make a copy of the set before we pass it into select
rset = allset;
/*select will wait until an exceptional event occurs when tv is NULL*/
nready = select(maxfd + 1, &rset, NULL, NULL, NULL);
if (nready == 0) {
continue;
}
if (nready == -1) {
perror("select");
continue;
}
//FD_ISSET returns 1 when a new connection is attempted
if(FD_ISSET(listenfd, &rset)){
//printf("a new client is connecting\n");
len = sizeof(q); //accept connection of listenfd stream socket
if ((clientfd = accept(listenfd, (struct sockaddr *)&q, &len)) < 0) {
perror("accept");
exit(1);
}
FD_SET(clientfd, &allset);
if (clientfd > maxfd) {
maxfd = clientfd;
}
static char msg[] = "What is your name?\r\n";
write(clientfd, msg, sizeof msg - 1);
printf("connection from %s\n", inet_ntoa(q.sin_addr));
char buf[256];
ret = read(clientfd, buf, sizeof(buf));
buf[ret] = '\0';
printf("%s", buf);
}
}
}
void makelistener()
{
struct sockaddr_in r;
if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket");
exit(1);
}
memset(&r, '\0', sizeof r);
r.sin_family = AF_INET;
r.sin_addr.s_addr = INADDR_ANY;
r.sin_port = htons(port);
if (bind(listenfd, (struct sockaddr *)&r, sizeof r)) {
perror("bind");
exit(1);
};
if (listen(listenfd, 5)) {
perror("listen");
exit(1);
}
}
above code is for the server and it does this
$ ./above.c
(does nothing but runs forever)
How to connect as a client:
$ nc 127.0.0.1 3000
What is your name?
(waiting for my input) so if I put bob, it would output it to the server
It works as intended. But I want it too work concurrently with multiple clients.
for example:
server
$ ./above.c
(does nothing but runs forever)
client1
$ nc 127.0.0.1 3000
What is your name?
client 2
$ nc 127.0.0.1 3000
What is your name? (Currently client2 wont show up until client1 is answered which is what I'm trying to fix)
How do I make it so the clients can run concurrently without waiting for the first client to finish? To explain the code a little bit, listener just binds and listens to a connection. Inside the while(1) is where select and calls are.
How do I make it so the clients can run concurrently without waiting for the first client to finish?
By paying attention to which sockets select() reports to you. You are asking select() to monitor multiple sockets for readability, but you are only checking if the listening socket is readable, you are not checking the client sockets. You need to keep track of the connected clients so you can enumerate them when needed.
Try something like this:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int port = 3008;
#define MAX_CLIENTS (FD_SETSIZE - 1)
int listenfd = -1;
extern void makelistener();
int main(int argc, char **argv)
{
int clientfd, nready;
socklen_t len;
struct sockaddr_in q;
int i, j, ret;
fd_set allset;
fd_set rset;
int clients[MAX_CLIENTS];
int num_clients = 0;
int maxfd;
char buf[256];
makelistener();
// initialize allset and add listenfd to the
// set of file descriptors passed into select
FD_ZERO(&allset);
FD_SET(listenfd, &allset);
maxfd = listenfd;
while (1)
{
// make a copy of the set before we pass it into select
FD_COPY(&allset, &rset);
// select will wait until an exceptional event occurs when tv is NULL
nready = select(maxfd + 1, &rset, NULL, NULL, NULL);
if (nready < 0) {
perror("select");
continue;
}
if (nready == 0) { // should never happen since no timeout was requested
continue;
}
//FD_ISSET returns 1 when a socket is readable
if (FD_ISSET(listenfd, &rset)) {
//printf("a new client is connecting\n");
len = sizeof(q); //accept connection of listenfd stream socket
if ((clientfd = accept(listenfd, (struct sockaddr *)&q, &len)) < 0) {
perror("accept");
exit(1);
}
printf("Client %d connected from %s\n", clientfd, inet_ntoa(q.sin_addr));
if (num_clients == MAX_CLIENTS) {
static char msg[] = "Max number of clients are already connected\r\n";
write(clientfd, msg, sizeof(msg)-1);
close(clientfd);
}
else {
static char msg[] = "What is your name?\r\n";
if (write(clientfd, msg, sizeof(msg)-1) < 0) {
close(clientfd);
}
else {
clients[num_clients++] = clientfd;
FD_SET(clientfd, &allset);
if (clientfd > maxfd) {
maxfd = clientfd;
}
}
}
}
for (i = 0; i < num_clients; ++i) {
clientfd = clients[i];
if (!FD_ISSET(clientfd, &rset)) {
continue;
}
ret = read(clientfd, buf, sizeof(buf));
if (ret <= 0) {
//printf("a client has disconnected\n");
close(clientfd);
FD_CLR(clientfd, &allset);
for (j = i + 1; j < num_clients; ++j) {
clients[j-1] = clients[j];
}
--num_clients;
if (clientfd == maxfd) {
maxfd = listenfd;
for (j = 0; j < num_clients; ++j) {
if (clients[j] > maxfd) {
maxfd = clients[j];
}
}
}
--i;
continue;
}
printf("Client %d: %.*s", clientfd, ret, buf);
}
}
return 0;
}
Note that poll() or epoll() would generally be a better choice to use than select().
How do I make it so the clients can run concurrently without waiting for the first client to finish?
every time that the call to accept() returns, start a thread pthread_create() to handle the actual communication with the client.
Note: creating/destroying a thread is very time consuming, so suggest learning about thread pools and how to use them.
When using threads, there is no call to select() (nor poll()) Rather the main function gets blocked on the call to accept() and when that function returns, pass the associated socket to a thread to handle
There are lots of example code for how a server should communicate with multiple clients on stackoverflow.com
I have to type two strings in a client and send them with a struct to server. Then the server does c = a + b and sends a news struct with { a, b, c } to client. If a or b received is quit, server sends to client bye.
Client receives the struct and prints c. If it is bye it closes connection, else it returns to asking the input of a and b and the cycle begins again.
Client:
#if defined WIN32
#include <Winsock2.h>
#else
#define closesocket close
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFSIZE 30
void ClearWinSock() {
#if defined WIN32
WSACleanup();
#endif
}
//-----------------------------INIZIALIZZAZIONE WSADATA
int main (void) {
#if defined WIN32
WSADATA wsaData;
int iResult = WSAStartup (MAKEWORD (2,2), &wsaData);
if (iResult !=0) {
printf ("error at WSASturtup\n");
return 0;
}
#endif
//--------------------------------CREAZIONE SOCKET
int Csocket;
Csocket = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (Csocket < 0) {
printf ("socket creation failed");
closesocket (Csocket);
ClearWinSock();
return 0;
}
char s_address[BUFSIZE];
printf ("Inserisci l'indirizzo dell'host a cui connetterti\n");
scanf ("%s", s_address);
int port;
printf ("Inserisci la porta a cui connetterti\n");
scanf("%d", &port);
struct sockaddr_in sad;
memset (&sad, 0, sizeof(sad));
sad.sin_family = AF_INET;
sad.sin_addr.s_addr = inet_addr(s_address);
sad.sin_port = htons (port);
//------------------------------CONNESSIONE AL SERVER
if (connect(Csocket, (struct sockaddr*) &sad, sizeof(sad)) < 0) {
printf ("failed to connect\n");
closesocket (Csocket);
ClearWinSock();
return 0;
}
//-----------------------------RICEZIONE STRINGA DAL SERVER
char buf[BUFSIZE];
int read = recv (Csocket, buf, BUFSIZE - 1, 0);
if (read <=0) {
printf ("Qualcosa non và!\n");
}
else {
buf[read] = '\0'; //tappo stringa per sicurezza
printf("Server scrive: %s\n", buf);
}
//------------------------------STRUTTURA DI STRINGHE
struct stringab {
char a[30];
char b[30];
char c[70];
} ab;
void* abptr = &ab;
printf ("Inserisci prima stringa\n");
scanf ("%s", ab.a);
printf ("Inserisci seconda stringa\n");
scanf ("%s", ab.b);
if (send(Csocket, (char*)abptr, sizeof(ab), 0) != sizeof(ab)) {
printf("client-send() sent a different number of bytes than expected");
closesocket(Csocket);
ClearWinSock();
system ("pause");
return 0;
}
printf ("\n");
closesocket (Csocket);
system ("pause");
ClearWinSock();
return 0;
}
Server:
#if defined WIN32
#include <Winsock2.h>
#else
#define closesocket close
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFSIZE 30
void ClearWinSock() {
#if defined WIN32
WSACleanup();
#endif
}
int main(void) {
//---------------------------INIZIALIZZAZIONE WSADATA
#if defined WIN32
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) {
printf ("Error at WSAStartup");
return 0;
}
#endif
//-------------------------------CREAZIONE SOCKET
int Mysocket;
Mysocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
//Valutare la presenza di errori per assicurarsi che la socket sia valida.
if (Mysocket < 0) {
printf("socket creation failed\n");
return 0;
}
//Assegnazione indirizzo alla socket.
struct sockaddr_in sad;
memset(&sad, 0, sizeof(sad));
sad.sin_family = AF_INET;
sad.sin_addr.s_addr = inet_addr ("127.0.0.1");
sad.sin_port = htons (9888);
//------------------------ASSEGNAZIONE PORTA E IP ALLA SOCKET
if (bind(Mysocket, (struct sockaddr*) &sad, sizeof(sad)) < 0) {
printf ("bind() failed\n");
closesocket(Mysocket);
return 0;
}
//---------------------------SETTAGGIO SOCKET ALL'ASCOLTO
int qlen = 10; //numero client che il server può gestire
if (listen (Mysocket, qlen) < 0) {
printf("listen() failed\n");
closesocket(Mysocket);
return 0;
}
struct sockaddr_in cad; // struttura per l'indirizzo del cient
int Csocket; // descrittore socket per il client
int clientlen; // lunghezza indirizzo del client
//------------------------------ACCETTA LA CONNESSIONE
while (1) {
printf("In attesa di un client con cui comunicare...\n");
memset(&cad, 0, sizeof(cad));
clientlen = sizeof(cad); // assegna la dimensione dell'indirizzo del client
if((Csocket = accept(Mysocket, (struct sockaddr*) &cad, &clientlen)) < 0) {
printf ("accept failed\n");
closesocket(Mysocket);
ClearWinSock();
return 0;
}
printf("Connessione stabilita con il client il cui indirizzo e' %s \n\n", inet_ntoa(cad.sin_addr));
//---------------------------------------INVIO STRINGA AL CLIENT
char* inputString = "Connessione avvenuta!";
int stringlen = strlen(inputString);
if (send(Csocket, inputString, stringlen, 0) != stringlen) {
printf("client-send() sent a different number of bytes than expected");
closesocket(Csocket);
ClearWinSock();
system ("pause");
return 0;
}
printf ("\n");
closesocket (Csocket);
system ("pause");
ClearWinSock();
return 0;
}
So, did I send the struct to server in this manner? How the server could recv() this struct and do c = a + b re-building and re-sending the struct?
I solved the problem on send side and receive side like this:
send(Csocket, (char*)abptr, sizeof(ab), 0);
recv (Csocket, (char*)abptr, sizeof(ab), 0);
So I passed the struct with a struct pointer on both side. I think it's a good solution in local hosting, maybe you need a better one for net (security reasons).
I don't know whether the problem is with the client or with the server or both.This is my first client-server socket programming code. But this is not working as expected. The code which I referenced is working well although.
When the code runs, the client and server should both exchange 2 messages, but they are not doing so. The server is displaying "Listening" which is right as expected but when I run the client code, Nothing happens, It just displays nothing.
This is the client code
#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
int main() {
struct sockaddr_in mysocket, servsocket;
int err;
char buf[256];
//CREATING SOCKET
int socketstatus = socket(AF_INET, SOCK_STREAM, 0);
printf("%d\n", socketstatus);
if(socketstatus < 0){
printf("socket failed\n");
scanf("%d", &err);
return 0;
}
bzero((char *) &mysocket, sizeof(mysocket));
mysocket.sin_family = AF_INET;
mysocket.sin_addr.s_addr = inet_addr("127.0.0.2");
int port = 5674;
mysocket.sin_port = htons(port);
//CONNECT
int connectstatus = connect(socketstatus, (struct sockaddr *) &servsocket, sizeof(servsocket));
if(connectstatus < 0){
printf("Connect failed\n");
scanf("%d", &err);
return 0;
}
//SEND
bzero(buf, 256);
strcpy(buf, "Message sent by client");
int sendstatus = send(socketstatus, buf, 256, 0);
printf("2\n"); //This is not being displayed
if(sendstatus < 0){
printf("Client send failed\n");
return 0;
}
printf("Reached for receiving\n");
//RECEIVE
bzero(buf, 256);
int recvstatus = recv(socketstatus, buf, 256, 0);
if(recvstatus < 0){
printf("Client RECEIVE failed\n");
scanf("%d", &err);
return 0;
}
printf("The message client got from server is, %s \n",buf );
scanf("%d", &err);
printf("Bye");
}
And this is the server code:
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
int main() {
int err;
struct sockaddr_in servsocket, clientsocket;
char sendmessage[256];
//CREATING SOCKET
int mysocket = socket(AF_INET, SOCK_STREAM, 0);
if(mysocket < 0){
printf("socket creation failed\n");
scanf("%d", &err);
return 0;
}
bzero((char*) &servsocket, sizeof(servsocket)); //initiazlizing servsocket with null
servsocket.sin_family = AF_INET;
servsocket.sin_addr.s_addr = inet_addr("127.0.0.2");
int port = 5674;
servsocket.sin_port = htons(port);
//BINDING
int bindstatus = bind(mysocket, (struct sockaddr*) &servsocket, sizeof(servsocket));
if(bindstatus < 0){
printf("Socket bind failed\n");
scanf("%d", &err);
return 1;
}
//LISTENING
int listenstatus = listen(mysocket, 5);
if(listenstatus < 0){
scanf("%d", &err);
return 2;
}
else
printf("LISTENING....\n");
//ACCEPTING
int clientsize = sizeof(clientsocket);
int acceptstatus = accept(mysocket, (struct sockaddr*) &clientsocket, &clientsize);
if(acceptstatus < 0){
printf("Accept failed");
scanf("%d", &err);
return 3;
}
char buf[256];
bzero(buf, 256);
//RECEIVING
int recvstatus = recv(acceptstatus, buf, 256, 0);
if(buf < 0){
printf("Error:Nothing read");
scanf("%d", &err);
return 4;
}
printf("I received this message, %s \n", buf);
printf("NOW I WILL SEND\n");
//SENDING
bzero(sendmessage, 256);
strcpy(sendmessage, "Message sent by server");
int sendstatus = send(acceptstatus, sendmessage, sizeof(sendmessage), 0);
if(sendstatus < 0){
printf("Error sending\n");
scanf("%d", &err);
return 5;
}
return 0;
}
In the client code, you initialize mysocket but pass serversocket to connect uninitialized.
You should be setting the fields of serversocket instead of mysocket.
You want to connect to the server socket inside your client (that would be serversocket in your code, not mysocket):
bzero((char *) &servsocket, sizeof(servsocket));
servsocket.sin_family = AF_INET;
servsocket.sin_addr.s_addr = inet_addr("127.0.0.2");
int port = 5674;
servsocket.sin_port = htons(port);
Then, I think you want your inet address to be 127.0.0.1 (what is typically default localhost address), not 127.0.0.2.
The code was "working" because you were passing a correct socket descriptor (socketstatus) to it is not correctly connected to the endpoint, so it fails on the send() call.
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! (:
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.