Socket connection problem in C and Linux

I am working on a simple project because I wanted to learn more about socket programming on Linux. I have created a very simple server that will accept connections and respond with one operator. However, I added a while loop to keep the network connected, so I can continue to send commands without disconnecting it. However, as soon as I send the first command, the server will respond with a connection. After the first answer, he just sits around and refuses to answer. As you can tell from the code, I tried the accept system call inside and outside the while loop, because I was not sure if a call being received more than once on the same client would cause it to hang. Once I moved the call to accept outside of the while loop, the function still hangs, so I'm not sure where to go from here.

#include "server.h"
#include <netinet/in.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

struct server {
    int sockfd;
    int client_socket; //the socket used for communication with the client
    int backlog; //maximum pending connections
    struct sockaddr_in *serv_addr;
    struct sockaddr_in *client_addr; //the clients information when it connects
};

int server_init(server **serv, int max_connections)
{
    *serv = (server *)malloc(sizeof(server));
    if (*serv) {
        (*serv)->backlog = max_connections;
        (*serv)->sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

        (*serv)->serv_addr = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
        if ((*serv)->serv_addr)
            memset((*serv)->serv_addr->sin_zero, 0, sizeof((*serv)->serv_addr->sin_zero));
        else {
            free(*serv);
            return -1;
        }

        (*serv)->serv_addr->sin_family = AF_INET;
        (*serv)->serv_addr->sin_addr.s_addr = INADDR_ANY;

    } else {
        return -1;
    }

    return 0;
}

/*
 * Bind the server to a port and start listening
 */
int server_bind(server *serv, int port)
{
    int result = 0;

    serv->serv_addr->sin_port = htons(port);
    if (bind(serv->sockfd, (struct sockaddr *)serv->serv_addr, (socklen_t)sizeof(*(serv->serv_addr))) < 0)
        return -1; //if the bind call fails, I dont want to continue to try the listen call

    if (listen(serv->sockfd, serv->backlog) < 0)
        result = -1;

    return result;  
}

int server_unbind(server *serv)
{
    int result = 0;

    if (close(serv->client_socket) < 0)
        result = -1;

    if (close(serv->sockfd) < 0)
        result = -1;

    return result;
}

int server_accept_connections(server *serv, int (*process_data)(char *buffer, ssize_t length, int client_scoket))
{
    int result = 0;
    char *buffer = (char *) malloc(sizeof(char) * 250);

    if (buffer) {
        int length = sizeof((serv)->client_addr); //may do something with this to keep from calculating it every time
        serv->client_socket = accept(serv->sockfd, (struct sockaddr *)(serv)->client_addr, &length);

        while (result == 0) {
            //int length = sizeof((serv)->client_addr);
            //serv->client_socket = accept(serv->sockfd, (struct sockaddr *)(serv)->client_addr, &length);
            ssize_t data_length = recv(serv->client_socket, buffer, sizeof(buffer), 0);
            result = (* process_data)(buffer, data_length, serv->client_socket);
        }
        result = 0;
    }
    else
        result = -1;

    free(buffer);
    return result;
}

void server_destroy(server *serv)
{
    if (serv) {
        free(serv->serv_addr);
        free(serv);
    }
}

      


#include <stdio.h>
#include "server.h"
#include <string.h>
#include <stdlib.h>

int process_netdata(char *buffer, ssize_t length, int socket_desc)
{   
    printf("%s",buffer);
    if(strcmp(buffer, "quit") != 0) {
        char *str = "I got your message";
        int str_length = strlen(str);
        write(socket_desc, str, str_length);
        return 0;
    }
    else {
        char *str = "quit received";
        int str_length = strlen(str);
        write(socket_desc, str, str_length);
        return -1;
    }
}

int main(int argc, char **argv)
{
    server *server;
    int value = 0;

    value = server_init(&server, 10);
    printf("server_init: %i\n", value);

    value = server_bind(server, 2021);
    printf("server_bind: %i\n", value);

    value = server_accept_connections(server, &process_netdata);
    printf("server_accept: %i\n", value);

    value = server_unbind(server);
    printf("server_unbind: %i\n", value);

    value = server_destroy(server);
    printf("server_destroy: %i\n", value);

    return 0;
}

      

+3


source to share


1 answer


You are missing a fork so that the parent keeps listening (accepting) new connections, and the child works on the established connection.



+2


source







All Articles