How to connect clients two by two as they connect












0















I'm facing a problem with sockets programming in C.
I've coded a server where multiple clients can connect and send messages in a chatroom but i don't know how to connect two clients two by two.



example:
Client A connect to the Server but must wait in a queue waiting for Client B to connect.
Client C connect but must wait in a queue waiting for Client D to connect.



Every pair of clients must be in their specific chatroom, do I need to share the fd between the two sockets of the 2 clients or link between the two sockets.



I thought about using another way by using the function accept() twice before I fork() but I have to use child processes for that.



Here is my server code:



#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

#define PORT "8888"


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)
{
fd_set master;
fd_set read_fds;
int fdmax;

int listener;
int newfd;
struct sockaddr_storage remoteaddr;
socklen_t addrlen;

char buf[256];
int nbytes;

char remoteIP[INET6_ADDRSTRLEN];

int yes=1;
int i, j, rv;

struct addrinfo hints, *ai, *p;

FD_ZERO(&master);
FD_ZERO(&read_fds);


memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
if ((rv = getaddrinfo(NULL, PORT, &hints, &ai)) != 0) {
fprintf(stderr, "Server msg: %sn", gai_strerror(rv));
exit(1);
}

for(p = ai; p != NULL; p = p->ai_next)
{
listener = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (listener < 0) {
continue;
}

setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));

if (bind(listener, p->ai_addr, p->ai_addrlen) < 0) {
close(listener);
continue;
}

break;
}

if (p == NULL) {
fprintf(stderr, "Server msg: bind failedn");
exit(2);
}

freeaddrinfo(ai);

puts("Bind success");

if (listen(listener, 10) == -1)
{
perror("listen");
exit(3);
}
puts("Server listening ...");


FD_SET(listener, &master);


fdmax = listener;


for(;;)
{
read_fds = master;
if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1)
{
perror("select");
exit(4);
}


for(i = 0; i <= fdmax; i++)
{
if (FD_ISSET(i, &read_fds))
{
if (i == listener)
{

addrlen = sizeof remoteaddr;
newfd = accept(listener,
(struct sockaddr *)&remoteaddr,
&addrlen);

if (newfd == -1)
{
perror("accept");
}
else
{
FD_SET(newfd, &master);
if (newfd > fdmax)
{
fdmax = newfd;
}
printf("Server msg: new connection from %s on "
"socket %dn", inet_ntop(remoteaddr.ss_family,
get_in_addr((struct sockaddr*)&remoteaddr),
remoteIP, INET6_ADDRSTRLEN), newfd);
}
}
else
{

if ((nbytes = recv(i, buf, sizeof buf, 0)) <= 0)
{
if (nbytes == 0)
{
printf("Server msg: socket %d lostn", i);
}
else
{
perror("recv");
}
close(i);
FD_CLR(i, &master);
}
else
{

for(j = 0; j <= fdmax; j++)
{

if (FD_ISSET(j, &master))
{

if (j != listener && j != i)
{
if (send(j, buf, nbytes, 0) == -1)
{
perror("send");
}
}
}
}
}
}
}
}
}

return 0;
}


And here is my client code:



#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#include <arpa/inet.h>

#define PORT "8888"

#define MAXDATASIZE 100
#define MAXNAMESIZE 25

void *receive_handler(void *);

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(int argc, char *argv)
{
char message[MAXDATASIZE];
char nickName[MAXNAMESIZE];
int sockfd;
char sBuf[MAXDATASIZE];
struct addrinfo hints, *servinfo, *p;
int rv;
char s[INET6_ADDRSTRLEN];

if (argc != 2) {
fprintf(stderr,"Usage: ./client addressn");
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: %sn", gai_strerror(rv));
return 1;
}


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: connection failedn");
return 2;
}

inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr),
s, sizeof s);
printf("Client: connection to %sn", s);

freeaddrinfo(servinfo);

puts("Give your username:");
memset(&nickName, sizeof(nickName), 0);
memset(&message, sizeof(message), 0);
fgets(nickName, MAXNAMESIZE, stdin);
pthread_t recv_thread;

if( pthread_create(&recv_thread, NULL, receive_handler, (void*)(intptr_t) sockfd) < 0)
{
perror("Failed on thread creation");
return 1;
}
puts("Connection established");

puts("Welcome!n");
puts("[Type '/quit' to quit the chatroom]");

for(;;)
{
char temp[6];
memset(&temp, sizeof(temp), 0);

memset(&sBuf, sizeof(sBuf), 0);
fgets(sBuf, 100, stdin);

if(sBuf[0] == '/' &&
sBuf[1] == 'q' &&
sBuf[2] == 'u' &&
sBuf[3] == 'i' &&
sBuf[4] == 't')
return 1;


int count = 0;
while(count < strlen(nickName))
{
message[count] = nickName[count];
count++;
}
count--;
message[count] = ':';
count++;

for(int i = 0; i < strlen(sBuf); i++)
{
message[count] = sBuf[i];
count++;
}
message[count] = '';
if(send(sockfd, message, strlen(message), 0) < 0)
{
puts("Sent failed");
return 1;
}
memset(&sBuf, sizeof(sBuf), 0);

}

pthread_join(recv_thread , NULL);
close(sockfd);

return 0;
}

void *receive_handler(void *sock_fd)
{
int sFd = (intptr_t) sock_fd;
char buffer[MAXDATASIZE];
int nBytes;

for(;;)
{
if ((nBytes = recv(sFd, buffer, MAXDATASIZE-1, 0)) == -1)
{
perror("recv");
exit(1);
}
else
buffer[nBytes] = '';
printf("%s", buffer);
}
}









share|improve this question























  • Do you intend for your server to mediate each chat session, or are you trying to get the clients to communicate with each other directly?

    – John Bollinger
    Jan 2 at 22:32













  • I'm trying to get the clients to communicate with each other directly as they connect. I'll be more explicit: When the number of clients connected to the server is impair, the last connected will communicate with the next client connecting. When the number of clients connected to the server is pair, the next client connecting will wait for the next after him to connect to chat with him

    – amintou
    Jan 2 at 22:42






  • 1





    Communicating directly means (to me) that the server does not relay traffic from one client to the other. If that's really what you're after, then one client from each pair needs to establish a (new) connection with the other. Presumably, then, the original server's role would be to tell each client what partner to expect, and whether to act as server or client for the direct connection.

    – John Bollinger
    Jan 2 at 22:52













  • I just need to establish a communication between only two clients as they connect in the queue, whatever the way, maybe I can assign an ID for every client and have a list of all the clients connected? But I don't really know how to code that

    – amintou
    Jan 2 at 22:56






  • 1





    Note that if your goal is to have client A make a TCP connection directly to client B (or send UDP packets directly to client B), and you want this system to work across the Internet, you are going to have to deal with the ubiquitous-firewall problem -- that is, most people's computers are hidden behind firewalls which will reject incoming TCP connections and UDP packets. So if you go that route you will either need to implement hole-punching techniques (which are a big pain-in-the-butt and don't always work), or ask your users to modify their firewall settings (which many won't do).

    – Jeremy Friesner
    Jan 2 at 23:19
















0















I'm facing a problem with sockets programming in C.
I've coded a server where multiple clients can connect and send messages in a chatroom but i don't know how to connect two clients two by two.



example:
Client A connect to the Server but must wait in a queue waiting for Client B to connect.
Client C connect but must wait in a queue waiting for Client D to connect.



Every pair of clients must be in their specific chatroom, do I need to share the fd between the two sockets of the 2 clients or link between the two sockets.



I thought about using another way by using the function accept() twice before I fork() but I have to use child processes for that.



Here is my server code:



#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

#define PORT "8888"


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)
{
fd_set master;
fd_set read_fds;
int fdmax;

int listener;
int newfd;
struct sockaddr_storage remoteaddr;
socklen_t addrlen;

char buf[256];
int nbytes;

char remoteIP[INET6_ADDRSTRLEN];

int yes=1;
int i, j, rv;

struct addrinfo hints, *ai, *p;

FD_ZERO(&master);
FD_ZERO(&read_fds);


memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
if ((rv = getaddrinfo(NULL, PORT, &hints, &ai)) != 0) {
fprintf(stderr, "Server msg: %sn", gai_strerror(rv));
exit(1);
}

for(p = ai; p != NULL; p = p->ai_next)
{
listener = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (listener < 0) {
continue;
}

setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));

if (bind(listener, p->ai_addr, p->ai_addrlen) < 0) {
close(listener);
continue;
}

break;
}

if (p == NULL) {
fprintf(stderr, "Server msg: bind failedn");
exit(2);
}

freeaddrinfo(ai);

puts("Bind success");

if (listen(listener, 10) == -1)
{
perror("listen");
exit(3);
}
puts("Server listening ...");


FD_SET(listener, &master);


fdmax = listener;


for(;;)
{
read_fds = master;
if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1)
{
perror("select");
exit(4);
}


for(i = 0; i <= fdmax; i++)
{
if (FD_ISSET(i, &read_fds))
{
if (i == listener)
{

addrlen = sizeof remoteaddr;
newfd = accept(listener,
(struct sockaddr *)&remoteaddr,
&addrlen);

if (newfd == -1)
{
perror("accept");
}
else
{
FD_SET(newfd, &master);
if (newfd > fdmax)
{
fdmax = newfd;
}
printf("Server msg: new connection from %s on "
"socket %dn", inet_ntop(remoteaddr.ss_family,
get_in_addr((struct sockaddr*)&remoteaddr),
remoteIP, INET6_ADDRSTRLEN), newfd);
}
}
else
{

if ((nbytes = recv(i, buf, sizeof buf, 0)) <= 0)
{
if (nbytes == 0)
{
printf("Server msg: socket %d lostn", i);
}
else
{
perror("recv");
}
close(i);
FD_CLR(i, &master);
}
else
{

for(j = 0; j <= fdmax; j++)
{

if (FD_ISSET(j, &master))
{

if (j != listener && j != i)
{
if (send(j, buf, nbytes, 0) == -1)
{
perror("send");
}
}
}
}
}
}
}
}
}

return 0;
}


And here is my client code:



#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#include <arpa/inet.h>

#define PORT "8888"

#define MAXDATASIZE 100
#define MAXNAMESIZE 25

void *receive_handler(void *);

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(int argc, char *argv)
{
char message[MAXDATASIZE];
char nickName[MAXNAMESIZE];
int sockfd;
char sBuf[MAXDATASIZE];
struct addrinfo hints, *servinfo, *p;
int rv;
char s[INET6_ADDRSTRLEN];

if (argc != 2) {
fprintf(stderr,"Usage: ./client addressn");
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: %sn", gai_strerror(rv));
return 1;
}


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: connection failedn");
return 2;
}

inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr),
s, sizeof s);
printf("Client: connection to %sn", s);

freeaddrinfo(servinfo);

puts("Give your username:");
memset(&nickName, sizeof(nickName), 0);
memset(&message, sizeof(message), 0);
fgets(nickName, MAXNAMESIZE, stdin);
pthread_t recv_thread;

if( pthread_create(&recv_thread, NULL, receive_handler, (void*)(intptr_t) sockfd) < 0)
{
perror("Failed on thread creation");
return 1;
}
puts("Connection established");

puts("Welcome!n");
puts("[Type '/quit' to quit the chatroom]");

for(;;)
{
char temp[6];
memset(&temp, sizeof(temp), 0);

memset(&sBuf, sizeof(sBuf), 0);
fgets(sBuf, 100, stdin);

if(sBuf[0] == '/' &&
sBuf[1] == 'q' &&
sBuf[2] == 'u' &&
sBuf[3] == 'i' &&
sBuf[4] == 't')
return 1;


int count = 0;
while(count < strlen(nickName))
{
message[count] = nickName[count];
count++;
}
count--;
message[count] = ':';
count++;

for(int i = 0; i < strlen(sBuf); i++)
{
message[count] = sBuf[i];
count++;
}
message[count] = '';
if(send(sockfd, message, strlen(message), 0) < 0)
{
puts("Sent failed");
return 1;
}
memset(&sBuf, sizeof(sBuf), 0);

}

pthread_join(recv_thread , NULL);
close(sockfd);

return 0;
}

void *receive_handler(void *sock_fd)
{
int sFd = (intptr_t) sock_fd;
char buffer[MAXDATASIZE];
int nBytes;

for(;;)
{
if ((nBytes = recv(sFd, buffer, MAXDATASIZE-1, 0)) == -1)
{
perror("recv");
exit(1);
}
else
buffer[nBytes] = '';
printf("%s", buffer);
}
}









share|improve this question























  • Do you intend for your server to mediate each chat session, or are you trying to get the clients to communicate with each other directly?

    – John Bollinger
    Jan 2 at 22:32













  • I'm trying to get the clients to communicate with each other directly as they connect. I'll be more explicit: When the number of clients connected to the server is impair, the last connected will communicate with the next client connecting. When the number of clients connected to the server is pair, the next client connecting will wait for the next after him to connect to chat with him

    – amintou
    Jan 2 at 22:42






  • 1





    Communicating directly means (to me) that the server does not relay traffic from one client to the other. If that's really what you're after, then one client from each pair needs to establish a (new) connection with the other. Presumably, then, the original server's role would be to tell each client what partner to expect, and whether to act as server or client for the direct connection.

    – John Bollinger
    Jan 2 at 22:52













  • I just need to establish a communication between only two clients as they connect in the queue, whatever the way, maybe I can assign an ID for every client and have a list of all the clients connected? But I don't really know how to code that

    – amintou
    Jan 2 at 22:56






  • 1





    Note that if your goal is to have client A make a TCP connection directly to client B (or send UDP packets directly to client B), and you want this system to work across the Internet, you are going to have to deal with the ubiquitous-firewall problem -- that is, most people's computers are hidden behind firewalls which will reject incoming TCP connections and UDP packets. So if you go that route you will either need to implement hole-punching techniques (which are a big pain-in-the-butt and don't always work), or ask your users to modify their firewall settings (which many won't do).

    – Jeremy Friesner
    Jan 2 at 23:19














0












0








0








I'm facing a problem with sockets programming in C.
I've coded a server where multiple clients can connect and send messages in a chatroom but i don't know how to connect two clients two by two.



example:
Client A connect to the Server but must wait in a queue waiting for Client B to connect.
Client C connect but must wait in a queue waiting for Client D to connect.



Every pair of clients must be in their specific chatroom, do I need to share the fd between the two sockets of the 2 clients or link between the two sockets.



I thought about using another way by using the function accept() twice before I fork() but I have to use child processes for that.



Here is my server code:



#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

#define PORT "8888"


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)
{
fd_set master;
fd_set read_fds;
int fdmax;

int listener;
int newfd;
struct sockaddr_storage remoteaddr;
socklen_t addrlen;

char buf[256];
int nbytes;

char remoteIP[INET6_ADDRSTRLEN];

int yes=1;
int i, j, rv;

struct addrinfo hints, *ai, *p;

FD_ZERO(&master);
FD_ZERO(&read_fds);


memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
if ((rv = getaddrinfo(NULL, PORT, &hints, &ai)) != 0) {
fprintf(stderr, "Server msg: %sn", gai_strerror(rv));
exit(1);
}

for(p = ai; p != NULL; p = p->ai_next)
{
listener = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (listener < 0) {
continue;
}

setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));

if (bind(listener, p->ai_addr, p->ai_addrlen) < 0) {
close(listener);
continue;
}

break;
}

if (p == NULL) {
fprintf(stderr, "Server msg: bind failedn");
exit(2);
}

freeaddrinfo(ai);

puts("Bind success");

if (listen(listener, 10) == -1)
{
perror("listen");
exit(3);
}
puts("Server listening ...");


FD_SET(listener, &master);


fdmax = listener;


for(;;)
{
read_fds = master;
if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1)
{
perror("select");
exit(4);
}


for(i = 0; i <= fdmax; i++)
{
if (FD_ISSET(i, &read_fds))
{
if (i == listener)
{

addrlen = sizeof remoteaddr;
newfd = accept(listener,
(struct sockaddr *)&remoteaddr,
&addrlen);

if (newfd == -1)
{
perror("accept");
}
else
{
FD_SET(newfd, &master);
if (newfd > fdmax)
{
fdmax = newfd;
}
printf("Server msg: new connection from %s on "
"socket %dn", inet_ntop(remoteaddr.ss_family,
get_in_addr((struct sockaddr*)&remoteaddr),
remoteIP, INET6_ADDRSTRLEN), newfd);
}
}
else
{

if ((nbytes = recv(i, buf, sizeof buf, 0)) <= 0)
{
if (nbytes == 0)
{
printf("Server msg: socket %d lostn", i);
}
else
{
perror("recv");
}
close(i);
FD_CLR(i, &master);
}
else
{

for(j = 0; j <= fdmax; j++)
{

if (FD_ISSET(j, &master))
{

if (j != listener && j != i)
{
if (send(j, buf, nbytes, 0) == -1)
{
perror("send");
}
}
}
}
}
}
}
}
}

return 0;
}


And here is my client code:



#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#include <arpa/inet.h>

#define PORT "8888"

#define MAXDATASIZE 100
#define MAXNAMESIZE 25

void *receive_handler(void *);

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(int argc, char *argv)
{
char message[MAXDATASIZE];
char nickName[MAXNAMESIZE];
int sockfd;
char sBuf[MAXDATASIZE];
struct addrinfo hints, *servinfo, *p;
int rv;
char s[INET6_ADDRSTRLEN];

if (argc != 2) {
fprintf(stderr,"Usage: ./client addressn");
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: %sn", gai_strerror(rv));
return 1;
}


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: connection failedn");
return 2;
}

inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr),
s, sizeof s);
printf("Client: connection to %sn", s);

freeaddrinfo(servinfo);

puts("Give your username:");
memset(&nickName, sizeof(nickName), 0);
memset(&message, sizeof(message), 0);
fgets(nickName, MAXNAMESIZE, stdin);
pthread_t recv_thread;

if( pthread_create(&recv_thread, NULL, receive_handler, (void*)(intptr_t) sockfd) < 0)
{
perror("Failed on thread creation");
return 1;
}
puts("Connection established");

puts("Welcome!n");
puts("[Type '/quit' to quit the chatroom]");

for(;;)
{
char temp[6];
memset(&temp, sizeof(temp), 0);

memset(&sBuf, sizeof(sBuf), 0);
fgets(sBuf, 100, stdin);

if(sBuf[0] == '/' &&
sBuf[1] == 'q' &&
sBuf[2] == 'u' &&
sBuf[3] == 'i' &&
sBuf[4] == 't')
return 1;


int count = 0;
while(count < strlen(nickName))
{
message[count] = nickName[count];
count++;
}
count--;
message[count] = ':';
count++;

for(int i = 0; i < strlen(sBuf); i++)
{
message[count] = sBuf[i];
count++;
}
message[count] = '';
if(send(sockfd, message, strlen(message), 0) < 0)
{
puts("Sent failed");
return 1;
}
memset(&sBuf, sizeof(sBuf), 0);

}

pthread_join(recv_thread , NULL);
close(sockfd);

return 0;
}

void *receive_handler(void *sock_fd)
{
int sFd = (intptr_t) sock_fd;
char buffer[MAXDATASIZE];
int nBytes;

for(;;)
{
if ((nBytes = recv(sFd, buffer, MAXDATASIZE-1, 0)) == -1)
{
perror("recv");
exit(1);
}
else
buffer[nBytes] = '';
printf("%s", buffer);
}
}









share|improve this question














I'm facing a problem with sockets programming in C.
I've coded a server where multiple clients can connect and send messages in a chatroom but i don't know how to connect two clients two by two.



example:
Client A connect to the Server but must wait in a queue waiting for Client B to connect.
Client C connect but must wait in a queue waiting for Client D to connect.



Every pair of clients must be in their specific chatroom, do I need to share the fd between the two sockets of the 2 clients or link between the two sockets.



I thought about using another way by using the function accept() twice before I fork() but I have to use child processes for that.



Here is my server code:



#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

#define PORT "8888"


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)
{
fd_set master;
fd_set read_fds;
int fdmax;

int listener;
int newfd;
struct sockaddr_storage remoteaddr;
socklen_t addrlen;

char buf[256];
int nbytes;

char remoteIP[INET6_ADDRSTRLEN];

int yes=1;
int i, j, rv;

struct addrinfo hints, *ai, *p;

FD_ZERO(&master);
FD_ZERO(&read_fds);


memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
if ((rv = getaddrinfo(NULL, PORT, &hints, &ai)) != 0) {
fprintf(stderr, "Server msg: %sn", gai_strerror(rv));
exit(1);
}

for(p = ai; p != NULL; p = p->ai_next)
{
listener = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (listener < 0) {
continue;
}

setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));

if (bind(listener, p->ai_addr, p->ai_addrlen) < 0) {
close(listener);
continue;
}

break;
}

if (p == NULL) {
fprintf(stderr, "Server msg: bind failedn");
exit(2);
}

freeaddrinfo(ai);

puts("Bind success");

if (listen(listener, 10) == -1)
{
perror("listen");
exit(3);
}
puts("Server listening ...");


FD_SET(listener, &master);


fdmax = listener;


for(;;)
{
read_fds = master;
if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1)
{
perror("select");
exit(4);
}


for(i = 0; i <= fdmax; i++)
{
if (FD_ISSET(i, &read_fds))
{
if (i == listener)
{

addrlen = sizeof remoteaddr;
newfd = accept(listener,
(struct sockaddr *)&remoteaddr,
&addrlen);

if (newfd == -1)
{
perror("accept");
}
else
{
FD_SET(newfd, &master);
if (newfd > fdmax)
{
fdmax = newfd;
}
printf("Server msg: new connection from %s on "
"socket %dn", inet_ntop(remoteaddr.ss_family,
get_in_addr((struct sockaddr*)&remoteaddr),
remoteIP, INET6_ADDRSTRLEN), newfd);
}
}
else
{

if ((nbytes = recv(i, buf, sizeof buf, 0)) <= 0)
{
if (nbytes == 0)
{
printf("Server msg: socket %d lostn", i);
}
else
{
perror("recv");
}
close(i);
FD_CLR(i, &master);
}
else
{

for(j = 0; j <= fdmax; j++)
{

if (FD_ISSET(j, &master))
{

if (j != listener && j != i)
{
if (send(j, buf, nbytes, 0) == -1)
{
perror("send");
}
}
}
}
}
}
}
}
}

return 0;
}


And here is my client code:



#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#include <arpa/inet.h>

#define PORT "8888"

#define MAXDATASIZE 100
#define MAXNAMESIZE 25

void *receive_handler(void *);

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(int argc, char *argv)
{
char message[MAXDATASIZE];
char nickName[MAXNAMESIZE];
int sockfd;
char sBuf[MAXDATASIZE];
struct addrinfo hints, *servinfo, *p;
int rv;
char s[INET6_ADDRSTRLEN];

if (argc != 2) {
fprintf(stderr,"Usage: ./client addressn");
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: %sn", gai_strerror(rv));
return 1;
}


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: connection failedn");
return 2;
}

inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr),
s, sizeof s);
printf("Client: connection to %sn", s);

freeaddrinfo(servinfo);

puts("Give your username:");
memset(&nickName, sizeof(nickName), 0);
memset(&message, sizeof(message), 0);
fgets(nickName, MAXNAMESIZE, stdin);
pthread_t recv_thread;

if( pthread_create(&recv_thread, NULL, receive_handler, (void*)(intptr_t) sockfd) < 0)
{
perror("Failed on thread creation");
return 1;
}
puts("Connection established");

puts("Welcome!n");
puts("[Type '/quit' to quit the chatroom]");

for(;;)
{
char temp[6];
memset(&temp, sizeof(temp), 0);

memset(&sBuf, sizeof(sBuf), 0);
fgets(sBuf, 100, stdin);

if(sBuf[0] == '/' &&
sBuf[1] == 'q' &&
sBuf[2] == 'u' &&
sBuf[3] == 'i' &&
sBuf[4] == 't')
return 1;


int count = 0;
while(count < strlen(nickName))
{
message[count] = nickName[count];
count++;
}
count--;
message[count] = ':';
count++;

for(int i = 0; i < strlen(sBuf); i++)
{
message[count] = sBuf[i];
count++;
}
message[count] = '';
if(send(sockfd, message, strlen(message), 0) < 0)
{
puts("Sent failed");
return 1;
}
memset(&sBuf, sizeof(sBuf), 0);

}

pthread_join(recv_thread , NULL);
close(sockfd);

return 0;
}

void *receive_handler(void *sock_fd)
{
int sFd = (intptr_t) sock_fd;
char buffer[MAXDATASIZE];
int nBytes;

for(;;)
{
if ((nBytes = recv(sFd, buffer, MAXDATASIZE-1, 0)) == -1)
{
perror("recv");
exit(1);
}
else
buffer[nBytes] = '';
printf("%s", buffer);
}
}






c sockets pthreads file-descriptor






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Jan 2 at 22:14









amintouamintou

236




236













  • Do you intend for your server to mediate each chat session, or are you trying to get the clients to communicate with each other directly?

    – John Bollinger
    Jan 2 at 22:32













  • I'm trying to get the clients to communicate with each other directly as they connect. I'll be more explicit: When the number of clients connected to the server is impair, the last connected will communicate with the next client connecting. When the number of clients connected to the server is pair, the next client connecting will wait for the next after him to connect to chat with him

    – amintou
    Jan 2 at 22:42






  • 1





    Communicating directly means (to me) that the server does not relay traffic from one client to the other. If that's really what you're after, then one client from each pair needs to establish a (new) connection with the other. Presumably, then, the original server's role would be to tell each client what partner to expect, and whether to act as server or client for the direct connection.

    – John Bollinger
    Jan 2 at 22:52













  • I just need to establish a communication between only two clients as they connect in the queue, whatever the way, maybe I can assign an ID for every client and have a list of all the clients connected? But I don't really know how to code that

    – amintou
    Jan 2 at 22:56






  • 1





    Note that if your goal is to have client A make a TCP connection directly to client B (or send UDP packets directly to client B), and you want this system to work across the Internet, you are going to have to deal with the ubiquitous-firewall problem -- that is, most people's computers are hidden behind firewalls which will reject incoming TCP connections and UDP packets. So if you go that route you will either need to implement hole-punching techniques (which are a big pain-in-the-butt and don't always work), or ask your users to modify their firewall settings (which many won't do).

    – Jeremy Friesner
    Jan 2 at 23:19



















  • Do you intend for your server to mediate each chat session, or are you trying to get the clients to communicate with each other directly?

    – John Bollinger
    Jan 2 at 22:32













  • I'm trying to get the clients to communicate with each other directly as they connect. I'll be more explicit: When the number of clients connected to the server is impair, the last connected will communicate with the next client connecting. When the number of clients connected to the server is pair, the next client connecting will wait for the next after him to connect to chat with him

    – amintou
    Jan 2 at 22:42






  • 1





    Communicating directly means (to me) that the server does not relay traffic from one client to the other. If that's really what you're after, then one client from each pair needs to establish a (new) connection with the other. Presumably, then, the original server's role would be to tell each client what partner to expect, and whether to act as server or client for the direct connection.

    – John Bollinger
    Jan 2 at 22:52













  • I just need to establish a communication between only two clients as they connect in the queue, whatever the way, maybe I can assign an ID for every client and have a list of all the clients connected? But I don't really know how to code that

    – amintou
    Jan 2 at 22:56






  • 1





    Note that if your goal is to have client A make a TCP connection directly to client B (or send UDP packets directly to client B), and you want this system to work across the Internet, you are going to have to deal with the ubiquitous-firewall problem -- that is, most people's computers are hidden behind firewalls which will reject incoming TCP connections and UDP packets. So if you go that route you will either need to implement hole-punching techniques (which are a big pain-in-the-butt and don't always work), or ask your users to modify their firewall settings (which many won't do).

    – Jeremy Friesner
    Jan 2 at 23:19

















Do you intend for your server to mediate each chat session, or are you trying to get the clients to communicate with each other directly?

– John Bollinger
Jan 2 at 22:32







Do you intend for your server to mediate each chat session, or are you trying to get the clients to communicate with each other directly?

– John Bollinger
Jan 2 at 22:32















I'm trying to get the clients to communicate with each other directly as they connect. I'll be more explicit: When the number of clients connected to the server is impair, the last connected will communicate with the next client connecting. When the number of clients connected to the server is pair, the next client connecting will wait for the next after him to connect to chat with him

– amintou
Jan 2 at 22:42





I'm trying to get the clients to communicate with each other directly as they connect. I'll be more explicit: When the number of clients connected to the server is impair, the last connected will communicate with the next client connecting. When the number of clients connected to the server is pair, the next client connecting will wait for the next after him to connect to chat with him

– amintou
Jan 2 at 22:42




1




1





Communicating directly means (to me) that the server does not relay traffic from one client to the other. If that's really what you're after, then one client from each pair needs to establish a (new) connection with the other. Presumably, then, the original server's role would be to tell each client what partner to expect, and whether to act as server or client for the direct connection.

– John Bollinger
Jan 2 at 22:52







Communicating directly means (to me) that the server does not relay traffic from one client to the other. If that's really what you're after, then one client from each pair needs to establish a (new) connection with the other. Presumably, then, the original server's role would be to tell each client what partner to expect, and whether to act as server or client for the direct connection.

– John Bollinger
Jan 2 at 22:52















I just need to establish a communication between only two clients as they connect in the queue, whatever the way, maybe I can assign an ID for every client and have a list of all the clients connected? But I don't really know how to code that

– amintou
Jan 2 at 22:56





I just need to establish a communication between only two clients as they connect in the queue, whatever the way, maybe I can assign an ID for every client and have a list of all the clients connected? But I don't really know how to code that

– amintou
Jan 2 at 22:56




1




1





Note that if your goal is to have client A make a TCP connection directly to client B (or send UDP packets directly to client B), and you want this system to work across the Internet, you are going to have to deal with the ubiquitous-firewall problem -- that is, most people's computers are hidden behind firewalls which will reject incoming TCP connections and UDP packets. So if you go that route you will either need to implement hole-punching techniques (which are a big pain-in-the-butt and don't always work), or ask your users to modify their firewall settings (which many won't do).

– Jeremy Friesner
Jan 2 at 23:19





Note that if your goal is to have client A make a TCP connection directly to client B (or send UDP packets directly to client B), and you want this system to work across the Internet, you are going to have to deal with the ubiquitous-firewall problem -- that is, most people's computers are hidden behind firewalls which will reject incoming TCP connections and UDP packets. So if you go that route you will either need to implement hole-punching techniques (which are a big pain-in-the-butt and don't always work), or ask your users to modify their firewall settings (which many won't do).

– Jeremy Friesner
Jan 2 at 23:19












1 Answer
1






active

oldest

votes


















0














Yes, in my opinion you can use two accept and then call a fork() or, even better, a new thread. You can create a new process/thread for each pair of connections.



What do you mean sharing the fd? You mean sending a fd of one client to another? In this case NO
You can keep, in the thread function, a mapping between the two clients to know which clients are paired. When receiving a message from one client, thanks to the mapping, you know which client you are supposed to send the message to.



I think the rest depends on further details you should specify in your question.
Let me know



If each client can both send and receive you might want to use multithreading on client-side too: one to send and one to receive.






share|improve this answer


























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54013875%2fhow-to-connect-clients-two-by-two-as-they-connect%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    0














    Yes, in my opinion you can use two accept and then call a fork() or, even better, a new thread. You can create a new process/thread for each pair of connections.



    What do you mean sharing the fd? You mean sending a fd of one client to another? In this case NO
    You can keep, in the thread function, a mapping between the two clients to know which clients are paired. When receiving a message from one client, thanks to the mapping, you know which client you are supposed to send the message to.



    I think the rest depends on further details you should specify in your question.
    Let me know



    If each client can both send and receive you might want to use multithreading on client-side too: one to send and one to receive.






    share|improve this answer






























      0














      Yes, in my opinion you can use two accept and then call a fork() or, even better, a new thread. You can create a new process/thread for each pair of connections.



      What do you mean sharing the fd? You mean sending a fd of one client to another? In this case NO
      You can keep, in the thread function, a mapping between the two clients to know which clients are paired. When receiving a message from one client, thanks to the mapping, you know which client you are supposed to send the message to.



      I think the rest depends on further details you should specify in your question.
      Let me know



      If each client can both send and receive you might want to use multithreading on client-side too: one to send and one to receive.






      share|improve this answer




























        0












        0








        0







        Yes, in my opinion you can use two accept and then call a fork() or, even better, a new thread. You can create a new process/thread for each pair of connections.



        What do you mean sharing the fd? You mean sending a fd of one client to another? In this case NO
        You can keep, in the thread function, a mapping between the two clients to know which clients are paired. When receiving a message from one client, thanks to the mapping, you know which client you are supposed to send the message to.



        I think the rest depends on further details you should specify in your question.
        Let me know



        If each client can both send and receive you might want to use multithreading on client-side too: one to send and one to receive.






        share|improve this answer















        Yes, in my opinion you can use two accept and then call a fork() or, even better, a new thread. You can create a new process/thread for each pair of connections.



        What do you mean sharing the fd? You mean sending a fd of one client to another? In this case NO
        You can keep, in the thread function, a mapping between the two clients to know which clients are paired. When receiving a message from one client, thanks to the mapping, you know which client you are supposed to send the message to.



        I think the rest depends on further details you should specify in your question.
        Let me know



        If each client can both send and receive you might want to use multithreading on client-side too: one to send and one to receive.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Jan 2 at 23:25

























        answered Jan 2 at 22:59









        Francesco BoiFrancesco Boi

        2,77022643




        2,77022643
































            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54013875%2fhow-to-connect-clients-two-by-two-as-they-connect%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            MongoDB - Not Authorized To Execute Command

            How to fix TextFormField cause rebuild widget in Flutter

            in spring boot 2.1 many test slices are not allowed anymore due to multiple @BootstrapWith