Click here to Skip to main content
15,884,388 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi I am newly to socket programing and I want to create possix tcp client and server , which handle keep alive and client to be able to wait for response with timeout. I read about socket options SO_KEEPALIVE and SO_RCVTIMEO and I have try to set the client socket with both of them .Why get Resource temporarily unavailable now? This is my client code :
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>


#define INDEX_ZERO (0)

struct sockaddr_in client;
socklen_t clientsz = sizeof(client);

int client_socket = -1;
int port = 5900;
const char* ip = "127.0.0.1";
bool socket_created = false;
bool already_connect_to_server = false;

bool SocketCreate()
{
    /*
        * Get a stream socket.
        */
    if((client_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("Socket()");
        return false;
    }
    else
    {
        return true;
    }
    
}

void ConnectToServer(void)
{
    struct sockaddr_in server; /* server address              */
    server.sin_family = AF_INET;
    server.sin_port = htons(port);
    server.sin_addr.s_addr = inet_addr(ip);

    // Set timeout to 2.5s

    struct timeval tv;
    tv.tv_sec = 2;
    tv.tv_usec = 500000;
    setsockopt(client_socket, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof(tv)); // if I remove this line the program just stops after first server respond
   

    /*
        * Connect to the server.
        */
    while ((connect(client_socket, (struct sockaddr *)&server, sizeof(server)) < 0))
    {
        perror("Connect()");
        sleep(1);
    }
    
    int enableKeepAlive = 1;
    int count = 3;      // number of emergency requests
    int maxIdle = 1;    // delay (s) between requests, max idle time
    int interval = 1;   // delay (s) between emergency requests. "count" request are send

    //I read that client inherit server SO_KEEPALIVE option
    setsockopt(client_socket, SOL_SOCKET, SO_KEEPALIVE, &enableKeepAlive, sizeof(enableKeepAlive));
    setsockopt(client_socket, IPPROTO_TCP, TCP_KEEPIDLE, &maxIdle, sizeof(maxIdle));
    setsockopt(client_socket, IPPROTO_TCP, TCP_KEEPCNT, &count, sizeof(count));
    setsockopt(client_socket, IPPROTO_TCP, TCP_KEEPINTVL, &interval, sizeof(interval));
    
    getsockname(client_socket, (struct sockaddr *) &client, &clientsz);

printf("[%s:%u] > ", inet_ntoa(client.sin_addr), ntohs(client.sin_port));
                   /* client address                  client port      */

}

uint8_t SendTcpPacket(uint8_t *payload, size_t len)
{
    
    bool sended = false;
    uint8_t ret_val;
    if(! socket_created)
    {
        socket_created = SocketCreate();
        if(! socket_created)
        {
            return 201;
        }
    }
    if(! already_connect_to_server)
    {
        already_connect_to_server = true;
        ConnectToServer();
    }


  
    while (!sended)
    {
        uint8_t one = 1;
        if (client_socket > 0)
        {

            if (send(client_socket, payload, len, 0) < 0)
            {
                perror("Send()");
            }
            else
            {
                printf("Sended %uhh",payload[0]);
            }
            ssize_t recv_ret = recv(client_socket, payload, len, 0);

            if ((recv_ret > 1) || (recv_ret < 0) || (recv_ret == EAGAIN) || (recv_ret == EWOULDBLOCK)) // EAGAIN or EWOULDBLOCK should be applicable only for non-blocking sockets
            {
                printf("Recv() failed with value: , %ld \n", recv_ret);
                perror("Recv():\n");
                //
                // Most prorably, this is the possible TIMEOUT
                // Handle the event accordingly... maybe goto the beginning of the protocol logic
                //
                if (recv_ret < 0)
                {
                    ret_val = 101;
                }
                else
                {
                    ret_val = 255; 
                }
            }

            else
            {
                printf("Received %lu bytes from the server...\n", recv_ret);
                for (int i = 0; i < 1; i++) 
                    printf("<--- buff[%d] = %hhu value\n", i, payload[i]);
            }
            ret_val = payload[INDEX_ZERO];
            sended = true;
        }
    }

    return ret_val;
}  
int main(void)
{   
    uint8_t payload[2] = {0,1};
    size_t len = sizeof(payload);
    int counter =0; 
    while(true)
    {
        counter++;
        if(counter % 2 == 0)
        {
            payload[0] = 1;
        }
        else
        {
            payload[0] = 0;
        }
        if(counter > 60000)
        {
            counter = 0;
        }

        SendTcpPacket(payload, len);
    }
    close(client_socket);
    
    return 0;
}


And this is my server code:
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <iostream>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>


using namespace std;

#define BUFFER_SIZE            ( 2 )  // Buffer Size
#define CMD_RESET_CHAIN     (uint8_t)0x00
#define CMD_INIT_CHAIN      (uint8_t)0x01

#define CMD_DEACTIVATE_ALL  (uint8_t)0x10
#define CMD_ACTIVATE_ALL    (uint8_t)0x11

#define CMD_DEACTIVATE_OUT  (uint8_t)0x20
#define CMD_ACTIVATE_OUT    (uint8_t)0x21

#define CMD_GET_FEEDBACK    (uint8_t)0x30

#define POSITIVE_RESPONSE   (uint8_t)0x00
#define NEGATIVE_RESPONSE   (uint8_t)0x80

/* Server and client sockets*/
int s;                             // socket for accepting connections    
int ns;                            // socket connected to client    


// Set the socketopt after accept like it is in example in stackoverflow
int enableKeepAlive = 1;
int count = 3;      // number of emergency requests
int maxIdle = 1;    // delay (s) between requests, max idle time
int interval = 1;   // delay (s) between emergency requests. "count" request are send
socklen_t sizeof_maxIdle = sizeof(maxIdle);


uint8_t buf[BUFFER_SIZE];          // buffer for sending & receiving data 
struct sockaddr_in client;         // client address information          
struct sockaddr_in server;         // server address information          
socklen_t namelen;                 // length of client name     


bool already_bind = false;

int test_counter = 0;

void socket_cr_bind_listen(int port)
{

    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("Socket()");
        exit(2);
    }

    /*set server socket to be non-blocking socket */

    server.sin_family = AF_INET;
    server.sin_port   = htons(port);
    server.sin_addr.s_addr = INADDR_ANY;

    if (bind(s, (struct sockaddr *)&server, sizeof(server)) < 0)
    {
        perror("Bind()");
        exit(3);
    }
   
    if (listen(s, 1) != 0)
    {
        perror("Listen()");
        exit(4);
    }
     else
    {
        printf("Server listening on port: %d...\n",ntohs(server.sin_port));
    }
}

int RunStandardTcpServer(const char* ip, int port, int res_mock) // make it void later on...
{


    if(! already_bind)
    {
        socket_cr_bind_listen(port);
        already_bind = true;
    }

    namelen = sizeof(client);
    uint8_t payload = 0;
    
    test_counter++;
    while ((ns = accept(s, (struct sockaddr *)&client, &namelen)) > 0)
    {        

        setsockopt(ns, SOL_SOCKET, SO_KEEPALIVE, &enableKeepAlive, sizeof(enableKeepAlive));
        setsockopt(ns, IPPROTO_TCP, TCP_KEEPIDLE, &maxIdle, sizeof(maxIdle));
        setsockopt(ns, IPPROTO_TCP, TCP_KEEPCNT, &count, sizeof(count));
        setsockopt(ns, IPPROTO_TCP, TCP_KEEPINTVL, &interval, sizeof(interval));
            ssize_t bytes_read = recv(ns, buf, sizeof(BUFFER_SIZE), 0);
        
        /*For test purpose to be removed from line 102 to line 110*/
        if(test_counter % 2 == 0)
        {
                //printf("After accept server listening on port: %c...\n",inet_ntop(server.sin_port));
        }
        if(test_counter > 65000)
        {
            test_counter = 0;
        }

        if ( bytes_read == -1)
        {
            perror("Recv()");
            exit(6);
        }
        printf("Read bytes: %ld\n", bytes_read);
        cout<<"Byte of interest"<<(unsigned)buf[0]<<endl;
        cout<<"If expceted second byte is: "<<(unsigned)buf[1]<<endl;

        switch (res_mock)
        {
        case 0:
        {
            payload = POSITIVE_RESPONSE;
            cout<<"Simulating positive response"<<endl;
            break;
        }
        case 1: 
        {
            payload = NEGATIVE_RESPONSE;
            cout<<"Simulating negative response"<<endl;
            break;
        }
        case 2:
            cout<<"Simulating unknown response"<<endl;
            payload = 222;
            break;
        case 3:
        {
            int i = 0;
            cout<<"Simulating late response"<<endl;
            while(i<5)
            {
                sleep(1);
                i++;
            }
        }
        case 4:
        {
            
            cout<<"Simulating no response"<<endl;
            while(true)
            {
                sleep(5);
                
            }
        }
        default:
            break;
        }

        if (send(ns, &payload, 1, 0) < 0)
        {
            perror("Send()");
            exit(7);
        }  
    
        memset(buf,255,sizeof(BUFFER_SIZE));
       
    }

    if (ns == -1)
    {
        perror("Accept()");
        exit(5);
    }
   
    /*For test purpose to be removed from line 102 to line 110*/
   
    printf("After accept server listening at port: %d...\n",ntohs(server.sin_port));
    
   
    
    return 0;
}

int main(int argc, char* argv[])
{
    if(argc <= 3)
    {
        printf("usage:  ip_address + port_number + response mock (0-positive 1-negative 2-unknown response 3-no response )\n");
        return -1;
    }

    const char* ip = argv[1];
    int port = atoi(argv[2]);
    int res_mock = atoi(argv[3]);
    while(true)
    {
        RunStandardTcpServer(ip, port,res_mock);
         /* Check the status for the keepalive option */
        if(getsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &maxIdle, &sizeof_maxIdle) < 0) {
            perror("getsockopt()");
            close(s);
            exit(EXIT_FAILURE);
        }
    }
    close(ns);
    close(s);
}


What I have tried:

-I have tried first to implement the timeout option and it was working , but only when I reconnect every time with new socket and file descriptor respectively.
-I also tried only the keep alive part but there was no keep alive (when I turn off the server, the client says: Connection shutdown by peer).
-I have used wireshark to check the payloads out and in , and there was keepalive payload, but not the effect which I expected, as I mention above.
Thank you for the attention!
Posted
Updated 27-Oct-22 20:46pm

1 solution

On the server side you need to tell it to reuse the socket, otherwise you will have to wait until the TIME_WAIT period is up to connect after the previous connection closes
C
const int one = 1;
setsocopt( SOL_SOCKET, SO_REUSEADDR, &one, (socklen_t)sizeof(one));

That's how you would do it in C. You may have to adjust casts for C++
 
Share this answer
 
v2
Comments
Деян Цонев 27-Oct-22 0:46am    
I just tried what you suggested. I tried setting the socket before bind the socket, after listen and after accept but the result when stop the server is : Connection reset by peer.
Деян Цонев 27-Oct-22 0:55am    
Did you mean that i should bind every time the connection is lost, because in my implementation the server bind the socket only once. Is this the mistake?

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900