How to connect clients two by two as they connect
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
|
show 2 more comments
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
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
|
show 2 more comments
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
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
c sockets pthreads file-descriptor
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
|
show 2 more comments
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
|
show 2 more comments
1 Answer
1
active
oldest
votes
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.
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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.
add a comment |
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.
add a comment |
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.
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.
edited Jan 2 at 23:25
answered Jan 2 at 22:59
Francesco BoiFrancesco Boi
2,77022643
2,77022643
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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