|
This following are assumed throughout this guide:
- GNU Bourne-Again Shell 2.04
GCC may depend on the following packages:
- glibc-devel <-(Kernel-Headers)
Download the Demo sample,
extract it and test it.
The purpose of this sample is to demonstrate how a server process
connects and communicates with client processes through a TCP/IP socket.
---------------- ------------------ ------------------
| | start | | fork | |
| Shell Script |==================| Server Process |====================>| Server Process |
| | stop | | | | |
---------------- | ------------------ ------------------
| /\ /\
| || IPC (TCP/IP socket communication) ||
| \/ \/
| ------------------ ------------------
| | | | |
|=====>| Client Process | | Client Process |
| | | |
------------------ ------------------
#define SERVER_IP_ADDRESS 2130706433
// 127.0.0.1 to bits upto 255 each field.
#define SERVER_TCP_PORT 12345
#define SERVER_STRING "Hello World"
#define SERVER_BUFFER_SIZE 256
#define SERVER_SLEEP_INTERVAL 1
void serve_connection
(
int socket_value
);
#include <stdlib.h> // EXIT_SUCCESS
#include <netinet/in.h> // sockaddr_in, htons, htonl
// AF_INET, PF_INET, SOCK_STREAM
#include <sys/types.h> // pid_t
#include <sys/socket.h> // sockaddr
#include "server.h" // SERVER_IP_ADDRESS
int main
(
)
{
struct sockaddr_in server_address;
int server_socket;
struct sockaddr_in client_address;
int client_address_size;
int current_socket;
pid_t process_id;
/*
// Initialise server address structure.
*/
bzero((char *) &(server_address), sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_port = htons(SERVER_TCP_PORT);
server_address.sin_addr.s_addr = htonl(SERVER_IP_ADDRESS);
/*
// Create server socket.
*/
if ((server_socket = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
perror("socket");
exit(EXIT_FAILURE);
}
/*
// Bind server address with server socket together.
*/
if (bind
(
server_socket,
(struct sockaddr *) (&(server_address)),
sizeof(server_address)
) < 0)
{
perror("bind");
exit(EXIT_FAILURE);
}
/*
// Listen for socket connection
*/
listen(server_socket, 5);
/*
// Loop to serve requests from clients
*/
for (;;)
{
/*
// Waits to accept a client request for socket connection.
*/
client_address_size = sizeof(client_address);
current_socket =
accept
(
server_socket,
(struct sockaddr *) &(client_address),
&(client_address_size)
);
if (current_socket < 0)
{
perror("accept");
exit(EXIT_FAILURE);
}
/*
// Fork process into 2 processes.
// - Parent server process will continue to
// listen for other client connection requests.
// - Child server process will serve the currently connected client.
*/
if ((process_id = fork()) < 0)
{
perror("fork");
exit(EXIT_FAILURE);
}
/*
// Parent server process:
// - Close current connection.
// - Continue listening for more client connections
*/
if (process_id > 0)
{
close(current_socket);
continue;
}
/*
// Child server process:
// - Close server socket.
// - Serve current connection.
*/
close(server_socket);
serve_connection(current_socket);
}
return EXIT_SUCCESS;
}
void serve_connection
(
int socket_value
)
{
for (;;)
{
write
(
socket_value,
SERVER_STRING,
(int) strlen(SERVER_STRING)
);
}
return;
}
#include <stdlib.h> // EXIT_SUCCESS
#include <stdio.h> // stdout
#include <netinet/in.h> // sockaddr_in, htons, htonl
// AF_INET, PF_INET, SOCK_STREAM
#include "server.h" // SERVER_IP_ADDRESS
int main
(
)
{
struct sockaddr_in server_address;
int server_socket;
char buffer[SERVER_BUFFER_SIZE];
/*
// Initialise server address structure.
*/
bzero((char *) &(server_address), sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_port = htons(SERVER_TCP_PORT);
server_address.sin_addr.s_addr = htonl(SERVER_IP_ADDRESS);
/*
// Create socket.
*/
server_socket = socket(PF_INET, SOCK_STREAM, 0);
/*
// Connect to server socket.
*/
if (connect
(
server_socket,
(struct sockaddr *) &(server_address),
sizeof(server_address)
) < 0)
{
perror("connect");
exit(EXIT_FAILURE);
}
for (;;)
{
read(server_socket, buffer, SERVER_BUFFER_SIZE);
fprintf(stdout, "%s", buffer);
}
return EXIT_SUCCESS;
}
#
# Usage: /usr/bin/make build
#
CC = /usr/bin/gcc
#
# Server
#
server: server.o
$(CC) server.o -o server
#
# CLIENT
#
client: client.o
$(CC) client.o -o client
clean:
/bin/rm -rf *.o server client
build:
/usr/bin/make clean
/usr/bin/make client
/usr/bin/make server
processfind()
{
if [ ${#} -ne 1 ]
then
return 0;
fi
/bin/ps -auwx | /usr/bin/awk '{print $11}' | /bin/grep -q ${1};
GREPFLAG=${?};
return ${GREPFLAG};
}
#
# Usage: ./system.sh start
# ./system.sh stop
#
#
# Check action by the number of arguments
#
if [ ${#} -ne 1 ]
then
/bin/echo "Usage:";
/bin/echo "${0} start";
/bin/echo "${0} stop";
exit ${?};
fi
#
# Get action from the first argument
#
ACTION=${1};
#
# Check for function library
#
if [ ! -f ./library.sh ]
then
/bin/echo "${0} cannot find a required file.";
exit ${?};
fi
#
# Calls the library of functions
#
source ./library.sh
#
# Check if processes already exist
#
RUNNING=0;
if processfind "./server"
then
RUNNING=1;
fi;
if processfind "./client"
then
RUNNING=1;
fi;
#
# Follow the action
#
case "${ACTION}" in
#
# START
#
start)
#
# If it's already running, no need to start.
#
if [ ${RUNNING} -ne 0 ]
then
/bin/echo "The system has already been started."
exit 1;
fi;
#
# Start system processes
#
./server &
./client &
exit ${?};
;;
#
# STOP
#
stop)
#
# If it's not running, no need to stop.
#
if [ ${RUNNING} -eq 0 ]
then
/bin/echo "The system is not running."
exit 1;
fi;
#
# Stop system processes
#
/usr/bin/killall server;
/usr/bin/killall client;
exit ${?};
;;
#
# OTHERS
#
*)
/bin/echo "Usage: ${0} {start|stop}"
exit ${?};
esac;
# (Ctrl-Alt F1) to switch to text virtual console number 1.
/bin/chmod 700 ./system.sh
./system.sh start
# (Ctrl-Alt F2) to switch to another text virtual console number 2.
./client &
# (Ctrl-Alt F3) to switch to another text virtual console number 3.
/bin/ps -ef # There should be a few client and server processes running.
/bin/netstat -an # There should be a few TCP/IP socket active.
./system.sh stop
# (Ctrl-Alt F1) to switch back to the original text virtual console number 1.
|