LinuxQuestions.org
Download your favorite Linux distribution at LQ ISO.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Blogs > rainbowsally
User Name
Password

Notices


Rate this Entry

Sockets - Bidirectional Communication IPv4/6 (terminal version)

Posted 01-17-2013 at 08:54 PM by rainbowsally

Sockets - Bidirectional Communication IPv4/6 (terminal version)

Today's features:
  • More fun with sockets.
  • Bidirectional communication using IPv4 and IPv6 socket streams (sequential).
  • Interactive. (Only interprets one command, but it's easily expandable.)
  • Terminal version for broader usefulness.

[Note the addresses in this and the previous sockets experiments (here http://www.linuxquestions.org/questi...example-35270/) are at your own computer. Nothing should go out onto the net at all. If you want to change the addresses or port numbers, they are defined at the top of the main() functions as strings.]

To run the server(s) you might just want to do something like:
Code:
xterm -e server_v6 &
(with the ampersand) and in your main terminal
Code:
client_v6
. Same with the v4 set of files.

And hey! What do you think will happen if you run a v4 socket setup with a v6 one? Find out! :-)

Now let's just get to the nitty.

file: client_v4.c
purpose: source code
Code:
/* client_v6.c
 * Based on files found at
 *  www.cs.utah.edu/~swalton/listings/sockets/programs/index.html
 * 
 * Copyright (c) 2001 Sean Walton and Macmillan Publishers.  Use may be in
 * whole or in part in accordance to the General Public License (GPL).
 *
 * Modified by Rainbow Sally Copyright (c) 2013 Rainbow Sally GPL 3+
*/

//Demonstrate IPv4 client read/write functions

#include <stdio.h>
#include <errno.h>
#include <resolv.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <stdarg.h>

#include <ctype.h>      // isdigit()
#include <stdlib.h>     // abort(), exit(), atoi()
#include <string.h>     // strcmp(), memset()
#include <unistd.h>     // close()
#define bzero(mem, len) memset(mem, 0, len)


void panic(char* msg, ...)
{   va_list ap;

    va_start(ap, msg);
    vprintf(msg, ap);
    va_end(ap);
    abort();
}

// MSG_OOB 
// MSG_PEEK 
// MSG_DONTROUTE
#define MSG_FLAGS 0 /* default */
    
int main(int argc, char **argv)
{ 
  const char* addr_str = "127.0.0.1";
  const char* port_str = "9999";
  
  printf(
         "Using address '%s', port %s\n"
         "Type text to send to server, 'bye' to end\n"
         , addr_str, port_str
        );
  
  int sd, portnum;
  struct sockaddr_in addr;
  char line[100];
  if(!sscanf(port_str, "%d", &portnum))
    panic("portnum");
  bzero(&addr, sizeof(addr));
  if ( (sd = socket(PF_INET, SOCK_STREAM, 0)) < 0 )
    panic("socket");
  addr.sin_family = AF_INET;
  addr.sin_port = htons(portnum);
    if ( inet_pton(AF_INET, addr_str, &addr.sin_addr) == 0 )
    panic("inet_aton");
  if ( connect(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
    panic("connect");
  do
  {
    fgets(line, sizeof(line), stdin);
    send(sd, line, strlen(line)+1, MSG_FLAGS);
    recv(sd, line, sizeof(line), 0);
    printf("client recieved echo: %s", line);
  }while ( strcmp(line, "bye\n") != 0 );
  
  close(sd);
  return 0;
}

file: client_v6.c
purpose: source code
Code:
/* client_v6.c
 * Based on files found at
 *  www.cs.utah.edu/~swalton/listings/sockets/programs/index.html
 * 
 * Copyright (c) 2001 Sean Walton and Macmillan Publishers.  Use may be in
 * whole or in part in accordance to the General Public License (GPL).
 *
 * Modified by Rainbow Sally Copyright (c) 2013 Rainbow Sally GPL 3+
*/

// Demonstrate IPv6 client connection

#include <stdio.h>
#include <errno.h>
#include <resolv.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <stdarg.h>

#include <ctype.h>      // isdigit()
#include <stdlib.h>     // abort(), exit(), atoi()
#include <string.h>     // strcmp(), memset()
#include <unistd.h>     // close()
#define bzero(mem, len) memset(mem, 0, len)


void panic(char* msg, ...)
{   va_list ap;

    va_start(ap, msg);
    vprintf(msg, ap);
    va_end(ap);
    abort();
}

// MSG_OOB 
// MSG_PEEK 
// MSG_DONTROUTE
#define MSG_FLAGS 0 /* default */

int main(int count, char *strings[])
{ 
  const char* addr_str = "0::0";
  const char* port_str = "9999";

  printf(
         "Using address '%s', port %s\n"
      "Type text to send to server, 'bye' to end\n"
      , addr_str, port_str
        );
  
  int sd, portnum;
  struct sockaddr_in6 addr;
  char line[100];
  if(!sscanf(port_str, "%d", &portnum))
    panic("portnum");
  bzero(&addr, sizeof(addr));
  if ( (sd = socket(PF_INET6, SOCK_STREAM, 0)) < 0 )
    panic("socket");
  addr.sin6_family = AF_INET6;
  addr.sin6_port = htons(portnum);
    if ( inet_pton(AF_INET6, addr_str, &addr.sin6_addr) == 0 )
    panic("inet_aton");
  if ( connect(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
    panic("connect6");
  do
  {
    fgets(line, sizeof(line), stdin);
    send(sd, line, strlen(line)+1, MSG_FLAGS);
    recv(sd, line, sizeof(line), 0);
    printf("client recieved echo: %s", line);
  }while ( strcmp(line, "bye\n") != 0 );
  
  close(sd);
  return 0;
}

file: server_v4.c
purpose: source code
Code:
/* server_v6.c
 * Based on files found at
 *  www.cs.utah.edu/~swalton/listings/sockets/programs/index.html
 *
 * Copyright (c) 2001 Sean Walton and Macmillan Publishers.  Use may be in
 * whole or in part in accordance to the General Public License (GPL).
 *
 * Modified by Rainbow Sally Copyright (c) 2013 Rainbow Sally GPL 3+
*/

//Demonstrate IPv4 server read/write functions

#include <stdio.h>
#include <errno.h>
#include <resolv.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <stdarg.h>

#include <ctype.h>      // isdigit()
#include <stdlib.h>     // abort(), exit(), atoi()
#include <string.h>     // strcmp(), memset()
#include <arpa/inet.h>  // inet_addr, etc.
#include <unistd.h>     // close()
#define bzero(mem, len) memset(mem, 0, len)

void panic(char* msg, ...)
{ va_list ap;

  va_start(ap, msg);
  vprintf(msg, ap);
  va_end(ap);
  abort();
}

int main(int count, char *strings[])
{ 
  const char* port_str = "9999";
  const char* addr_str = "127.0.0.1"; // localhost
  printf(
      "Using address '%s', port %s\n"
      "Waits for connection then echos string typed in client to\n"
      "stdout.\n"
      "Press Ctrl-C to exit\n", addr_str, port_str
        );
  int sd, portnum;
  int max_conns = 15; // max number of simultaneous connections
  struct sockaddr_in addr;
  bzero(&addr, sizeof(addr));

  if(!sscanf(port_str, "%d", &portnum))
    panic("portnum");
  if ( (sd = socket(PF_INET, SOCK_STREAM, 0)) < 0 )
    panic("socket");
  addr.sin_family = AF_INET;
  addr.sin_port = htons(portnum);
  if ( inet_pton(AF_INET, addr_str, &addr.sin_addr) == 0 )
    panic("inet_pton");
  if ( bind(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
    panic("bind");
  if ( listen(sd, max_conns) != 0 )
    panic("listen");
  while (1)
  { 
    int sent;
   size_t size=sizeof(addr);
    int client;
    char line[100];

    client = accept(sd, (struct sockaddr*)&addr, &size);
    fprintf(stderr, "Connected: %s port=%d\n",
        inet_ntop(AF_INET, &addr.sin_addr, line, sizeof(line)),
        addr.sin_port);
    
    for(;;)
    {
      // receive and echo back
      sent = send(client, line, recv(client, line, sizeof(line), 0), 0);
      
      if(sent == 0) // client disconnected
        break;

      fprintf(stderr, "server echoing: %s", line);

      if(strcmp(line, "bye\n") == 0)
         break;
    }
    close(client);
  }
}

file: server_v6.c
purpose: source code
Code:
/* server_v6.c
 * Based on files found at
 *  www.cs.utah.edu/~swalton/listings/sockets/programs/index.html
 * 
 * Copyright (c) 2001 Sean Walton and Macmillan Publishers.  Use may be in
 * whole or in part in accordance to the General Public License (GPL).
 *
 * Modified by Rainbow Sally Copyright (c) 2013 Rainbow Sally GPL 3+
*/

//Demonstrate IPv6 server read/write functions

#include <stdio.h>
#include <errno.h>
#include <resolv.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <stdarg.h>

#include <ctype.h>      // isdigit()
#include <stdlib.h>     // abort(), exit(), atoi()
#include <string.h>     // strcmp(), memset()
#include <arpa/inet.h>  // inet_addr, etc.
#include <unistd.h>     // close()
#define bzero(mem, len) memset(mem, 0, len)

void panic(char* msg, ...)
{ va_list ap;

  va_start(ap, msg);
  vprintf(msg, ap);
  va_end(ap);
  abort();
}

int main(int argc, char **argv)
{ 
  const char* port_str = "9999";
  const char* addr_str = "0::0";
  printf(
         "Using address '%s', port %s\n"
      "Waits for connection then echos string typed in client to\n"
      "stdout.\n"
      "Press Ctrl-C to exit\n", addr_str, port_str
        );
  int sd, portnum;
  struct sockaddr_in6 addr;
  bzero(&addr, sizeof(addr));
  
  if(!sscanf(port_str, "%d", &portnum))
    panic("portnum");
  if ( (sd = socket(PF_INET6, SOCK_STREAM, 0)) < 0 )
    panic("socket");
  addr.sin6_family = AF_INET6;
  addr.sin6_port = htons(portnum);
  if ( inet_pton(AF_INET6, "0::0", &addr.sin6_addr) == 0 )
    panic("inet_pton");
  if ( bind(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
    panic("bind6");
  if ( listen(sd, 15) != 0 )
    panic("listen6");
  while (1)
  { 
    int sent;
   size_t size=sizeof(addr);
    int client;
    char line[100];

    client = accept(sd, (struct sockaddr*)&addr, &size);
    fprintf(stderr, "Connected: %s port=%d\n",
        inet_ntop(AF_INET6, &addr.sin6_addr, line, sizeof(line)),
        addr.sin6_port);
    for(;;)
    { 
      // receive and echo back
      sent = send(client, line, recv(client, line, sizeof(line), 0), 0);
      
      if(sent == 0) // client disconnected
        break;

      fprintf(stderr, "server echoing: %s", line);
      
      if(strcmp(line, "bye\n") == 0)
        break;
    }
    close(client);
  }
}

For the Makefile you're on your own unless you have mc2. It shouldn't be too hard to roll your own, but here's the mc2.def for this setup.

Run 'mc2 -init' to create the initial Makefile. After this 'make update' will add and remove sources as names change or files are added or removed.

This mc2.def is a type MULTI build. (See 'mc2 -help all')

file: mc2.def
purpose: Makefile generation
Code:
# mc2.def template created with Makefile Creator 'mc2'

# sandbox path and other new variables
PREFIX = $(HOME)/usr32
BUILDDIR := $(PWD)

OUTNAME = MULTI

SRCDIR = .
OBJDIR = o
BINDIR = .

# compile function overrides
COMPILE = gcc -m32 -c -o # COMPILE <output_file> (for C, 32 bit, object)
 CFLAGS = -Wall -g3 # debug
# CFLAGS = -Wall -O2 # optimized
INCLUDE = -I $(SRCDIR) -I$(PREFIX)/include -I /usr/include 

# link function overrides
LINK = gcc -m32 -o
LDFLAGS = 
LIB = -L$(PREFIX)/lib -L/usr/lib 
 
semiclean:
  @rm -f $(OBJ)
  @rm -f *~ */*~ */*/*~ */*/*/*~

strip:
  @strip $(MAIN)
  @make semiclean

# additional targets
#mc2-update:
#  @mc2 -update

clean:
  @rm -f $(MAIN)
  @rm -f $(OBJ)
  @rm -f *.kdevelop.pcs *.kdevses
  @rm -f *~ */*~ */*/*~ */*/*/*~ 

force: # used to force execution
These last two blogs entries use blocking (stopping cpu) until there is input. That's mostly convenient in a terminal app. For a gui, where you need to avoid hanging the gui, you either need a separate thread, a mutex, and all kinds of complication like that, or to run in non-blocking mode.

The Computer Mad Science Team

:-)
Posted in Uncategorized
Views 1008 Comments 0
« Prev     Main     Next »
Total Comments 0

Comments

 

  



All times are GMT -5. The time now is 03:26 AM.

Main Menu
Advertisement
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration