Link to home
Start Free TrialLog in
Avatar of vikas_nm
vikas_nmFlag for India

asked on

Server Socket in C on linux should accept data and return it to the client

Hello Experts,

I have attached a C file that contains code to Listen for client connections on the server. I have tested the same and is working fine. The clients are getting connected and receiving a "Hello" message from the server.

What i want is that after the server accepts connection from the client, it should also accept data from the client i.e. a simple string value and then return the same string back to the client with the date appended to it.

Can u please help me in this by modify the source code to include the above requirement.

With Kind Regards.
listner.c
Avatar of lomo74
lomo74
Flag of Italy image

look at the attached code.
cheers - Lorenzo -
/*
** server.c -- a stream socket server demo
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#include <time.h>

#define PORT "3490"  // the port users will be connecting to

#define BACKLOG 10     // how many pending connections queue will hold

#define MAXBUF 256   // max length of received string

void sigchld_handler(int s)
{
    while(waitpid(-1, NULL, WNOHANG) > 0);
}

// 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(void)
{
    int sockfd, new_fd;  // listen on sock_fd, new connection on new_fd
    struct addrinfo hints, *servinfo, *p;
    struct sockaddr_storage their_addr; // connector's address information
    socklen_t sin_size;
    struct sigaction sa;
    int yes=1;
    char s[INET6_ADDRSTRLEN];
    int rv;
    char rc, buf[MAXBUF], *pbuf=&(buf[0]), *pbufend=&(buf[MAXBUF-1]), resp[MAXBUF+16];
    time_t t;
    struct tm *ltime;
    char stime[16];
    
    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE; // use my IP

    if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
        return 1;
    }

    // loop through all the results and bind to the first we can
    for(p = servinfo; p != NULL; p = p->ai_next) {
        if ((sockfd = socket(p->ai_family, p->ai_socktype,
                p->ai_protocol)) == -1) {
            perror("server: socket");
            continue;
        }

        if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
                sizeof(int)) == -1) {
            perror("setsockopt");
            exit(1);
        }

        if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
            close(sockfd);
            perror("server: bind");
            continue;
        }

        break;
    }

    if (p == NULL)  {
        fprintf(stderr, "server: failed to bind\n");
        return 2;
    }

    freeaddrinfo(servinfo); // all done with this structure

    if (listen(sockfd, BACKLOG) == -1) {
        perror("listen");
        exit(1);
    }

    sa.sa_handler = sigchld_handler; // reap all dead processes
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;
    if (sigaction(SIGCHLD, &sa, NULL) == -1) {
        perror("sigaction");
        exit(1);
    }

    printf("server: waiting for connections...\n");

    while(1) {  // main accept() loop
        sin_size = sizeof their_addr;
        new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
        if (new_fd == -1) {
            perror("accept");
            continue;
        }

        inet_ntop(their_addr.ss_family,
            get_in_addr((struct sockaddr *)&their_addr),
            s, sizeof s);
        printf("server: got connection from %s\n", s);

        if (!fork()) { // this is the child process
            close(sockfd); // child doesn't need the listener
	    while (recv(new_fd, &rc, sizeof rc, 0) == 1 && pbuf < pbufend) {
		if (rc == '\n')
		    break; // stop reading on new line
		*pbuf++ = rc;
	    }
	    *pbuf = '\0'; // terminate received string
	    // format current date
	    t = time(NULL);
	    ltime = localtime(&t);
	    strftime(stime, sizeof stime, "%Y-%m-%d", ltime);
	    // format response and send it
	    sprintf(resp, "%s: %s", stime, buf);
            if (send(new_fd, resp, strlen(resp), 0) == -1)
                perror("send");
            close(new_fd);
            exit(0);
        }
        close(new_fd);  // parent doesn't need this
    }

    return 0;
}

Open in new window

Avatar of vikas_nm

ASKER

I will check this code and get back to you on this. One more thing can i define how many or unlimited number of sockets to open concurrently. This is one more requirement for my project.
/*
** server.c -- a stream socket server demo
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#include <time.h>

#define PORT "3490"  // the port users will be connecting to

#define BACKLOG 10     // how many pending connections queue will hold

#define MAXBUF 256   // max length of received string

static int num_conn = 0;
// define MAX_CONN -1 to remove limit
#define MAX_CONN 10

void sigchld_handler(int s)
{
    while(waitpid(-1, NULL, WNOHANG) > 0);
    num_conn--;
}

// 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(void)
{
    int sockfd, new_fd;  // listen on sock_fd, new connection on new_fd
    struct addrinfo hints, *servinfo, *p;
    struct sockaddr_storage their_addr; // connector's address information
    socklen_t sin_size;
    struct sigaction sa;
    int yes=1;
    char s[INET6_ADDRSTRLEN];
    int rv;
    char rc, buf[MAXBUF], *pbuf=&(buf[0]), *pbufend=&(buf[MAXBUF-1]), resp[MAXBUF+16];
    time_t t;
    struct tm *ltime;
    char stime[16];
    
    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE; // use my IP

    if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
        return 1;
    }

    // loop through all the results and bind to the first we can
    for(p = servinfo; p != NULL; p = p->ai_next) {
        if ((sockfd = socket(p->ai_family, p->ai_socktype,
                p->ai_protocol)) == -1) {
            perror("server: socket");
            continue;
        }

        if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
                sizeof(int)) == -1) {
            perror("setsockopt");
            exit(1);
        }

        if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
            close(sockfd);
            perror("server: bind");
            continue;
        }

        break;
    }

    if (p == NULL)  {
        fprintf(stderr, "server: failed to bind\n");
        return 2;
    }

    freeaddrinfo(servinfo); // all done with this structure

    if (listen(sockfd, BACKLOG) == -1) {
        perror("listen");
        exit(1);
    }

    sa.sa_handler = sigchld_handler; // reap all dead processes
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;
    if (sigaction(SIGCHLD, &sa, NULL) == -1) {
        perror("sigaction");
        exit(1);
    }

    printf("server: waiting for connections...\n");

    while(1) {  // main accept() loop
        sin_size = sizeof their_addr;
        new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
        if (new_fd == -1) {
            perror("accept");
            continue;
        }
        
        if (MAX_CONN > 0 && num_conn >= MAX_CONN) {
	    send(new_fd, "too many connections", 20, 0);
	    close(new_fd);
	    continue;
	} else {
	    num_conn++;
	}

        inet_ntop(their_addr.ss_family,
            get_in_addr((struct sockaddr *)&their_addr),
            s, sizeof s);
        printf("server: got connection from %s\n", s);

        if (!fork()) { // this is the child process
            close(sockfd); // child doesn't need the listener
	    while (recv(new_fd, &rc, sizeof rc, 0) == 1 && pbuf < pbufend) {
		if (rc == '\n')
		    break; // stop reading on new line
		*pbuf++ = rc;
	    }
	    *pbuf = '\0'; // terminate received string
	    // format current date
	    t = time(NULL);
	    ltime = localtime(&t);
	    strftime(stime, sizeof stime, "%Y-%m-%d", ltime);
	    // format response and send it
	    sprintf(resp, "%s: %s", stime, buf);
            if (send(new_fd, resp, strlen(resp), 0) == -1)
                perror("send");
            close(new_fd);
            exit(0);
        }
        close(new_fd);  // parent doesn't need this
    }

    return 0;
}

Open in new window

Hi
Sorry for the late reply. I have executed the code on the server and tested it from the client. I am passing a string "Hello" the client is able to connect to the server socket and send the data. But its unable to receive the data from the server. the code hangs. I am testing the client code using C#.
The server was written to return an answer after it has read a new line character. You can obviously change this behaviour, but if you keep the server as is, you must send "Hello\n" before reading the answer back. Maybe post your C# code, let's look at it.
ASKER CERTIFIED SOLUTION
Avatar of lomo74
lomo74
Flag of Italy image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial