• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 671
  • Last Modified:

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
0
vikas_nm
Asked:
vikas_nm
  • 4
  • 2
1 Solution
 
lomo74Commented:
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
 
vikas_nmAuthor Commented:
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
 
lomo74Commented:
/*
** 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
Cloud Class® Course: Microsoft Office 2010

This course will introduce you to the interfaces and features of Microsoft Office 2010 Word, Excel, PowerPoint, Outlook, and Access. You will learn about the features that are shared between all products in the Office suite, as well as the new features that are product specific.

 
vikas_nmAuthor Commented:
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
 
lomo74Commented:
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
 
lomo74Commented:
...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
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Cloud Class® Course: C++ 11 Fundamentals

This course will introduce you to C++ 11 and teach you about syntax fundamentals.

  • 4
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now