?
Solved

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

Posted on 2012-08-27
6
Medium Priority
?
669 Views
Last Modified: 2012-09-30
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
0
Comment
Question by:vikas_nm
  • 4
  • 2
6 Comments
 
LVL 8

Expert Comment

by:lomo74
ID: 38339966
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

0
 

Author Comment

by:vikas_nm
ID: 38344246
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.
0
 
LVL 8

Expert Comment

by:lomo74
ID: 38344393
/*
** 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

0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:vikas_nm
ID: 38351575
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#.
0
 
LVL 8

Expert Comment

by:lomo74
ID: 38351742
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.
0
 
LVL 8

Accepted Solution

by:
lomo74 earned 2000 total points
ID: 38353417
...here you are...
using System;
using System.Linq;
using System.Text;
using System.Net.Sockets;

namespace client
{
    class Program
    {
        static int Main(string[] args)
        {
            if (args.Length < 1)
            {
                Console.Error.WriteLine("specify the server address");
                return 1;
            }

            try
            {
                TcpClient client = new TcpClient(args[0], 3490);

                ASCIIEncoding ascii = new ASCIIEncoding();
                byte[] data = ascii.GetBytes("Hello\n");

                Console.Out.WriteLine("Sending \"Hello\\n\"...");

                client.GetStream().Write(data, 0, data.Length);

                Console.Out.WriteLine("Reading response...");

                byte[] buffer = new byte[256];
                int nread;
                while ((nread = client.GetStream().Read(buffer, 0, buffer.Length)) > 0)
                {
                    byte[] toprint = (nread == buffer.Length)
                        ? buffer
                        : buffer.Take(nread).ToArray();

                    Console.Out.Write(ascii.GetString(toprint));
                }

                Console.Out.WriteLine();

                return 0;
            }
            catch (Exception e)
            {
                Console.Error.WriteLine(e.Message);
                Console.Error.WriteLine(e.StackTrace);
                return 1;
            }
        }
    }
}

Open in new window

0

Featured Post

Fill in the form and get your FREE NFR key NOW!

Veeam is happy to provide a FREE NFR server license to certified engineers, trainers, and bloggers.  It allows for the non‑production use of Veeam Agent for Microsoft Windows. This license is valid for five workstations and two servers.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Join Greg Farro and Ethan Banks from Packet Pushers (http://packetpushers.net/podcast/podcasts/pq-show-93-smart-network-monitoring-paessler-sponsored/) and Greg Ross from Paessler (https://www.paessler.com/prtg) for a discussion about smart network …
I have written articles previously comparing SARDU and YUMI.  I also included a couple of lines about Easy2boot (easy2boot.com).  I have now been using, and enjoying easy2boot as my sole multiboot utility for some years and realize that it deserves …
Video by: Grant
The goal of this video is to provide viewers with basic examples to understand and use nested-loops in the C programming language.
Video by: Grant
The goal of this video is to provide viewers with basic examples to understand and use while-loops in the C programming language.
Suggested Courses
Course of the Month14 days, 15 hours left to enroll

840 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question