I'm trying to create a server socket with C++ in order to accept one client connection at a time. The program successfully creates the server socket and waits for incoming connections but when a connection is closed by the client the program would loop endlessly. Otherwise if the connection is interrupted it would keep waiting for new connections as expected. Any idea why this is happening? Thanks
This is my C++ server code:
int listenfd, connfd, n;
struct sockaddr_in servaddr, cliaddr;
socklen_t clilen;
pid_t childpid;
char mesg[1000];
listenfd = socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(32000);
bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
listen(listenfd, 1024);
while (true) {
clilen = sizeof(cliaddr);
connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen);
if ((childpid = fork()) == 0) {
close (listenfd);
while (true) {
n = recvfrom(connfd, mesg, 1000, 0, (struct sockaddr *)&cliaddr, &clilen);
sendto(connfd, mesg, n, 0, (struct sockaddr *)&cliaddr, sizeof(cliaddr));
mesg[n] = 0;
printf("%d: %s \n", n, mesg);
if (n <= 0) break;
}
close(connfd);
}
}
For some reason when the client closes the connection the program would keep printing -1: even with the if-break clause..
You never close connfd in parent process (when childpid != 0), and you do not properly terminate child process that will try to loop. Your if block should look like :
if ((childpid = fork()) == 0) {
...
close(connfd);
exit(0);
}
else {
close(connfd);
}
But as you say you want to accept one connection at a time, you can simply not fork.
And as seen in other answers :
do not use mesg[n] without testing n >= 0
recvfrom and sendto are overkill for TCP simply use recv and send (or even read and write)
mesg[n] = 0;
This breaks when n<0, ie. socket closed
The problem is your "n" and recvfrom. You are having a TCP client so the recvfrom won't return the correct value.
try to have a look on :
How to send and receive data socket TCP (C/C++)
Edit 1 :
Take note that you do the binding not connect() http://www.beej.us/guide/bgnet/output/html/multipage/recvman.html
means there is an error in recieving data, errno will be set accordingly, please try to check the error flag.
you've written a TCP server, but you use recvfrom and sendto which are specific for connection-less protocols (UDP).
try with recv and send. maybe that might help.
Related
I have a tcp server and 2 clients that want to connect to it. The way this clients will connect is that 1 of them, lets call it client1 will be all the time connected sending data and the other, client2, will eventually connect, send small amount of data and disconnect. I set O_NONBLOCK option on. The behaviour I experience is that the client that is continuosly sending data,on server side, receives one message and wait for the next connection... Here is what i tried so far(The code is the while where in any moment the client2 wants to connect and send data and disconnect):
fcntl(sockfd, F_SETFL, O_NONBLOCK);
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
error("ERROR on binding");
listen(sockfd, 5);
clilen = sizeof(cli_addr);
int flag = 0;
do {
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if(newsockfd > 0){
//Sockets Layer Call: inet_ntop()
inet_ntop(AF_INET6, &(cli_addr.sin6_addr),client_addr_ipv6, 100);
printf("Incoming connection from client having IPv6 address: %s\n",client_addr_ipv6);
n = recv(newsockfd, buffer, 49,0);
if(n > 0){
send_data(argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],buffer);
memset(buffer,0,sizeof(buffer));
}
}
newsockfd2 = accept(sockfd, (struct sockaddr *) &cli_addr2, &clilen);
//Sockets Layer Call: inet_ntop()
if(newsockfd2 > 0){
inet_ntop(AF_INET6, &(cli_addr2.sin6_addr),client_addr_ipv6, 100);
printf("Incoming connection from client having IPv6 address: %s\n",client_addr_ipv6);
n2= recv(newsockfd2, buffer, 49, 0);
if(n2 > 0){
send_data(argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],buffer);
memset(buffer,0,sizeof(buffer));
}
}
}while(!flag);
I also tried adding the option inside of the while and setting nonblocking on newsockfd and newsockfd2but same result.
What am I doing wrong? thanks ! :D
When a new socket is retuned from accept, you must create a new thread with this socket so that one-to-one communication will be handled in this thread. The socked doesn't have to ne non-blocking.
I want to implement a 'flexible' TCP connection where I can randomly shutdown and restart both the Server and the Client. The other one should then automatically detect the shutdown and enter try to reconnect. I successfully implemented this s.t. I can shutdown and restart the server. The client discovers the shutdown (via recv(...) == 0) and then closes the connection (it therefore closes the sockets close(this->sockfd_) and close(this->newsockfd_)).
Unfortunately I am not able to get this working the other way around. I initialize the server (using the class constructor) the following way:
tcpServer::tcpServer(int _port) {
this->sockfd_ = -1;
this->port_ = _port;
this->connected_ = false;
if ((this->sockfd_ = socket(AF_INET, SOCK_STREAM, 0)) < 0)
this->dieWithError("ERROR opening Socket");
else
printf("-> Port %d: Socket opened\n", this->port_);
// get rid of "address already in use" error message
int yes = 1;
setsockopt(this->sockfd_, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
/* assign values to the fields of struct sockaddr_in */
bzero((char *) &this->serv_addr_, sizeof(this->serv_addr_));
this->serv_addr_.sin_family = AF_INET;
this->serv_addr_.sin_port = htons(this->port_);
this->serv_addr_.sin_addr.s_addr = INADDR_ANY;
/* bind the socket to an address */
if (bind(this->sockfd_, (struct sockaddr *) &this->serv_addr_, sizeof(this->serv_addr_)) < 0) {
printf("-> Port %d:", this->port_);
this->dieWithError("ERROR on binding");
}
printf("-> Binding successful. Start TCP client in new terminal\n");
fflush(stdout);
/* listen for connections and accept a connection */
listen(this->sockfd_, 5);
this->clilen_ = sizeof(this->cli_addr_);
if ((this->newsockfd_ = accept(this->sockfd_, (struct sockaddr *) &this->cli_addr_, &this->clilen_)) < 0)
this->dieWithError("Error on accept");
else {
printf("-> Connection established\n");
this->connected_ = true;
}
}
So once the server detects that the connection is closed, it enters a loop where it tries to reconnect using the following code:
void tcpServer::connect() {
if (this->sockfd_ == -1) {
/* create socket */
if ((this->sockfd_ = socket(AF_INET, SOCK_STREAM, 0)) < 0)
this->dieWithError("ERROR opening Socket");
else
printf("-> Port %d: Socket opened\n", this->port_);
// get rid of "address already in use" error message
int reuse_address = 1;
setsockopt(this->sockfd_, SOL_SOCKET, SO_REUSEADDR, &reuse_address, sizeof(int));
/* listen for connections and accept a connection */
listen(this->sockfd_, 5);
this->clilen_ = sizeof(this->cli_addr_);
if ((this->newsockfd_ = accept(this->sockfd_, (struct sockaddr *) &this->cli_addr_, &this->clilen_)) < 0)
this->dieWithError("Error on accept");
else {
printf("-> Connection established\n");
this->connected_ = true;
}
}
}
Some simple debugging output tells me that in the reconnect-mode, the server gets stuck in the
accept(this->sockfd_, (struct sockaddr *) &this->cli_addr_, &this->clilen_) call. Another observation I made is that the client does not shut down properly (via ctrl-c), i.e., it gets stuck in a loop somewhere and does not properly close the connection.
Since I am a total beginner with the TCP stuff, I would be very happy if someone could point me to the right direction. Thank you.
I have problem while reading data from client on server. The read() function will always freeze (block) after all data are readed and waiting for more data what is undesirable for me.
Server program:
soc = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
sin.sin_addr.s_addr = INADDR_ANY;
bind(soc, (struct sockaddr*) &sin, sizeof(sin));
if (listen(soc, MAX))
return;
int socc; // socket for clinet
while (1) {
if ((socc = accept(soc, (struct sockaddr *) &sin, sinlen)) < 0)
break;
while ((result = read(socc, pointer, SIZE)) > 0) {
// after the data are readed, read function will block
}
// do some stuff and write reply to client => will never done
}
Client program:
...
soc = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
struct sockaddr_in socketAddr;
socketAddr.sin_family = AF_INET;
socketAddr.sin_port = htons(port);
memcpy(&(socketAddr.sin_addr), host->h_addr, host->h_length);
if (connect(soc, (sockaddr *)&socketAddr, sizeof(socketAddr)) == -1)
return;
if (write(soc, req.c_str(), strlen(req.c_str())) < 0)
return;
The main problem is that I don't know how much data will be client sending to server, so the server should read all data from socket and after nothing is coming, leave the reading cycle. But the server read whole message for example (30 bytes) and waiting for more (but no more is coming). The sockets are still opened because the client is waiting for reply from server.
You will need to make your socket non-blocking. The read will immediately exit in that case if there is nothing to be read with a specific error.
Look at C- Unix Sockets - Non-blocking read
As stated earlier use non blocking or add RCV_TIMEOUT to socket.
struct timeval tv;
tv.tv_sec = 30; /* 30 Secs Timeout */
setsockopt(sockid, SOL_SOCKET, SO_RCVTIMEO,(struct timeval *)&tv,sizeof(struct timeval));
I'm experiencing some issues with rewriting my blocking socket server to a non-blocking version.
Actually, I can't seem to even get socket connected anymore, I've been googling for the most of today, and trying different solutions I find here and there, but none of them seem to work properly...
Currently my server loop just keeps timeouting the select() call, with no new sockets accepted.
Client socket seems to connect on some level, since if I start it, it will block trying to write, and if I close the server, it will inform that connection was reset by peer.
Is the following a correct assumption?
With non-blocking server I should normally open the socket, then set it's flags to non-blocking, bind it, and the start calling select for read file descriptor and wait for it to populate ?
I need to remove old blocking "accept()" call, which was waiting endlessly..
If I try calling accept, it will -1 on me now...
Here is the relevant code I'm trying now
fd_set incoming_sockets;
....
int listener_socket, newsockfd, portno;
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
....
listener_socket = socket(AF_INET, SOCK_STREAM, 0); //get socket handle
int flags = fcntl(listener_socket, F_GETFL, 0);
if( fcntl(listener_socket, F_SETFL, flags | O_NONBLOCK) < 0 )
log_writer->write_to_error_log("Error setting listening socket to non blocking", false);
memset(&serv_addr, 0, sizeof(struct sockaddr_in));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
....
if (bind(listener_socket, (struct sockaddr *) &serv_addr,
sizeof(struct sockaddr_in)) < 0)
{
log_writer->write_to_error_log("Unable to bind socket, aborting!", true);
}
....
struct timeval timeout;
timeout.tv_sec = 1;
timeout.tv_usec = 0;
int ready_sockets = 0;
listen(listener_socket,1);
FD_ZERO(&incoming_sockets);
FD_SET(listener_socket, &incoming_sockets);
while(true)
{
ready_sockets = select(listener_socket + 1 , &incoming_sockets, (fd_set * ) 0, (fd_set * ) 0, &timeout );
if(ready_sockets == 0)
{
//I loop here now for ever
std::cout << "no new sockets available, snooze 2\n";
sleep(2);
} else
{
std::cout << "connection received!\n";
Since you don't show the whole loop, I don't know if you do it later, but you should initialize the descriptor sets and timeout structure before every call to select.
You should mover the fd_zero() fd_set() macros inside the loop, select will actually change the bitmasks in the fd_sets (and the timeout value). Reinitialise them on every iteration. Also check for select returning -1 and the associated errno (EPIPE ...)
while(true)
{
FD_ZERO(&incoming_sockets);
FD_SET(listener_socket, &incoming_sockets);
ready_sockets = select(listener_socket + 1 , &incoming_sockets, (fd_set * ) 0, (fd_set * ) 0, &timeout );
if(ready_sockets == 0)
{
... }
I have a socket that listens on some port.
I send the SIGSTOP signal to the thread that waits on the port (using accept) and terminate it. then I close the fd of the socket that I waited on. But for the next run of my project it doe's not allow me to listen on that port again.
My program is in C++ under linux.
What should I do?
Some parts of my code are:
Thread 1:
void* accepter(void *portNo) {
int newsockfd;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("ERROR opening socket");
}
struct sockaddr_in server;
bzero((char *) & server, sizeof (server));
server.sin_family = AF_INET;
server.sin_port = htons(*(int*) portNo);
server.sin_addr.s_addr = INADDR_ANY;
if (bind(sockfd, (struct sockaddr *) & server, sizeof (struct sockaddr_in)) < 0) {
perror("ERROR on binding");
}
listen(sockfd, 50);
while (true) {
struct sockaddr_in client;
socklen_t clientLen = sizeof (struct sockaddr_in);
newsockfd = accept(sockfd, (struct sockaddr *) & client, &clientLen);
if (accepterFlag) {
break;
}
if (getpeername(newsockfd, (sockaddr *) & client, &clientLen) == -1) {
perror("getpeername() failed");
}
sem_wait(setSem);
FD_SET(newsockfd, &set);
if (maxFd < newsockfd) {
maxFd = newsockfd;
}
sem_post(setSem);
}
Thread 2:
listenerFlag = true;
accepterFlag = true;
sleep(1);
pthread_kill(listenerThread, SIGSTOP);
pthread_kill(accepterThread, SIGSTOP);
close(sockfd);
sem_wait(setSem);
for (int i = 1; i <= maxFd; i++) {
if (FD_ISSET(i, &set)) {
close(i);
}
}
sem_post(setSem);
Thank you.
Did you know that sockets are typically kept in a kind of limbo for a minute or two after you've finished listening on them to prevent communications intended for the previous process coming to yours? It's called the 'TIME_WAIT' state.
If you want to override that behaviour use setsockopt to set the SO_REUSEADDR flag against the socket before listening on it.
I think the problem is that you have not properly closed the socket and/or your program.The socket probably still exists in the OS. check it with something like nestat -an. You should also check if your process has exited. If it has correctly ended, it should have closed your socket.
What you should do is :
interrupt your thread with a signal.
when interrupted your thread should cleanly close the socket before the end.
then you can cleanly exit from your program.
my2cents,