Using select() for non-blocking sockets - c

I am trying to use the select function to have non-blocking i/o between a server and 1 client (no more) where the communication flows nicely (can send at any time and the other will receive without waiting to send). I found a tutorial with some code and tried to adapt it to mine. This is what I have -
Server
#define PORT "4950"
#define STDIN 0
struct sockaddr name;
void set_nonblock(int socket) {
int flags;
flags = fcntl(socket,F_GETFL,0);
assert(flags != -1);
fcntl(socket, F_SETFL, flags | O_NONBLOCK);
}
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa) {
if (sa->sa_family == AF_INET)
return &(((struct sockaddr_in*)sa)->sin_addr);
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(int agrc, char** argv) {
int status, sock, adrlen, new_sd;
struct addrinfo hints;
struct addrinfo *servinfo; //will point to the results
//store the connecting address and size
struct sockaddr_storage their_addr;
socklen_t their_addr_size;
fd_set read_flags,write_flags; // the flag sets to be used
struct timeval waitd; // the max wait time for an event
int sel; // holds return value for select();
//socket infoS
memset(&hints, 0, sizeof hints); //make sure the struct is empty
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM; //tcp
hints.ai_flags = AI_PASSIVE; //use local-host address
//get server info, put into servinfo
if ((status = getaddrinfo("127.0.0.1", PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
exit(1);
}
//make socket
sock = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol);
if (sock < 0) {
printf("\nserver socket failure %m", errno);
exit(1);
}
//allow reuse of port
int yes=1;
if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
//unlink and bind
unlink("127.0.0.1");
if(bind (sock, servinfo->ai_addr, servinfo->ai_addrlen) < 0) {
printf("\nBind error %m", errno);
exit(1);
}
freeaddrinfo(servinfo);
//listen
if(listen(sock, 5) < 0) {
printf("\nListen error %m", errno);
exit(1);
}
their_addr_size = sizeof(their_addr);
//accept
new_sd = accept(sock, (struct sockaddr*)&their_addr, &their_addr_size);
if( new_sd < 0) {
printf("\nAccept error %m", errno);
exit(1);
}
set_nonblock(new_sd);
cout<<"\nSuccessful Connection!";
char* in = new char[255];
char* out = new char[255];
int numSent;
int numRead;
while(1) {
waitd.tv_sec = 10;
FD_ZERO(&read_flags);
FD_ZERO(&write_flags);
FD_SET(new_sd, &read_flags);
if(strlen(out) != 0)
FD_SET(new_sd, &write_flags);
sel = select(new_sd+1, &read_flags, &write_flags, (fd_set*)0, &waitd);
if(sel < 0)
continue;
//socket ready for reading
if(FD_ISSET(new_sd, &read_flags)) {
FD_CLR(new_sd, &read_flags);
memset(&in, 0, sizeof(in));
if(recv(new_sd, in, sizeof(in), 0) <= 0) {
close(new_sd);
break;
}
else
cout<<"\n"<<in;
} //end if ready for read
//socket ready for writing
if(FD_ISSET(new_sd, &write_flags)) {
FD_CLR(new_sd, &write_flags);
send(new_sd, out, strlen(out), 0);
memset(&out, 0, sizeof(out));
}
} //end while
cout<<"\n\nExiting normally\n";
return 0;
}
Client (basically the same just minus an accept call) -
#define PORT "4950"
struct sockaddr name;
void set_nonblock(int socket) {
int flags;
flags = fcntl(socket,F_GETFL,0);
assert(flags != -1);
fcntl(socket, F_SETFL, flags | O_NONBLOCK);
}
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa) {
if (sa->sa_family == AF_INET)
return &(((struct sockaddr_in*)sa)->sin_addr);
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(int agrc, char** argv) {
int status, sock, adrlen;
struct addrinfo hints;
struct addrinfo *servinfo; //will point to the results
fd_set read_flags,write_flags; // the flag sets to be used
struct timeval waitd; // the max wait time for an event
int sel; // holds return value for select();
memset(&hints, 0, sizeof hints); //make sure the struct is empty
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM; //tcp
hints.ai_flags = AI_PASSIVE; //use local-host address
//get server info, put into servinfo
if ((status = getaddrinfo("127.0.0.1", PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
exit(1);
}
//make socket
sock = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol);
if (sock < 0) {
printf("\nserver socket failure %m", errno);
exit(1);
}
if(connect(sock, servinfo->ai_addr, servinfo->ai_addrlen) < 0) {
printf("\nclient connection failure %m", errno);
exit(1);
}
cout<<"\nSuccessful connection!";
set_nonblock(sock);
char* out = new char[255];
char* in = new char[255];
int numRead;
int numSent;
while(1) {
waitd.tv_sec = 10;
FD_ZERO(&read_flags);
FD_ZERO(&write_flags);
FD_SET(sock, &read_flags);
if(strlen(out) != 0)
FD_SET(sock, &write_flags);
sel = select(sock+1, &read_flags, &write_flags, (fd_set*)0, &waitd);
if(sel < 0)
continue;
//socket ready for reading
if(FD_ISSET(sock, &read_flags)) {
FD_CLR(sock, &read_flags);
memset(&in, 0, sizeof(in));
if(recv(sock, in, sizeof(in), 0) <= 0) {
close(sock);
break;
}
else
cout<<"\n"<<in;
} //end if ready for read
//socket ready for writing
if(FD_ISSET(sock, &write_flags)) {
FD_CLR(sock, &write_flags);
send(sock, out, strlen(out), 0);
memset(&out, 0, sizeof(out));
}
} //end while
cout<<"\n\nExiting normally\n";
return 0;
}
The problem is that when I run them, nothing happens. I can type into one and hit enter and nothing shows up on the other screen (and vice versa). Thats not a whole of information for me to debug and this is my first real attempt at using select so I thought maybe I am just unaware of something simple. If anything can be spotted as wrong or weird please point it out, any help is appreciated.

The problem is that when I run them, nothing happens.
The real problem is that people have been pasting stuff from Beej for years without understanding it. That's why I don't really like that guide; it gives large blocks of code without really explaining them in detail.
You're not reading anything and not sending anything; no fgets, scanf, cin, etc. Here's what I would do:
FD_SET(sock, &read_flags);
FD_SET(STDIN_FILENO, &read_flags);
/* .. snip .. */
if(FD_ISSET(STDIN_FILENO, &read_flags)) {
fgets(out, len, stdin);
}
This will monitor stdin and read from it when input is available; then, when the socket is writeable (FD_ISSET(sock, &write_flags)), it will send the buffer.

I have the program working correctly now.
server -
#define PORT "4950"
#define STDIN 0
struct sockaddr name;
void set_nonblock(int socket) {
int flags;
flags = fcntl(socket,F_GETFL,0);
assert(flags != -1);
fcntl(socket, F_SETFL, flags | O_NONBLOCK);
}
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa) {
if (sa->sa_family == AF_INET)
return &(((struct sockaddr_in*)sa)->sin_addr);
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(int agrc, char** argv) {
int status, sock, adrlen, new_sd;
struct addrinfo hints;
struct addrinfo *servinfo; //will point to the results
//store the connecting address and size
struct sockaddr_storage their_addr;
socklen_t their_addr_size;
fd_set read_flags,write_flags; // the flag sets to be used
struct timeval waitd = {10, 0}; // the max wait time for an event
int sel; // holds return value for select();
//socket infoS
memset(&hints, 0, sizeof hints); //make sure the struct is empty
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM; //tcp
hints.ai_flags = AI_PASSIVE; //use local-host address
//get server info, put into servinfo
if ((status = getaddrinfo("127.0.0.1", PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
exit(1);
}
//make socket
sock = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol);
if (sock < 0) {
printf("\nserver socket failure %m", errno);
exit(1);
}
//allow reuse of port
int yes=1;
if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
//unlink and bind
unlink("127.0.0.1");
if(bind (sock, servinfo->ai_addr, servinfo->ai_addrlen) < 0) {
printf("\nBind error %m", errno);
exit(1);
}
freeaddrinfo(servinfo);
//listen
if(listen(sock, 5) < 0) {
printf("\nListen error %m", errno);
exit(1);
}
their_addr_size = sizeof(their_addr);
//accept
new_sd = accept(sock, (struct sockaddr*)&their_addr, &their_addr_size);
if( new_sd < 0) {
printf("\nAccept error %m", errno);
exit(1);
}
//set non blocking
set_nonblock(new_sd);
cout<<"\nSuccessful Connection!\n";
char in[255];
char out[255];
memset(&in, 0, 255);
memset(&out, 0, 255);
int numSent;
int numRead;
while(1) {
FD_ZERO(&read_flags);
FD_ZERO(&write_flags);
FD_SET(new_sd, &read_flags);
FD_SET(new_sd, &write_flags);
FD_SET(STDIN_FILENO, &read_flags);
FD_SET(STDIN_FILENO, &write_flags);
sel = select(new_sd+1, &read_flags, &write_flags, (fd_set*)0, &waitd);
//if an error with select
if(sel < 0)
continue;
//socket ready for reading
if(FD_ISSET(new_sd, &read_flags)) {
//clear set
FD_CLR(new_sd, &read_flags);
memset(&in, 0, 255);
numRead = recv(new_sd, in, 255, 0);
if(numRead <= 0) {
printf("\nClosing socket");
close(new_sd);
break;
}
else if(in[0] != '\0')
cout<<"\nClient: "<<in;
} //end if ready for read
//if stdin is ready to be read
if(FD_ISSET(STDIN_FILENO, &read_flags))
fgets(out, 255, stdin);
//socket ready for writing
if(FD_ISSET(new_sd, &write_flags)) {
//printf("\nSocket ready for write");
FD_CLR(new_sd, &write_flags);
send(new_sd, out, 255, 0);
memset(&out, 0, 255);
} //end if
} //end while
cout<<"\n\nExiting normally\n";
return 0;
}
The client is basically the same...only difference really is the lack of listen and accept.

I just want to add that above example may not work as expected on Linux. On Linux waitd may be modified by select. So for Linux, waitd should be rewritten before select.
See the "timeout" section in the man page for select.

Related

Reading consecutive messages

I have created a server and trying to listen on a specific port. When I am sending a message with netcat to this specific port, I succeed reading the first message, with the
read(fd_client_serv, buf, sizeof(buf));
system call. After that, any message sent will not be printed. Why is that happening?
Here is my code:
void start_server(void)
{
int fd_serv, fd_client_serv, bytes_read;
struct sockaddr_in client_serv_addr;
char buf[2048];
socklen_t sin_len_serv = sizeof(client_serv_addr);
fd_serv = initialize_server(get_serving_port());
fd_set_blocking(fd_serv, 0);
while(1)
{
fd_client_serv = accept(fd_serv, (struct sockaddr *) &client_serv_addr, &sin_len_serv);
puts("HA!!! you cannot block me!!!");
sleep(2);
memset(buf, 0, sizeof(buf));
write(fd_client_serv, "thank you for answering", 30);
bytes_read = read(fd_client_serv, buf, sizeof(buf));
printf("%d\n", bytes_read);
fflush(stdout);
printf("%s\n", buf);
}
}
int initialize_server(int port)
{
struct sockaddr_in server_addr;
int fd_temp;
int on = 1;
fd_temp = socket(AF_INET, SOCK_STREAM, 0);
if (fd_temp < 0)
{
perror("socket");
exit(1);
}
setsockopt(fd_temp, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(port);
if (bind(fd_temp,(struct sockaddr *) &server_addr, sizeof(server_addr)) == -1)
{
perror("bind");
close(fd_temp);
exit(1);
}
if (listen(fd_temp, 10) == -1)
{
perror("listen");
close(fd_temp);
exit(1);
}
return fd_temp;
}
int fd_set_blocking(int fd, int blocking)
{
/* Save the current flags */
int flags = fcntl(fd, F_GETFL, 0);
if (flags == -1)
return 0;
if (blocking)
flags &= ~O_NONBLOCK;
else
flags |= O_NONBLOCK;
return fcntl(fd, F_SETFL, flags) != -1;
}
I just noticed that if I shutdown netcat (or telnet) and start a new one, I can read again the first message sent. But that's it.
accept() accepts a new connection. So every time through the loop you set fd_client_serv to the socket id of a new connection, abandoning the old connection. ("Abandoning" in the sense that you will never read from it again, since you have lost its id. You haven't closed it but you've forgotten about it.)

C, TCP, recvAll block is not receing anything

I am new to both C and socket programming, so please bear with me. The following code is mostly from Beej networking guide, with some changes. I have the receiver code attached (which is TCP server in this case), that listens to multiple TCP connections. I have a transmitter (client) who is constantly sending fixed chunks of data to this receiver. This code (which I cleaned and removed some function definitions unrelated to my issue) works if instead of calling recv_all function, I only call recv(). But the problem with that I need to do processing on each chunk of received data, so I need the whole chunk. So I thought I should use the recv_all().
Now the problem is it gets stuck in an infinite loop in the while in recv_all(), because n is always 0. I truly appreciate your help.
#define PORT "3490" // the port users will be connecting to
#define BACKLOG 20 // how many pending connections queue will hold
#define MAXDATASIZE 801 // max number of bytes we can get at once
int recv_all(int socket, char *buffer, int *length)
{
int total = 0; // how many bytes we've sent
int bytesleft = *length; // how many we have left to send
int n;
while(total < *length) {
n = recv(socket, buffer+total, bytesleft, 0);
if (n == -1) { break; }
total += n;
bytesleft -= n;
}
*length = total; // return number actually received here
return n==-1?-1:0; // return -1 on failure, 0 on success
}
int main(void)
{
int sockfd, new_fd; // listen on sock_fd, new connection on new_fd
struct addrinfo hints, *servinfo, *p;
struct sockaddr_storage their_addr; // connector's address information
socklen_t sin_size;
struct sigaction sa;
int yes=1;
char s[INET6_ADDRSTRLEN];
int rv;
double buf[MAXDATASIZE];
int lenRecv;
struct sockaddr_in local_addr; // For the new addition to bind it to an interface
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; // use my IP
if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and bind to the first we can
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
perror("server: socket");
continue;
}
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
perror("server: bind");
continue;
}
break;
}
freeaddrinfo(servinfo); // all done with this structure
if (listen(sockfd, BACKLOG) == -1) {
perror("listen");
exit(1);
}
sa.sa_handler = sigchld_handler; // reap all dead processes
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
perror("sigaction");
exit(1);
}
printf("server: waiting for connections...\n");
while(1) { // main accept() loop
sin_size = sizeof their_addr;
new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
if (new_fd == -1) {
perror("accept");
continue;
}
inet_ntop(their_addr.ss_family, get_in_addr((struct sockaddr *)&their_addr), s, sizeof s);
printf("server: got connection from %s\n", s);
if (!fork()) { // this is the child process
close(sockfd); // child doesn't need the listener
for (int i=0; i<1000000; i++) {
int rowInfoSize;
//if ((numbytes = recv(sockfd, buf, sizeof (buf), 0)) == -1) {
//if ((numbytes = recv(new_fd, buf, sizeof (buf), MSG_WAITALL)) == -1) { // I THINK THE BETTER WAY IS to CHECK THE OUTPUT AND LOOP UNTIL COMPLETE.
lenRecv = sizeof (buf);
//if (recv_all(new_fd, (char *)buf, &lenRecv) == -1) {
if (recv_all(new_fd, buf, &lenRecv) == -1) {
perror("sendall");
printf("We only sent %d bytes because of the error!\n", lenRecv);
}
}
close(new_fd);
exit(0);
}
close(new_fd); // parent doesn't need this
}
return 0;
}
You are ignoring end of stream. If n == 0 the peer has disconnected. Your code will loop forever.
Throw it all away and use recv() with the MSG_WAITALL option.
give recv_all a timeout value
int recv_all(int socket, char *buffer, int *length, int timeout)
and use select before recv()
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
looks like this
int recv_all(int socket, char *buffer, int *length)
{
int total = 0; // how many bytes we've sent
int bytesleft = *length; // how many we have left to send
int n = -1;
struct timeval timeout;
fd_set rset;
int rc;
timeout.tv_sec = 1;
timeout.tv_usec = 0;
while(total < *length) {
FD_ZERO(&rset);
FD_SET(socket, &rset);
rc = select(socket + 1, &rset, NULL, NULL, &timeout);
if(rc < 0)
{
// errno
n = -1;
break;
}
if(0 == rc)
{
// timeout
n = -1;
break;
}
if(FD_ISSET(socket, &rset))
{
n = recv(socket, buffer+total, bytesleft, 0);
if (n == -1) { break; }
total += n;
bytesleft -= n;
timeout.tv_sec = 1;
timeout.tv_usec = 0;
}
}
*length = total; // return number actually received here
return n==-1?-1:0; // return -1 on failure, 0 on success
}

listen(): invalid argument

Trying to create a server-client application, and I'm having quite a bit of trouble setting up the connection on the server-side. After setting up the socket, and bind()ing the socket, my listen()-call fails with the error message
listen: Invalid argument
which I get from perror()-ing the case where listen() returns -1.
The synopsis of the program is the following: I use getaddrinfo() to generate a linked list of struct addrinfo's, loop through that until I find one that I can successfully create a socket with, then bind() and finally listen().
The listen() call goes as follows:
if ((status = listen(socket_fd, BACKLOG_SIZE)) == -1) {
perror("listen");
close(socket_fd);
freeaddrinfo(res);
exit(EXIT_FAILURE);
}
To be sure, I've printed the values of socket_fd and BACKLOG_SIZE, turning out to be 3 and 5, respectively. Have been debugging for hours now, and I simply cannot find out where the problem lies. Haven't found anyone with the same issue on stackOverflow, either...
Thank you in advance for any help!
Full program:
int main(int argc, char* argv[]) {
int port_no = server_usage(argc, argv);
ready_connection(port_no);
/* Synopsis:
getaddrinfo()
socket()
bind()
listen()
accept()
*/
int socket_fd = setup_socket(NULL, port_no);
struct sockaddr_storage their_addr;
socklen_t addr_size = sizeof(their_addr);
int new_fd = 0;
// Allow reuse of sockets
int activate=1;
setsockopt(socket_fd, IPPROTO_TCP, TCP_NODELAY, &activate, sizeof(int));
if ((status = bind(socket_fd, res->ai_addr, res->ai_addrlen)) == -1) {
perror("bind");
exit(EXIT_FAILURE);
}
if ((status = connect(socket_fd, res->ai_addr, res->ai_addrlen)) == -1) {
perror("connect");
close(socket_fd);
freeaddrinfo(res); // free the linked-list
exit(EXIT_FAILURE);
}
if ((status = listen(socket_fd, BACKLOG_SIZE)) == -1) {
perror("listen");
close(socket_fd);
freeaddrinfo(res); // free the linked-list
exit(EXIT_FAILURE);
}
if ((new_fd == accept(socket_fd, (struct sockaddr *)&their_addr, &addr_size)) == -1) {
perror("accept");
exit(EXIT_FAILURE);
}
char buffer[BUFSIZE];
recv(new_fd, buffer, BUFSIZE, 0);
close(socket_fd);
close(new_fd);
freeaddrinfo(res); // free the linked-list
return 0;
}
setup_socket()-function:
int setup_socket(char* hostname, int port_no) {
// hints is mask struct, p is loop variable
struct addrinfo hints, *p;
memset(&hints, 0, sizeof hints); // make sure the struct is empty
// TODO IPv6-support?
hints.ai_family = AF_INET; // only IPv4 supported
hints.ai_socktype = SOCK_STREAM; // TCP stream sockets
hints.ai_flags = AI_PASSIVE; // fill in my IP for me
char port_str[6]; // max port size is 5 digits + 0-byte
memset(port_str, 0, 6);
sprintf(port_str, "%d", port_no);
if ((status = getaddrinfo(hostname, port_str, &hints, &res)) == -1) {
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
exit(EXIT_FAILURE);
}
int socket_fd = 0;
for (p = res; p != NULL; p = p->ai_next) {
if ((socket_fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
perror("socket");
exit(EXIT_FAILURE);
}
}
if (socket_fd == 0) {
errno = ENOTSOCK;
perror("no socket");
exit(EXIT_FAILURE);
}
return socket_fd;
}
You cannot connect(), then listen() on the same socket. Lose the connect().

Multi session chat server in C

I am trying to write a multi session chat server in C. I host the server from one terminal and telnet to it from other terminals.
Using ubuntu 13.04 on VMWare player.
What happens is this:
I'm incrementing a loop from 3 onward to fdmax, to accept new connections using sd ( the listener) and newsd represents the new socket descriptor.
When I print 'hi' in one window, it prints in ALL windows including the one I typed in. Plus, a lot of random junk keeps appearing.
I want only what I type to appear(how do i get rid of the junk>), and in all the windows except the one I typed it in!
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<netdb.h>
#include<arpa/inet.h>
#include<stdlib.h>
#include<unistd.h>
#include<stdio.h>
#include<string.h>
#include<sys/select.h>
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)
{
//ptr used for traversal, serv used for the linked list of struct addinfos , hints for the getaddrinfo function
struct addrinfo *ptr, hints, *serv;
int max_cli, dat, x, i;
struct sockaddr_storage cli_addr;
socklen_t addr_size;
char cli_ip[INET_ADDRSTRLEN];
char inc[256]; //one command line is 80 characters
memset(inc, 0, strlen(inc));
int sd, newsd;
fd_set master;
fd_set read_fds;
char value[256];
FD_ZERO(&master);
FD_ZERO(&read_fds);
//argv[1]-server ip argv[2]-server port argv[3]-maximum client number
int fdmax;
int opt = 1;
/*if(argc!=4)
{
printf("Please re-enter data. Data insufficient\n");
exit(1);
}
if(atoi(argv[2])<1025)
{
printf("Reserved port. Please try again\n");
exit(1);
}*/
max_cli = atoi(argv[3]);
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
/* Verify the inputs and generate linked list of possible IPs to use*/
if (sd = getaddrinfo(argv[1], argv[2], &hints, &serv))
{
fprintf(stderr, "Error calling getaddrinfo %s\n", gai_strerror(sd));
exit(1);
}
for (ptr = serv; ptr != NULL ; ptr = ptr->ai_next)
{
void *addr;
if (ptr->ai_family == AF_INET)
{
struct sockaddr_in *ipv4 = (struct sockaddr_in *) ptr->ai_addr;
addr = &(ipv4->sin_addr);
}
inet_ntop(ptr->ai_family, addr, value, sizeof value);
//printf("%s\n",value);
//Form connection with one of the IP addresses
sd = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
if (sd < 0)
continue;
setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt);
if (bind(sd, ptr->ai_addr, ptr->ai_addrlen) < 0)
{
close(sd);
continue;
}
break; //Indicates one working socket found and bound
} //end for
if (ptr == NULL )
{
fprintf(stderr, "Bind failed\n");
exit(2);
}
freeaddrinfo(serv);
if (listen(sd, 15) == -1)
{
printf("Error occurred while listening\n");
exit(3);
}
/* Socket found, bound and now listening for active connections*/
FD_SET(sd, &master);
fdmax = sd; //Latest active socket descriptor
while (1)
{
read_fds = master; //Copy the master list so that the original list doesn't get damaged
if (select(fdmax + 1, &read_fds, NULL, NULL, NULL ) == -1)
{
perror("Select failed.\n");
exit(4);
}
for (i = 3; i <= fdmax; i++)
{
//printf("i");
//printf("entered for loop\n");
if (FD_ISSET(i,&read_fds)) //new connection->false, existing one->true
{
// printf("Started reading descriptors!\n");
if (i == sd) //primary connection,exists, accept new file descriptor
{ //printf("Read first connection!\n");
addr_size = sizeof cli_addr;
newsd = accept(sd, (struct sockaddr *) &cli_addr, &addr_size);
printf("Accepted new connection socket %d\n", newsd);
FD_SET(newsd, &master);
if (newsd == -1)
{
perror("accept");
}
if (newsd > fdmax)
{
fdmax = newsd;
}
printf("%d %d\n", newsd, fdmax);
continue;
}
else if (i != sd) //existing connection, so accept data
{
if (dat = recv(i, &inc, sizeof inc, 0) <= 0)
{
if (dat == 0)
{
printf(" Socket %d has quit the chatroom", i);
}
if (dat < 0)
{
perror("Error on Receive");
}
// char *s=&inc;
//printf("%d\n %s",dat);
close(i);
FD_CLR(i, &master);
}
//Nothing wrong with the input from client i. Broadcast!
else
{
for (x = 3; x <= fdmax; x++)
{
if (FD_ISSET(x,&master))
{
if (x != sd)
{
//send(x,&inc,sizeof inc,0);
if (send(x, &inc, sizeof inc, 0) < 0)
{
perror("Send");
}
}
}
}
}
}
}
/*else// new connection
{ break;
printf("SERVERBOT: new connection from %s on socket %d\n",inet_ntop(cli_addr.ss_family,get_in_addr((struct sockaddr*)&cli_addr),cli_ip, INET6_ADDRSTRLEN),newsd);
}////change this to 'username' has joined the room*/
}
}
return 0;
}
First of all, when you send received data, you use sizeof operator, which gives you total size of array. You should send just as many bytes as you received, which will often be less. Use return value of recv to know how many bytes were actually received. In general, C arrays do not have dynamic size, you have to keep track of that yourself.
Then about garbage, you probably print buffer contents without terminating '\0' character. So, either add that (make sure there is the 1 byte of extra space in the buffer!) before printing or using other string functions, or use a printing function which accepts maximum size of string in case that terminating nul is missing.
for a start your send must use dat as length not sizeof(inc)

Unable to connect 2 machines using ipv6 (TCP server client )

I was trying to do a simple tcp server client using ipv6. It works on the same machine for ipv6 and ipv4 but when on different machines ipv6 fails to connect.
Server Code
int main(int argc, char* argv[])
{
int sockfd,new_fd,rv,yes=1;
struct addrinfo hints,*servinfo,*p;
struct sockaddr_storage their_addr;
socklen_t addr_size;
SOCKET listenSocket,clientSocket;
WSADATA w;
if (WSAStartup(0x0101, &w) != 0)
{
fprintf(stderr, "Could not open Windows connection.\n");
exit(0);
}
//ip=argv[1];
//port=argv[2];
memset(&hints,0,sizeof(hints));
hints.ai_family=AF_INET6;
hints.ai_socktype=SOCK_STREAM;
hints.ai_flags=AI_NUMERICHOST;
if((rv = getaddrinfo("fe80::c0a8:0160","5002",&hints,&servinfo)) != 0)
{
perror("\nGetaddrinfo failed\n");
return 1;
}
//Creating socket
listenSocket = socket(servinfo->ai_family,servinfo->ai_socktype,servinfo->ai_protocol);
if(listenSocket == INVALID_SOCKET)
{
printf("\nSocket failed with error \n");
WSACleanup();
}
//setting non blocking mode
u_long iMode = 1;
rv = ioctlsocket(listenSocket,FIONBIO,&iMode);
if(rv == SOCKET_ERROR)
{
printf("\nioctl failed\n");
WSACleanup();
}
rv = bind(listenSocket,servinfo->ai_addr,(int)servinfo->ai_addrlen);
if(rv == SOCKET_ERROR)
{
perror("\nBind: \n");
}
freeaddrinfo(servinfo);
rv = listen(listenSocket,SOMAXCONN);
if(rv == SOCKET_ERROR)
{
perror("listen");
return 1;
}
// now accept an incoming connection:
char recvbuf[DEFAULT_BUFLEN];
int buflen = DEFAULT_BUFLEN;
SOCKET AcceptSocket;
while (1)
{
AcceptSocket = SOCKET_ERROR;
while (AcceptSocket == SOCKET_ERROR)
{
AcceptSocket = accept(listenSocket, NULL, NULL);
}
printf("Server: Client Connected!\n");
listenSocket = AcceptSocket;
rv = recv(listenSocket,recvbuf,buflen,0);
break;
}
printf("Received %d bytes from client \n",rv);
closesocket(listenSocket);
closesocket(AcceptSocket);
return 0;
}
Client Code
int main(int argc,char* argv[])
{
struct addrinfo hints,*servinfo,*p;
int rv;
SOCKET connectSocket;
WSADATA w;
if (WSAStartup(0x0101, &w) != 0)
{
fprintf(stderr, "Could not open Windows connection.\n");
exit(0);
}
//resetting memory
memset(&hints,0,sizeof(hints));
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_NUMERICHOST;
//getting values
if((rv = getaddrinfo("fe80::c0a8:160","5002",&hints,&servinfo)) != 0)
{
perror("Getaddrinfo failed");
return 1;
}
//Creating socket
connectSocket = socket(servinfo->ai_family,servinfo->ai_socktype,servinfo->ai_protocol);
if(connectSocket == INVALID_SOCKET)
{
perror("Socket create : ");
}
rv = connect(connectSocket,servinfo->ai_addr,(int)servinfo->ai_addrlen);
if(rv == SOCKET_ERROR)
{
perror("Socket Connect : ");
}
//free memory
freeaddrinfo(servinfo);
// Send and receive data.
int bytesSent;
char sendbuf[200] = "Client: Sending some test string to server...";
char recvbuf[200] = "";
bytesSent = send(connectSocket, sendbuf, strlen(sendbuf), 0);
printf("Client: send() - Bytes Sent: %ld\n", bytesSent);
closesocket(connectSocket);
return 0;
}
The aim is just to print how many bytes transferred.
It appears that you're using a link local address. Are you sure for that? Also, I'd suggest you check your firewall settings first.
EDIT:
Try to include the zone ID. When you issue the ipconfig in command prompt, you should be able to get addresses like fe80::c0a8:0160%21 where %21 is the zone ID. It's important when you use link local addresses according to this answer.

Resources