C++ Reconnect TCP Server to Client after Client restart - c++

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.

Related

C/C++: socket() creation fails in the loop, too many open files

I am implementing a client-server TCP socket application. Client is on an OpenWRT Linux router (C based) and writes some data on the socket repeatedly and in a loop at some frequency rate. The Server is on a Linux Ubuntu machine (C/C++ based) and reads data in a loop according to data arrival speed.
Problem: Running the Server and then Client, server keeps reading new data. Both sides work well until the number of data deliveries (# of connections) reaches 1013. After that, the Client stuck at socket(AF_INET,SOCK_STREAM,0) with socket creation failed...: Too many open files. Apparently, the number of open fd approaches ulimit -n = 1024 on client.
I put the snippets of the code which shows the loop structures for Server.cpp and Client.c:
Server.c:
// TCP Socket creation stuff over here (work as they should):
// int sock_ = socket() / bind() / listen()
while (1)
{
socklen_t sizeOfserv_addr = sizeof(serv_addr_);
fd_set set;
struct timeval timeout;
int connfd_;
FD_ZERO(&set);
FD_SET(sock_, &set);
timeout.tv_sec = 10;
timeout.tv_usec = 0;
int rv_ = select(sock_ + 1, &set, NULL, NULL, &timeout);
if(rv_ == -1){
perror("select");
return 1;
}
else if(rv_ == 0){
printf("Client disconnected.."); /* a timeout occured */
close (connfd_);
close (sock_);
}
else{
connfd_ = accept (sock_,(struct sockaddr*)&serv_addr_,(socklen_t*)&sizeOfserv_addr);
if (connfd_ >= 0) {
int ret = read (connfd_, &payload, sizeof(payload)); /* some payload */
if (ret > 0)
printf("Received %d bytes !\n", ret);
close (connfd_); /* Keep parent socket open (sock_) */
}else{
printf("Server acccept failed..\n");
close (connfd_);
close (stcp.sock_);
return 0;
}
}
}
Client.cpp:
while (payload_exist) /* assuming payload_exist is true */
{
struct sockaddr_in servaddr;
int sock;
if (sock = socket(AF_INET, SOCK_STREAM, 0) == -1)
perror("socket creation failed...\n");
int one = 1;
int idletime = 2;
setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(one));
setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &idletime, sizeof(idletime));
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr("192.168.100.12");
servaddr.sin_port = htons(PORT); /* some PORT */
if (connect (sock, (struct sockaddr*)&servaddr, sizeof(servaddr)) != 0){
perror("connect failed...");
return 1;
}
write(sock, (struct sockaddr*)&payload, sizeof(payload)); /* some new payload */
shutdown(sock,SHUT_WR);
bool serverOff = false;
while (!serverOff){
if(read(sock, &res, sizeof(res)) < 0){
serverOff = true;
close(sock);
}
}
}
NOTE: payload is 800 bytes and always gets fully transmitted per one write action. Having both codes defined under int main(), the client keeps creating sockets and sending data, on the other side, server receives all and would automatically close() and leave if client terminates, due to using select(). If I don't terminate the Client, however, by checking some print logs, it is evident that Server successfully receives 1013 payloads before client crashes with socket creation failed...: Too many open files.
Update:
Following the point mentioned by Steffen Ullrich, it turned out that, the client socket fd has no leak, and the existence of a second fd in the original loop (which was left open) was making the ulimit exceed the limit.
if(read(sock, &res, sizeof(res)) < 0){
serverOff = true;
close(sock); /********* Not actually closing sock *********/
}
Your check for end of connection is wrong.
read returns 0 if the other side has shut down the connection and <0 only on error.
if (sock = socket(AF_INET, SOCK_STREAM, 0) == -1)
perror("socket creation failed...\n");
Given the precedence of operators in C this basically says:
sock = ( socket(AF_INET, SOCK_STREAM, 0) == -1) )
if (sock) ...
Assuming that socket(...) will not return an error but a file descriptor (i.e. >=0) the comparison will be false and thus this essentially says sock = 0 while leaking a file descriptor if the fd returned by socket was >0.

Server socket finishes when client closes connection

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.

Getting "Transport endpoint is not connected" in UDP socket programming in C++

I am getting Transport endpoint is not connected error in UDP server program, while I am try to
shutdown the socket via shutdown(m_ReceiveSocketId, SHUT_RDWR);
Following is my code snippet:
bool UDPSocket::receiveMessage()
{
struct sockaddr_in serverAddr; //Information about the server
struct hostent *hostp; // Information about this device
char buffer[BUFFERSIZE]; // Buffer to store incoming message
int serverlen; // to store server address length
//Open a datagram Socket
if((m_ReceiveSocketId = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
Utility_SingleTon::printLog(LOG_ERROR,"(%s %s %d) UDP Client - socket() error",__FILE__,__func__, __LINE__);
pthread_exit(NULL);
return false;
}
//Configure Server Address.
//set family and port
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(m_ListeningPort);
if (bind(m_ReceiveSocketId, (struct sockaddr *) &serverAddr,sizeof(struct sockaddr_in)) < 0 )
{
Utility_SingleTon::printLog(LOG_ERROR,"(%s %s %d) UDP Client- Socket Bind error=%s",__FILE__,__func__, __LINE__,strerror(errno));
pthread_exit(NULL);
return false;
}
//TODO Re-Route Mechanism.
if((serverAddr.sin_addr.s_addr = inet_addr(m_ServerIPStr.c_str())) == (unsigned long)INADDR_NONE)
{
/* Use the gethostbyname() function to retrieve */
/* the address of the host server if the system */
/* passed the host name of the server as a parameter. */
/************************************************/
/* get server address */
hostp = gethostbyname(m_ServerIPStr.c_str());
if(hostp == (struct hostent *)NULL)
{
/* h_errno is usually defined */
/* in netdb.h */
Utility_SingleTon::printLog(LOG_ERROR,"%s %d %s %s %d", "Host Not found", h_errno,__FILE__,__func__, __LINE__);
pthread_exit(NULL);
return false;
}
memcpy(&serverAddr.sin_addr, hostp->h_addr, sizeof(serverAddr.sin_addr));
}
serverlen = (int )sizeof(serverAddr);
// Loop and listen for incoming message
while(m_RecevieFlag)
{
int receivedByte = 0;
memset(buffer, 0, BUFFERSIZE);
//receive data from the server
receivedByte = recvfrom(m_ReceiveSocketId, buffer, BUFFERSIZE, 0, (struct sockaddr *)&serverAddr, (socklen_t*)&serverlen);
if(receivedByte == -1)
{
Utility_SingleTon::printLog(LOG_ERROR,"[%s:%d#%s] UDP Client - receive error",__FILE__,__LINE__,__func__);
close(m_ReceiveSocketId);
pthread_exit(NULL);
return false;
}
else if(receivedByte > 0)
{
string rMesg;
rMesg.erase();
for(int loop = 0; loop < receivedByte; loop++)
rMesg.append(1, buffer[loop]);
Utility_SingleTon::printLog(LOG_DEBUG,"[%s:%d#%s] received message=%d",__FILE__,__LINE__,__func__, rMesg.length());
QOMManager_SingleTon::getInstance()->setReceivedMessage(rMesg);
raise(SIGUSR1);
}
}
close(m_ReceiveSocketId);
pthread_exit(NULL);
return true;
}
Any help would be appreciated.
Thanks Yuvi.
You don't need to call shutdown() for a UDP socket. From the man page:
The shutdown() call causes all or part of a full-duplex connection on the socket
associated with sockfd to be shut down.
If you call shutdown() on a UDP socket, it will return ENOTCONN
(The specified socket is not connected) because UDP is a connectionless protocol.
All you need to do is close the socket and set the socket to INVALID_SOCKET. Then in your destructor check whether the socket has already been set to INVALID_SOCKET before closing it.

C++ UDP. Why is recvfrom() is not blocking?

I am writing some simple client/server code using UDP. The program works fine, but if I only start the client, the recvfrom method does not block. However, when I remove the sendto method, recvfrom starts to block. Any idea of what is going on?
Here is the client side code:
int server_length; /* Length of server struct */
char send_buffer[256] = "hi"; /* Data to send */
time_t current_time; /* Time received */
while(true)
{
/* Tranmsit data to get time */
server_length = sizeof(struct sockaddr_in);
if (sendto(m_oSocket, send_buffer, (int)strlen(send_buffer) + 1, 0, (struct sockaddr *)&m_oServer, server_length) == -1)
{
fprintf(stderr, "Error transmitting data.\n");
continue;
}
/* Receive time */
if (recvfrom(m_oSocket, (char *)&current_time, (int)sizeof(current_time), 0, (struct sockaddr *)&m_oServer, &server_length) < 0)
{
fprintf(stderr, "Error receiving data.\n");
continue;
}
/* Display time */
printf("Current time: %s\n", ctime(&current_time));
Sleep(1000);
}
And here is the initialization:
unsigned short m_iPortnumber;
struct sockaddr_in m_oServer;
struct sockaddr_in m_oClient;
SOCKET m_oSocket;
WSADATA w; /* Used to open Windows connection */
int a1, a2, a3, a4; /* Server address components in xxx.xxx.xxx.xxx form */
a1 = 192;
a2 = 168;
a3 = 2;
a4 = 14;
m_iPortnumber = 52685;
/* Open windows connection */
if (WSAStartup(0x0101, &w) != 0)
{
fprintf(stderr, "Could not open Windows connection.\n");
exit(0);
}
/* Open a datagram socket */
m_oSocket = socket(AF_INET, SOCK_DGRAM, 0);
if (m_oSocket == INVALID_SOCKET)
{
fprintf(stderr, "Could not create socket.\n");
WSACleanup();
exit(0);
}
/* Clear out server struct */
memset((void *)&m_oServer, '\0', sizeof(struct sockaddr_in));
/* Set family and port */
m_oServer.sin_family = AF_INET;
m_oServer.sin_port = htons(m_iPortnumber);
/* Set server address */
m_oServer.sin_addr.S_un.S_un_b.s_b1 = (unsigned char)a1;
m_oServer.sin_addr.S_un.S_un_b.s_b2 = (unsigned char)a2;
m_oServer.sin_addr.S_un.S_un_b.s_b3 = (unsigned char)a3;
m_oServer.sin_addr.S_un.S_un_b.s_b4 = (unsigned char)a4;
/* Clear out client struct */
memset((void *)&m_oClient, '\0', sizeof(struct sockaddr_in));
/* Set family and port */
m_oClient.sin_family = AF_INET;
m_oClient.sin_addr.s_addr=INADDR_ANY;
m_oClient.sin_port = htons(0);
/* Bind local address to socket */
if (bind(m_oSocket, (struct sockaddr *)&m_oClient, sizeof(struct sockaddr_in)) == -1)
{
fprintf(stderr, "Cannot bind address to socket.\n");
closesocket(m_oSocket);
WSACleanup();
exit(0);
}
There are a variety of ways that sendto can fail. Some, such as arp failure, will cause an error during sendto. Other, such as ICMP port unreachable, may be reported when you next use the socket.
Your recvfrom call could actually be fetching the ICMP packet sent in response to your outgoing packet.
Does a second recvfrom block as expected?
Socket required to be set BLOCKING/NON-BLOCKING.
Set BLOCKING
int nMode = 0; // 0: BLOCKING
if (ioctlsocket (objSocket, FIONBIO, &nMode) == SOCKET_ERROR)
{
closesocket(SendingSocket);
WSACleanup();
return iRet;
}
Set NON-BLOCKING
int nMode = 1; // 1: NON-BLOCKING
if (ioctlsocket (objSocket, FIONBIO, &nMode) == SOCKET_ERROR)
{
closesocket(SendingSocket);
WSACleanup();
return iRet;
}
It looks like you're setting up the server socket and the client socket the same way. The initialization looks good for a server, but for the client, you'll want to bind to port 0.
In fact, for both of them you can do INADDR_ANY (IP 0.0.0.0), which doesn't bind to a specific interface, but instead allows any connection on the correct port.

Socket listen doesn't unbind in C++ under linux

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,