I am trying have non-blocking I/O between a server and client. After the two are connected, I am trying to use fork to handle the IO, but the server side gets an error when trying to read of “Transport endpoint is not connected” and it happens twice (because of fork I’m guessing?).
Server code
//includes taken out
#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;
//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);
}
cout<<"\nSuccessful Connection!";
//set nonblock
set_nonblock(new_sd);
char* in = new char[255];
char* out = new char[255];
int numSent;
int numRead;
pid_t pid;
fork();
pid = getpid();
if(pid == 0) {
while( !(out[0] == 'q' && out[1] == 'u' && out[2] == 'i' && out[3] == 't') ) {
fgets(out, 255, stdin);
numSent = send(sock, out, strlen(out), 0);
if(numSent < 0) {
printf("\nError sending %m", errno);
exit(1);
} //end error
} //end while
} //end child
else {
numRead = recv(sock, in, 255, 0);
if(numRead < 0) {
printf("\nError reading %m", errno);
exit(1);
} //end error
else {
cout<<in;
for(int i=0;i<255;i++)
in[i] = '\0';
} //end else
} //end parent
cout<<"\n\nExiting normally\n";
return 0;
}
Client code
//includes taken out
#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
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
set_nonblock(sock);
char* out = new char[255];
char* in = new char[255];
int numRead;
int numSent;
pid_t pid;
fork();
pid = getpid();
if(pid == 0) {
while( !(out[0] == 'q' && out[1] == 'u' && out[2] == 'i' && out[3] == 't') ) {
fgets(out, 255, stdin);
numSent = send(sock, out, strlen(out), 0);
if(numSent < 0) {
printf("\nError sending %m", errno);
exit(1);
} //end error
} //end while
} //end child process
else {
while( !(in[0] == 'q' && in[1] == 'u' && in[2] == 'i' && in[3] == 't') ) {
numRead = recv(sock, in, 255, 0);
cout<<in;
for(int i=0;i<255;i++)
in[i] = '\0';
}
} //end parent process
cout<<"\n\nExiting normally\n";
return 0;
}
I also tried using threads to do the I/O. The problem there is that when I run the program, its like the threads don’t occur. The program just runs with a “Successful Connection” and then “exiting normally.” I put some cout statements into the while(1) loops and they did print out a few times, but they just stop for some reason. I’m not sure if its a problem with my threads or my sockets. The code (very similar to above) for that is here –
Server
//includes taken out
#define PORT "4950"
#define STDIN 0
pthread_t readthread;
pthread_t sendthread;
char* in = new char[255];
char* out = new char[255];
int numSent;
int numRead;
struct sockaddr name;
int sock, new_sd;
void* readThread(void* threadid) {
while(1) {
numRead = recv(new_sd, in, 255, 0);
if(numRead > 0) {
cout<<"\n"<<in;
for(int i=0;i<strlen(in);i++)
in[i] = '\0';
} //end if
else if(numRead < 0) {
printf("\nError reading %m", errno);
exit(1);
}
} //end while
} //END READTHREAD
void* sendThread(void* threadid) {
while(1) {
cin.getline(out, 255);
numSent = send(new_sd, out, 255, 0);
if(numSent > 0) {
for(int i=0;i<strlen(out);i++)
out[i] = '\0';
} //end if
else if(numSent < 0) {
printf("\nError sending %m", errno);
exit(1);
}
} //end while
} //END SENDTHREAD
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, adrlen;
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;
//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);
}
cout<<"\nSuccessful Connection!";
//set nonblock
set_nonblock(new_sd);
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_create(&readthread, &attr, readThread, (void*)0);
pthread_create(&sendthread, &attr, sendThread, (void*)1);
cout<<"\n\nExiting normally\n";
return 0;
}
Client
#define PORT "4950"
pthread_t readthread;
pthread_t sendthread;
char* in = new char[255];
char* out = new char[255];
int numSent;
int numRead;
struct sockaddr name;
int sock;
void* readThread(void* threadid) {
while(1) {
numRead = recv(sock, in, 255, 0);
if(numRead > 0) {
cout<<"\n"<<in;
for(int i=0;i<strlen(in);i++)
in[i] = '\0';
} //end if
else if(numRead < 0) {
printf("\nError reading %m", errno);
exit(1);
}
} //end while
} //END READTHREAD
void* sendThread(void* threadid) {
while(1) {
cin.getline(out, 255);
numSent = send(sock, out, 255, 0);
if(numSent > 0) {
for(int i=0;i<strlen(out);i++)
out[i] = '\0';
} //end if
else if(numSent < 0) {
printf("\nError sending %m", errno);
exit(1);
}
} //end while
} //END SENDTHREAD
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, adrlen;
struct addrinfo hints;
struct addrinfo *servinfo; //will point to the results
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
set_nonblock(sock);
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_create(&readthread, &attr, readThread, (void*)0);
pthread_create(&sendthread, &attr, sendThread, (void*)1);
cout<<"\n\nExiting normally\n";
return 0;
}
I apologize for the long post, but I have been at this for a few days now and am not sure how to proceed. I tried using select(), but that seems like a little much for just 1 client and a server I/O. If anyone can point out what may be going wrong above or any other tips (or I’m just plain wrong about select :)) I would greatly appreciate it.
I looked at the first two codes server and client. Unfortunately, you designed your program mistakenly. The server is supposed to do the following (in case of multi-processes):
sockis ONLY responsible to listen for new connection and it is not responsible to send/recv as you did.Here is a pseudo-code
UPDATE: since you are looking for non-blocking scenario, i would recommend you to use select() or poll() system calls.
I feel that you want to create two processes such that one process is for sending and another for receiving. If so, then you don’t need to set new_sd to non-blocking mode since these two processes are running at the same time. If you are planning to do that, then the child process will create another process such that the first child do sending and the second child do receiving. As follows: