MC7404 NETWORK PROGRAMMING UNIT – I Overview of UNIX OS - Environment of a UNIX process - Process control – Process relationships , Signals – Interprocess Communication- overview of TCP/IP protocols UNIX is a computer operating system. OPERATING SYSTEM An operating system is the program that controls all the other parts of a computer system, both the hardware and the software. It allocates the computer's resources and schedules tasks. It helps to use the facilities provided by the system Every computer requires an operating system. How UNIX was developed Back to 60’s There were NO personal computers There were different mainframe computers, each with its own operating system Computers were NOT networked; data transfer was via magnetic tape. Often computers from the same manufacturer could not talk to each other It was difficult to get one program created on one system to work on another system, and it was even difficult to transfer data output by one system into another system. There was no C programming language, or for that matter no standardized programming language at all Programming was frequently done by submitting a program via punch cards and the computer delivered a printed answer More and more ―dumb terminals‖ were hooked up to a mainframe (text-based only) which required a multi-user, multi-tasking operating system – many were not. History of UNIX Bell Laboratories (formerly Bell Telephone Labs, then AT&T Bell Labs, now part of Lucent Technologies) at Murray Hill, NJ, and Holmdel, NJ. This is where ―Unix‖ was originally developed. It was started as UNICS (UNiplexedInformation and Computing Service) Name later changed to UNIX UC Berkeley is where BSD (Berkeley Systems Distribution) Unix started. Berkeley UNIX added substantial number of utility programs Editor –vi Shell – csh Ken Thompson and Dennis Ritchie are considered the founders of the Unix operating system. Ritchie was also instrumental in developi ng and standardizing the C programming language. Prepared by : Mrs. M.Nirmala / AP / MCA Page : 1 MC7404 NETWORK PROGRAMMING UNIT – I Richard Stallman, who was working for MIT, is the founder of the GNU Project to develop a complete Unix-like, free operating system (GNU is Not Unix). He started with GNU Emacs and, with many others, develop ed everything but a kernel. Linus Torvalds is a programmer who develops a product that mimics the form and function of a Unix system but is not derived from licensed source code. Note that ―Linux‖ is not a registered Unix system. Designed as an interactive OS Handles multiple processes and multiple users at the same time Hardware independence It is Simple, elegant, consistent UNIX Components Architecture Diagram of UNIX Kernel: The kernel is the heart of the UNIX operating system. It interacts with hardware It is responsible for scheduling running of user and other processes. It is responsible for allocating memory. It is responsible for managing the swapping between memory and disk. It is responsible for moving data to and from the peripherals. It receives service requests from the processes and honours them. Shell Whenever you login to a Unix system you are placed in a shell program. The shell's prompt is usually visible at the cursor's position on your screen. To get your work done, you enter commands at this prompt. The shell is a command interpreter; it takes each command and passes it to the operating system kernel to be acted upon. It then displays the results of this operation on your screen. Prepared by : Mrs. M.Nirmala / AP / MCA Page : 2 MC7404 NETWORK PROGRAMMING UNIT – I Several shells are usually available on any UNI X system, each with its own strengths and weaknesses. Different users may use different shells. Initially, your system adminstrator will supply a default shell, which can be overridden or changed. The most commonly available shells are: o Bourne shell (sh) o C shell (csh) o Korn shell (ksh) o TC Shell (tcsh) o Bourne Again Shell (bash) Each shell also includes its own programming language. Command files, called "shell scripts" are used to accomplish a series of tasks. Utilities UNIX provides several hundred utility programs, often referred to as commands. Example of Commands are cp,mv,sort,rm,rmdir Divided into six categories File and directory manipulation commands Example: cp a b | ls*.* Filters Example: grep(extracts lines containing patterns), cut, paste, Program development tools such as editors/compilers Example: cc (C compiler), make (maintain large programs whose source code consists of multiple files) Text processing Example: vi System administration Example: mount (mount file system) Miscellaneous Example: kill 1325 (kill a process), chmod(change privileges of a file) Modular: single functions can be grouped to perform more complex tasks Files and Directories: All data in UNIX is organized into files. All files are organized into directories. These directories are organized into a tree-like structure called the filesystem (ii) FILES AND DIRECTORIES File System: The UNIX file system is a hierarchical arrangement of directories and files. Everything starts in the directory called root whose name is the single character. Directory: A directory is a file that contains directory entries. Each directory entry contains a file name along with a structure of information describing the attributes of the file. The some of the attributes of a file are, Type of file – regular file Prepared by : Mrs. M.Nirmala / AP / MCA Page : 3 MC7404 NETWORK PROGRAMMING UNIT – I Directory - the size of the file The owner of the file Permissions for the file. Filename: The names in a directory are called filenames. The only two characters that cannot appear in a filename are the slash character (/) and the null character. Two filenames are automatically created whenever a new directory is created: (i) . [called dot] – Current Directory (ii) ..[called dot-dot] – Parent Directory Pathname: A sequence of one or more filenames separated by slashes and optionally starting with a slash, forms a pathname. A pathname that begins with a slash is called an absolute pathname. Relative pathnames refer to files relative to the current directory Working Directory: Every process has a working directory, also called the current working directory from which all relative paths are interpreted. A process can change its working directory with the chdir function. Home Directory: When the user logs in, the working directory is set to the user‗s home directory. This user‗s home directory is obtained from the user‗s entry in the password file. (iii) INPUT AND OUTPUT File Descriptors: File descriptors are normally small non-negative integers that the kernel uses to identify the files being accessed by a particular process. Whenever the user opens an existing file or creates a new file, the kernel returns a file descriptor that the user uses to read the file or write into the file. All shells open three descriptors namely, (i) Standard input (ii) Standard output (iii) Standard error. The ls‗ command provide away to redirect any or all of these three descriptors to any file. Unbuffered I/O: Unbuffered I/O is provided by the functions open, read, write, lseek and close. These functions all work with file descriptors. Standard I/O: The standard I/O functions provide a buffered interface to the unbuffered I/O functions. The fgets() reads an entire line whereas the read() reads a specified number of bytes. File I/O operations Most Unix file I/O can be performed with six functions: open close read write Prepared by : Mrs. M.Nirmala / AP / MCA Page : 4 MC7404 NETWORK PROGRAMMING UNIT – I lseek dup, dup2 These functions are part of the POSIX standard for UNIX programming, not part of ANSI C A process may have several open files which it may be reading from and writing to. It also has a current position within the file, which is the next byte to be read or written. Each process has its own array to keep track of The file opened. The files status (whether open for reading or writing: the file status flags ) The current offset within the file When a file is opened or created by a process the kernel assigns a position in the array called the file descriptor. Each entry of this array actually contains a pointer to a file table which stores each of the three pieces of information: file, file status flags, and offset. The file table does not itself contain the file, but instead has a pointer to another table (called the vnode table), which has vital information about the file, including its location in memory. The vnode table is unique for each file. file descriptor file table vnode table It turns out to be very flexible: Different processes can have file descriptors for the same file. A single process can have several file descriptors for the same file through different file tables. A single process can have different file descriptors for the same file table. Different process can have different file descriptors for the same file table. (The processes must be related as parent to child, or grandchild. This involves forking.) PROGRAMS AND PROCESSES: Program: A program is an executable file residing on disk in a directory. A program is read into memory and is executed by the kernel. Process: An executing instance of a program. Some operating systems use the term task to refer to a program that is being executed. Every process has a unique numeric identifier called the process ID. The process ID is always a non-negative integer. Process Control: The UNIX system provides three primary functions for process control. This includes, (i) the creation of new processes – fork() (ii) Program execution – exec() (iii) Process termination – waitpid() Prepared by : Mrs. M.Nirmala / AP / MCA Page : 5 MC7404 NETWORK PROGRAMMING UNIT – I (v) USER IDENTIFICATION: User ID The user ID entry in the password file is a numeric value that identifies the user to the system. This user ID is assigned by the system administrator when the login name is assigned, and the user cannot change it. The userID is normally assigned to be unique for every user. Eg: userID 0 is referred as root or the supervisor. Group ID The entry in the password file also specifies the numeric group ID which is assigned by the system administrator when the login name is assigned. The password file contains multiple entries that specify the same group ID. The group file that maps group names into numeric group ID‗s is /etc/group. (vi) SIGNALS: Signals are a technique used to notify a process that some condition has occurred. (vii) TIME VALUES: UNIX systems have maintained two different time values: Calendar time. This value counts the number of seconds since January 1, 1970, Coordinated Universal Time(UTC). These time values are used to record the time when a file was last modified. The primitive system data type time-t holds these time values. Process time: It measures the central processor resources used by a process. Process time is measured in clock ticks. Process time is also called CPU time. When we measure the execution time of a process, unix system maintains the following three values for a process. They are, Clock time. User CPU time. System CPU time. Clock time: The clock time is the amount of time the process takes to run, and its value depends on the number of other processes being run on the system. User CPU time: The user CPU time is the CPU time attributed to user instructions. System CPU time: The System CPU time is the CPU time attributed to the kernel when it executes on behalf of the process. The sum of user CPU time and system CPU time is often called the CPU time. The time(1) command is used to measure the clock time, user time and system time of any process. ENVIRONMENT OF A UNIX PROCESS Prepared by : Mrs. M.Nirmala / AP / MCA Page : 6 MC7404 NETWORK PROGRAMMING UNIT – I The only active entities in a UNIX system are the processes. UNIX processes are very similar to the classical sequent ial processes or task Each process runs a single program and initially has a single thread of control UNIX is a multiprogramming system, so multiple, independent processes may be running at the same time. Each user may have several active processes at once, so on a large system, there may be hundreds or even thousands of processes running. When a program is being executed on the UNIX system, the system creates a special environment for that program Whenever you issue a command in UNIX, it creates, or starts, a new process A process, in simple terms, is an instance of a running program. The operating system tracks processes through a five digit ID number known as the pid or process ID . Each process in the system has a unique pid. Daemons On Single -user workstations, even when the user is absent, dozens of background processes, called daemons, are running. These are started automatically when the system is booted. (‗‗Daemon‘‘ is a variant spelling of ‗‗demon,‘‘ which is a self-employed evil spirit.) Example of a Daemon A typical daemon is the cron daemon. It wakes up once a minute to check if there is any work for it to do. If so, it does the work. Then it goes back to sleep until it is time for the next check Applications of Daemon Daemon are set to check regular back up updates Handle incoming and outgoing mail Processes are created in UNIX in an especially simple manner. The fork system call creates an exact copy of the original process. The forking process is called the parent process. The new process is called the child process. The parent and child each have their own, private memory images. If the parent subsequently changes any of its variables, the changes are not visible to the child, and vice versa. Process Environment main Function A C program starts executions with a function main(). The prototype for the main function without command line arguments is int main() Prepared by : Mrs. M.Nirmala / AP / MCA Page : 7 MC7404 NETWORK PROGRAMMING UNIT – I #include <stdio.h> int main() { int i,fac1=1,n; printf(" Enter the value of N : "); scanf("%d",&n); for(i=1;i<=n;i++) fac1 = fac1 * i; printf("factorial is %d",fac1); } //output sh-4.2# vi fact1.c sh-4.2# cc fact1.c sh-4.2# ./a.out Enter the value of N : 4 factorial is 24sh-4.2# a.out remains the default output file name for executables created by certain compilers and linkers. ―a‖ refers to assembler output The prototype of the main function with command line arguments #include <stdio.h> main(int argc, char *argv[]) { int i,fac1=1; int n = atoi(argv[2]); for(i=1;i<=n;i++) fac1 = fac1 * i; printf("factorial is %d",fac1); } sh-4.2# cc fact.c sh-4.2# ./a.out fact 5 factorial is 120sh-4.2# where argc is the number of command-line arguments and argv is an array of pointers to the arguments. When a C program is executed by the kernel — by one of the exec functions — a special start-up routine is called before the main function is called. The executable program file specifies this routine as the starting address for the program; this is set up by the link editor when it is invoked by the C compiler. This start-up routine takes values from the kernel — the command line arguments and the environment — and sets things up so that the main function is called. Prepared by : Mrs. M.Nirmala / AP / MCA Page : 8 MC7404 NETWORK PROGRAMMING UNIT – I C Program Life Cycle: Invocation through Termination 1. When a C program is executed by the kernel by one of the exec function 2. A start up routine is called before the main() function 3. The startup routine takes arguments from the command li ne arguments Process termination: To terminate a process. There are eight ways for a process to terminate. These eight ways are divided under two categories. They are (a) Normal termination. (b) Abnormal termination. Normal termination occurs in five ways. They are, 1. Return from main 2. Calling exit 3. Calling_exit or _Exit Prepared by : Mrs. M.Nirmala / AP / MCA Page : 9 MC7404 NETWORK PROGRAMMING UNIT – I 4. Return of the last thread from its start routine 5. Calling pthread_exit from the last thread Abnormal termination occurs in three ways. They are, 6. Calling abort 7. Receipt of signal 8. Response of the last thread to a cancellation request Return from main: If the start-up routine were coded in ‗C‗ the call to main could look like, exit(main(argc, argv)); Returning an integer value from the main function is equivalent to calling exit with same value. Thus, exit(0); is the same as return(0); from the main function. Exit Functions: The following three functions (a) _exit (b) _Exit and (c) exit terminate a program normally. The _exit() and _Exit(), returns to the kernel immediately but exit(), performs certain cleanup processing and then returns to the kernel. The prototype is as follows, #include<stdlib.h> void exit(int status); void _Exit(int status); #include<unistd.h> void _exit(int status); The Death of a Process exit() and _exit() and _Exit() There are three ways to forcefully exit a program: 1. _exit() : System calls that request the O.S. to terminate a process immediately without any additional code execution. Prepared by : Mrs. M.Nirmala / AP / MCA Page : 10 MC7404 NETWORK PROGRAMMING UNIT – I 2. exit() : C Standard Library exit procedure that will cleanly terminate a process by invoking additional code as requested by the user and to manage ongoing I/O. 3. _Exit() : C Standard Library exit procedure that will immediately terminate a process, essentially a wrapper to _exit() I/O Buffering and Exit Procedures One aspect of the standard library exit procedure is to handle I/O buffering that occurs within the C standard library. Figure 3: C Program Life Cycle: Standard I/O Cleanup Buffering is one way to avoid excessive calls. When you call printf() or another standard I/O library function that is printing to the terminal or a file, the print does not occur right away. Instead, it is buffered, or temporarily stored and waiting to be completed. A print will become unbuffered whenever the buffer is full, e.g., there is enough bytes to write and cannot store any more, or when a line completes, as defined by printing a newline symbol. Case 1 Return from main() #include<stdio.h> #include<unistd.h> #include<stdlib.h> int main() { printf("Hello"); exit(0); } exit() function is used to terminate a process exit() flushes (cleans the) the IO related buffer before exiting the process and calls the _exit() function. Sample code with exit function: #include<stdio.h> #include<unistd.h> #include<stdlib.h> Prepared by : Mrs. M.Nirmala / AP / MCA Page : 11 MC7404 NETWORK PROGRAMMING UNIT – I int main() { printf("Hello"); exit(0); } Output: admin@nirmala ~ $ cc exit.c admin@nirmala ~ $ ./a Hello #include<stdio.h> #include<unistd.h> #include<stdlib.h> int main() { printf("Hello"); _exit(0); } outPut: admin@nirmala ~ $ cc exit.c admin@nirmala ~ $ ./a admin@nirmala ~ It prints nothing. Explanation: This is due to ,we called _exit() function directly, so IO related data is not flushed, so printf data is not flushed, because of this, it has printed nothing. Sample code with _exit function with \n: #include<stdio.h> #include<unistd.h> #include<stdlib.h> int main() { printf("Hello\n"); _exit(0); //or _Exit(0); // they are equivalent } OutPut: Prepared by : Mrs. M.Nirmala / AP / MCA Page : 12 MC7404 NETWORK PROGRAMMING UNIT – I sh-4.2# cc exit.c sh-4.2# ./a.out Hello We got the output Hello, this is due to we are forcefully flushing the data using '\n'. Infact printf() function wont print or flush the data until buffer completes or end of the character is \n. printf internally maintains some buffer. Abnormal termination occurs in three ways: 6. Calling abort 7. Receipt of a signal 8. Response of the last thread to a cancellation request atexit() Exit Handlers atexit - register a function to be called at normal process termination atexit function: A process can register up to 32 functions that are automatically called by exit. These are called exit handlers and are registered by calling the atexit function. Syntax: #include <stdlib.h> int atexit (void (*func)(void)); Here, the user pass the address of a function as the argument to atexit .When this function is called it, is not passed any arguments and is not expected to return a value. Syntax The atexit() function registers the given function to be called at normal process termination, either via exit(3) or via return from the program's main(). Functions so registered are called in the reverse order of their registration; no arguments are passed. The same function may be registered multiple times: it is called once for each registration. The atexit() function returns the value 0 if successful; otherwise it returns a nonzero value #include <stdio.h> #include <stdlib.h> void my_exit1(void); void my_exit2(void); int main(void) Prepared by : Mrs. M.Nirmala / AP / MCA Page : 13 MC7404 NETWORK PROGRAMMING UNIT – I { int k; if (atexit(my_exit1) != 0) { printf("cant register my_exit1 "); exit(0); } k = atexit(my_exit2); if (k != 0) { printf("can't register my_exit1"); exit(0); } return(0); } void my_exit1(void) { printf("first exit handler\n"); } void my_exit2(void) { printf("second exit handler\n"); } Exit Statuses The last bit of the exit() puzzle is exit status. Every program exits with some status. _exit(int status); exit(int status); _Exit(int status); Additionally, the return value of main() implicitly sets the exit status. Convention indicates the following exit status: 0 : success 1 : failure 2 : error Memory Layout of a C program Historically a C program has been composed of o Text segment o Initialised data segment o Uninitialised data segment o Stack Prepared by : Mrs. M.Nirmala / AP / MCA Page : 14 MC7404 NETWORK PROGRAMMING UNIT – I o Heap Text segment o machine instructions, executed by the CPU o sharable, only a single copy needs to be in the memory for frequently executed program o read-only, to prevent a program from being accidently modifying its instructions Initialised data segment (or data segment) o contains variables that are specifically initialised in the program e.g. o int max = ; Unintialised data segment o often called ―bss‖ segment -- block started by symbol o data is initialised by the kernel to be before the program starts executing o e.g. o long sum[ ; appear outside any function ==> stored in uninitialised data segment Stack o stores automatic variables + information saved each time a function is called Heap o Dynamic memory allocation usually takes place on the heap o Normally located between the uniintialised data segment and the stack PROCESS CONTROL The process control provided by the UNIX system includes, The creation of new processes Program execution Program termination Process Identifiers: Every process has a unique process ID which is a non-negative integer. There are some special processes available. Example: (i) Process ID 0 is usually the scheduler process and is often known as the swapper. It is a part of the kernel and is called the system process (ii) Process ID 1 is usually the init process and is invoked by the kernel at the end of the bootstrap procedure. It is a normal process and not a system process. Prepared by : Mrs. M.Nirmala / AP / MCA Page : 15 MC7404 NETWORK PROGRAMMING UNIT – I (iii) Process Id 2 is the page daemon responsible for su pporting the paging of the virtual memory system. In addition to the process ID, there are other identifiers for every process. The following function returns these identifiers #include<unistd.h> pid_t getpid(void) Returns: process Id of calling process pid_t getppid(void) Returns: parent process ID of calling process uid_t getuid(void) Returns : real user ID of calling process uid_t geteuid(void) Returns: effective user ID of calling process gid_t getgid(void) Returns: real group ID of calling process gid_t getegid(void) Returns: effective group ID of calling process Process Creation in UNIX Every process, except process 0, is created by the fork() system call fork() allocates entry in process table and assigns a unique PID to the child process child gets a copy of process I mage of parent: both child and parent are executing the same code following fork() but fork() returns the PID of the child to the parent process and returns 0 to the child process Process 0 is created at boot time and becomes the ―swapper‖ after forking process 1 (the INIT process) When a user logs in: process 1 creates a process for that user Process creation There are three distinct phases in the creation of a process 1. Forking 2. Overlaying and execution 3. Waiting Forking Forking is the first phase in the creation of a process by a process. Prepared by : Mrs. M.Nirmala / AP / MCA Page : 16 MC7404 NETWORK PROGRAMMING UNIT – I The calling process (parent) makes a call to the system routine fork() which then makes an exact copy of itself. Right after the fork() there will be 2 processes with identical memory images. Each one of these 2 processes has to return from the fork() system call. Thus there will be 2 return values. The fork of the parent process returns the PID of the new processes, that is the child process just created, whereas the fork of the child returns a 0. If a new child is process is not created a -1 is returned Child gets a copy of parents text, data , heap and stack Instead of completely copying we can use COW copy on write technique is used. These regions are shared by the parent and the child and have their protection changed by the kernel to read only. Immediately after forking the parent makes a system call to one of the wait() functions. The paren‘t waits for the child process to complete its task There are also symbolic constants defined in unistd.h for the file descriptors belonging to the standard streams stdin, stdout, and stderr; see Standard Streams. STDIN_FILENO This macro has value 0, which is the file descriptor for standard input. STDOUT_FILENO This macro has value 1, which is the file descriptor for standard output. STDERR_FILENO This macro has value 2, which is the file descriptor for standard error output. Prepared by : Mrs. M.Nirmala / AP / MCA Page : 17 MC7404 NETWORK PROGRAMMING UNIT – I #include #include #include #include <sys/types.h> <stdio.h> <sys/wait.h> <unistd.h> int glob = 6; /* external variable in initialized data */ char buf[ ] = "a write to stdout\n"; int main(void) { Int var; /* automatic variable on the stack */ pid_t pid; var = 88; if (write(STDOUT_FILENO,buf, sizeof(buf)-1) != sizeof(buf)-1) printf("write error"); printf("before fork\n"); if ( (pid = fork()) < 0) printf("fork error"); else if (pid == 0) { /* child */ glob++; /* modify variables */ var++; } else sleep(2); /* parent */ printf("pid = %d, glob = %d, var = %d ppid = %d\n", getpid(), glob, var, getppid()); exit(0); } admin@nirmala ~ $ ./a a write to stdout before fork pid = 4168, glob = 7, var = 89 pid = 4140, glob = 6, var = 88 Signals A signal is an asynchronous event which is delivered to a process. Signals are called as software interrupts Prepared by : Mrs. M.Nirmala / AP / MCA Page : 18 MC7404 NETWORK PROGRAMMING UNIT – I Asynchronous means that the event can occur at any time – may be unrelated to the execution of the process – e.g. user types ctrl-C, or the modem hangs An important feature of signals is that they are asynchronous, which means that a process may receive a signal at any time during its execution, and must be prepared to respond to the signal at that time Signals are usually sent by the Operating System (kernel) to notify processes that some event has occurred. By their nature, signals interrupt whatever the process is doing at that moment, and force it to handle them immediately Signal Sources: Hardware - division by zero Kernel – notifying an I/O device for which a process has bee n waiting is available Other Processes – a child notifies its parent that it has terminated User – key press (i.e., Ctrl-C) Syntax signal() is a function that accepts two arguments and returns a pointer to a function that takes one argument, the signal handler, and returns nothing. If the call fails, it returns SIG_ERR. The arguments are The first is an integer (i.e., int), a signal name. The second is a function that accepts an int argument and returns nothing, the signal handler. If you want to ignore a signal, use SIG_IGN as the second argument. If you want to use the default way to handle a signal, use SIG_DFL as the second argument Examples The following ignores signal SIGINT signal(SIGINT, SIG_IGN); The following uses the default way to handle SIGALRM signal(SIGALRM, SIG_DFL); The following installs function INThandler() Prepared by : Mrs. M.Nirmala / AP / MCA Page : 19 MC7404 NETWORK PROGRAMMING UNIT – I as the signal handler for signal SIGINT signal(SIGINT, INThandler); Procedure Prepare a function that accepts an integer, a signal name, to be a signal handler. 2. Call signal() with a signal name as the first argument and the signal handler as the second. 3. When the signal you want to handle occurs your signal handler is called with the argument the signal name that just occurred. 4. Two important notes: a. You might want to ignore that signal in your handler b. Before returning from your signal handler, don‘t forget to re -install it. For example, the user may want to stop the process any time by pressing Control-C, which results in SIGINT signal. Each signal has an integer number, as well as a symbolic name associated with it. There are 30 odd signals and all these names begin with the three characters SIG Linux supports 31 different signals They are accessed by the header file <signal.h> value symbol purpose 1 SIGHUP hangup on control terminal 2 SIGINT interrupt from keyboard (Ctrl-c) 3 SIGQUIT quit from keyboard (Ctrl-\) 8 SIGFPE floating point exception (e.g. divide by 0) 9 SIGKILL terminate receiving process 14 SIGALRM end of alarm() system call timeout 15 SIGTERM default kill command signal 17 SIGCHLD child process stopped or terminated 19 SIGSTOP stop execution from keyboard Ctrl-z There are about 25 different kinds of signals, depending on the flavor of the system. Use the command kill -l, to get the list of signals supported by your system admin@nirmala ~ $ kill -l 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL Prepared by : Mrs. M.Nirmala / AP / MCA Page : 20 MC7404 NETWORK PROGRAMMING UNIT – I 5) SIGTRAP 6) SIGABRT 7) SIGEMT 8) SIGFPE 9) SIGKILL 10) SIGBUS 11) SIGSEGV 12) SIGSYS 13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGURG 17) SIGSTOP 18) SIGTSTP 19) SIGCONT 20) SIGCHLD 21) SIGTTIN 22) SIGTTOU 23) SIGIO 24) SIGXCPU 25) SIGXFSZ 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGLOST 30) SIGUSR1 31) SIGUSR2 For some signals, the default behavior is to ignore the signal. For others, the default behavior is to terminate the process. The process can catch most of the signals except for a few. The process cannot catch SIGKILL & SIGSTOP signals. W hen the process receives such signals, it will be terminated. What is signal handling? We all have faced the traffic signals. How do we handle it? Green? we go ahead. Yellow? we slow down. Red? we stop. Same way how a program (process) handles the signals it receives is referred to as signal handling. How to handle signals? How did we learn to handle signals? Somebody, probably our parents taught us. The user tells the program what to do when it receives a signal. Similarly, you need to tell your program what should it do when it receives a signal and that is called as signal handling Programming Signal Handling THE SIGNAL The signal what is to be handled whould be known. THE HANDLER The handler is the main thing used to handle signals It gets the signal and performs whatever we want it to do with the signal. THE CONNECTION How to connect the signal with the handler? The program should know which handler is associated with which signal We can have different handlers for different signals. The proce ss of setting up the handler for a signal is called as signal set up. signal function The signal function connects the signal with the handler. Below example shows a very basic signal handling. Prepared by : Mrs. M.Nirmala / AP / MCA Page : 21 MC7404 NETWORK PROGRAMMING UNIT – I #include<stdio.h> #include<signal.h> void sigHandlerFunc(int sig); //signal handler prototype int main() { int i; for(i=0;i<5;i++) { printf(" \n Number %d",i); signal(SIGUSR1, sigHandlerFunc); //signal is declared and called raise(SIGUSR1); } return 0; } void sigHandlerFunc(int sig) { printf("\n Hey there! Just got this signal %d",sig); } //output Number 0 Hey there! Number 1 Hey there! Number 2 Hey there! Number 3 Hey there! Number 4 Hey there! Just got this signal 30 Just got this signal 30 Just got this signal 30 Just got this signal 30 Just got this signal 30 The process cannot catch SIGKILL & SIGSTOP signals. When the process receives such signals, it will be terminated #include <stdio.h> #include <unistd.h> #include <signal.h> /* * signal handler */ Prepared by : Mrs. M.Nirmala / AP / MCA Page : 22 MC7404 NETWORK PROGRAMMING UNIT – I void CatchInterrupt (int signum) { pid_t my_pid; printf("\nReceived an interrupt! About to exit ..\n"); fflush(stdout); my_pid = getpid(); kill(my_pid, SIGKILL); } int main(int argc, char** argv) { /* * Set the INT (Ctrl-C) signal handler to 'CatchInterrupt' */ signal(SIGINT, CatchInterrupt); /* * Do Nothing and wait for interrupts */ for ( ;; ) {} } In the above program, the process simply waits in an infinite loop, for an interrupt event to occur and as soon as it receive one, it exits after printing a message on the console. //output //create a signal by pressing ctrl + c $ ./a Received an interrupt! About to exit .. Killed Sleep #include <unistd.h> unsigned int sleep(unsigned int seconds); Returns: 0 or number of unslept seconds. This function causes the calling process to be suspended until either Prepared by : Mrs. M.Nirmala / AP / MCA Page : 23 MC7404 NETWORK PROGRAMMING UNIT – I • The amount of wall clock time specified by seconds has elapsed. The return value is 0. A signal is caught by the process and the signal handler returns. Return value is the number of unslept seconds. #include <stdio.h> #include <signal.h> /* * number of times the handle will run: */ int count = 3; void handle(int sig) { printf("\n network programming \n"); --count; alarm(1); } int main() { signal(SIGALRM, handle); alarm(1); while(count) { sleep(1); } printf("done\n"); return 0; } admin@nirmala ~ $ cc sig7.c admin@nirmala ~ $ ./a network programming network programming network programming done Prepared by : Mrs. M.Nirmala / AP / MCA Page : 24 MC7404 NETWORK PROGRAMMING UNIT – I INTERPROCESS COMMUNICATION InterprocessCommunication (IPC) enables processes to communicate with each other to share information Interprocess communication has 2 forms IPC is used for 2 functions: 1) Synchronization---Used to coordinate access to resources among processes and also to coordinate the execution of these processes. They are Record locking, Semaphores, Mutexes and Condition variables. 2) Message Passing---Used when processes wish to exchange information. Message passing takes several forms such as : Pipes, FIFOs, Message Queues, Shared Memory. File or Record Locking: Used to ensure that a process has exclusive access to a file before using it. Simple Client-Server or IPC model: Pipes A pipe provides a one way flow of data #include <unistd.h> int pipe(int fildes[2]); fildes[0] is open for reading and fildes[1] is open for writing Prepared by : Mrs. M.Nirmala / AP / MCA Page : 25 MC7404 NETWORK PROGRAMMING UNIT – I The output of fildes[1] is the input for fildes[0] //pipe creation and its usage #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <sys/types.h> #include <unistd.h> main() { int pipefd[2], n; char buff[100]; if (pipe(pipefd) < 0 ) printf("pipe error"); //pipe not created printf("read fd = %d, write fd = %d \n", pipefd[0], pipefd[1]); printf("\n The word written in pipe "); write(pipefd[1], "HELLO WORLD" , 12); n = read(pipefd[0],buff,sizeof(buff)); write(1, buff, n); /*fd=1=stdout*/ } //output admin@nirmala ~ $ ./a read fd = 3, write fd = 4 HELLO WORLD The word written in pipe is #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> void client(int readfd, int writefd) { char msg[100]; int n; char eof = EOF; printf("\n Enter msg to be sent to server: " ); fgets(msg, 100, stdin); if (write(writefd, msg, strlen(msg) - 1) == -1){ perror("error writing..."); exit(0); } if ((n = read(readfd, msg, 100)) < 0) { perror("error reading..."); exit(0); } msg[n] = '\0'; Prepared by : Mrs. M.Nirmala / AP / MCA Page : 26 MC7404 NETWORK PROGRAMMING UNIT – I printf(" \n received from server: %s", msg); } void server(int readfd, int writefd) { char msg[100]; int n; if ((n = read(readfd, msg, 100)) < 0) { perror("error reading..."); } msg[n] = '\0' ; printf("\n server received from client: %s ",msg); printf("\n enter msg to be sent to client: "); fgets(msg, 100, stdin); write(writefd, msg, strlen(msg) - 1); } int main() { int pipe1fd[2], pipe2fd[2]; int pid; /* create two pipes */ if (pipe(pipe1fd) == -1) { perror("pipe:"); return 0; } if (pipe(pipe2fd) == -1) { perror("pipe:"); return 0; } /* start child process and run client code in it */ pid = fork(); if (pid == 0) { close(pipe1fd[1]); //close the write end of the first pipe close(pipe2fd[0]); //close the read end of the second pipe client(pipe1fd[0], pipe2fd[1]); exit(0); } else { /* code that runs in parent ; runs as server */ close(pipe1fd[0]); // close read end of the first pipe close(pipe2fd[1]); // close write end of the second pipe server(pipe2fd[0], pipe1fd[1]); wait(NULL); //wait for child process to finish return 0; } } Prepared by : Mrs. M.Nirmala / AP / MCA Page : 27 MC7404 NETWORK PROGRAMMING UNIT – I OUTPUT admin@nirmala ~ $ ./a Enter msg to be sent to server: hello server received from client: hello enter msg to be sent to client: hai received from server: hai The program above creates two pipes and use them for two way communication between client and server 1. Create two pipes, pipe1 (pipe1fd[2]) and pipe2 (pipe2fd[2]). 2. call fork to create a child process and let child process run client code 3. In child process close write end of pipe1 (pipe1fd[1]) and read end of pipe2 (pipe2fd[0]) 4. parent process close read end of pipe1 (pipe1fd[0]) and write end of pipe2 (pipe2fd[1]) If all file descriptors referring to the write end of a pipe have been closed, then an attempt to read from the pipe will see en d-of-file (read will return 0).If all file descriptors referring to the read end of a pipe have been closed, then a write will cause a SIGPIPE signal to be generated for the calling process. Properties of Pipe: 1) Pipes do not have a name. For this reason, the processes must share a parent process. This is the main drawback to pipes. 2) Pipes do not distinguish between messages; they just read a fixed number of bytes. Newline (\n) can be used to separate messages. A structure with a length field can be used for message containing binary data. 3) Pipes can also be used to get the output of a command or to provide input to a command FIFOs–named pipes With regular pipes, only processes with a common ancestor can communicate With FIFOs, any two processes can communicate Creating and opening a FIFO is just like creating and opening a file Definition: A FIFO is similar to a pipe. A FIFO (First In First Out) is a one -way flow of data. FIFOs have a name, so unrelated processes can share the FIFO. FIFO is a named pipe. This is the main difference between pipes and FIFOs. Prepared by : Mrs. M.Nirmala / AP / MCA Page : 28 MC7404 NETWORK PROGRAMMING UNIT – I Creat: A FIFO is created by the mkfifo function: #include <sys/types.h> #include <sys/stat.h> int mkfifo(const char *pathname, mode_t mode); pathname – a UNIX pathname (path and filename). The name of the FIFO mode – the file permission bits. FIFO can also be created by the mknod system call, e.g., mknod(―fifo1‖, S_IFIFO|0666, 0) is same as mkfifo(―fifo1‖, 0666). Open: mkfifo tries to create a new FIFO. If the FIFO already exists, then an EEXIST error is returned. To open an existing FIFO, use open(), fopen() or freopen() Close: to close an open FIFO, use close(). To delete a created FIFO, use unlink(). Properties: ( Some of them are also applicable to PIPES) 1) After a FIFO is created, it can be opened for read or write. 2) Normally, opening a FIFO for read or write, it blocks until another process opens it for write or read. mode : The file protection mode usually given by 9 bits indicat ing rwx permission The flag codes are given by O_RDONLY -- opens file for read only O_WRONLY – opens file for write only O_RDWR – opens file for reading and writing O_NDELAY – prevents possible blocking Prepared by : Mrs. M.Nirmala / AP / MCA Page : 29 MC7404 NETWORK PROGRAMMING UNIT – I O_APPEND --- opens the file for appending O_CREAT -- creates the file if it does not exists O_TRUNC -- truncates the size to zero O_EXCL – produces an error if the O_CREAT bit is on and file exists Open: mkfifo tries to create a new FIFO. If the FIFO already exists, then an EEXIST error is returned. To open an existing FIFO, use open(), fopen() or freopen() Close: to close an open FIFO, use close(). To delete a created FIFO, use unlink(). Properties: (mode – the file permission bits) There are file access permissions and there are nine permission bits for each file divided into 3 categories. st_mode mask S_IRUSR S_IWUSR S_IXUSR S_IRGRP S_IWGRP S_IXGRP S_IROTH S_IWOTH S_IXOTH Meaning Examples user-read user-write user-execute group-read group-write groupexecute other-read other-write otherexecute chmod chmod chmod chmod chmod chmod u+r u+w u+x g+x g+x g+x Set - chmod u+rwx Unset – chmod u-rwx chmod o+x chmod o+x chmod o+x Set - chmod o+rwx Unset – chmod o-rwx Set - chmod g+rwx Unset – chmod g-rwx Chmod - used to change the file permissions to a existing file To check whether the permissions has been set ls –l filename Prepared by : Mrs. M.Nirmala / AP / MCA Page : 30 MC7404 NETWORK PROGRAMMING UNIT – I admin@nirmala ~ $ ls -l a.c ----rwxrwx 1 admin mkpasswd 52 Jan 21 22:22 a.c For IPC FIFO Sender process Receiver process A Channel to pass the data In our case it is FIFO Algorithm (Client Side) 1. Start. 2. Open well known server FIFO in write mode. 3. Write the pathname of the file in this FIFO and send the request. 4. Open the client specified FIFO in read mode and wait for reply. 5. When the contents of the file are available in FIFO, display it on the terminal 6. Stop. Algorithm (Server Side) 1. Start. 2. Create a well known FIFO using mkfifo() 3. Open FIFO in read only mode to accept request from clients. 4. When client opens the other end of FIFO in write only mode, then read the contents and store it in buffer. 5. Create another FIFO in write mode to send replies. 6. Open the requested file by the client and write the contents into the client specified FIFO and terminate the connection. 7. Stop. //fifo writer #include <fcntl.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> int main() { int fd; char *msg; char * myfifo = "myfifo"; /* create the FIFO (named pipe) */ mkfifo(myfifo, 0666); /* write a message to the FIFO */ fd = open(myfifo, O_WRONLY); printf(―\n Enter the message to send : ‖); scanf(―%s‖,msg); write(fd, msg, sizeof(msg)); Prepared by : Mrs. M.Nirmala / AP / MCA Page : 31 MC7404 NETWORK PROGRAMMING UNIT – I close(fd); /* remove the FIFO */ unlink(myfifo); return 0; } //fifo reader #include <fcntl.h> #include <stdio.h> #include <sys/stat.h> #include <unistd.h> #define MAXBUF 1024 int main() { int fd; char * myfifo = "myfifo"; char buf[MAXBUF]; /* open, read, and display the message from the Fifo */ fd = open(myfifo, O_RDONLY); read(fd, buf, MAXBUF); printf("Received: %s \n", buf); close(fd); return 0; } //execute writer first [root@localhost ~]# cc fifowriter.c [root@localhost ~]# ./a.out Enter the message to send : hello [root@localhost ~]# //output reader [root@localhost ~]# cc fiforeader.c [root@localhost ~]# ./a.out Received: hello [root@localhost ~]# Message Queues Drawback of PIPE and FIFO: 1) Pipe or FIFO is an unformatted stream. Message queue is a formatted stream consisted of messages. 2) Pipe or FIFO has to be read in the same order as they are written. Message queue can be accessed randomly. 3) Pipe or FIFO is unidirectional. Message queue is bidirectional. 4) Pipe or FIFO is simplex. Message queue is multiplex. 5) Message queue is faster since it is in kernel. Prepared by : Mrs. M.Nirmala / AP / MCA Page : 32 MC7404 NETWORK PROGRAMMING UNIT – I Message Queue Properties Unlike pipes and FIFOs, message queues support messages that have structure. Message queues are are persistent objects that must be initially created and eventually deleted when no longer required. Message queues are created with a specified maximum message size and maximum number of messages. Message queues are created and opened using a special version of the open system call, mq_open. It is identified by an queue identifier Linked list of messages stored in the kernel Identifier by a message queue identifier Created or opened with msgget() Messages are added to the queue with msgsnd() Specifies type, length, and data of msg Messages are read with msgrcv() Message format: A message queue is created or opened using: int msgget(key_t key, int msgflag) msgflag — sets permission + IPC_CREAT / IPC_EXCL msgid — returned by the msgget() function, -1 on error. Messages are sent using: int msgsnd(int msgid, struct msgbuf *ptr, int length, int flag) struct msgbuf -- message format, has a long int (message type) as a field, immediately followed by the data. Must be filled by caller before calling msgsnd(). length — determine how many bytes of data portion are sent. flag — can be IPC_NOWAIT which causes the function to return immediately with error=EAGAIN if no queue space is available. Default action is to block. return — 0 if successful; -1 on error. Messages are received using: int msgrcv(int msgid, struct msgbuf *ptr, int length, long msgtype, int flag) length — specify the size of the data buffer. Error if the message is too long. OK if the length ≥ message length which is determined by msgsnd(… length…). flag — if set to MSG_NOERROR, long messages are truncated and the rest is discarded. //IPC message send #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> Prepared by : Mrs. M.Nirmala / AP / MCA Page : 33 MC7404 NETWORK PROGRAMMING UNIT – I #include <stdio.h> #include <string.h> #include <stdlib.h> #define MAXSIZE 128 void die(char *s) { perror(s); exit(1); } struct msgbuf { long mtype; char mtext[MAXSIZE]; }; main() { int msqid; int msgflg = IPC_CREAT | 0666; key_t key; struct msgbuf sbuf; size_t buflen; key = 1234; if ((msqid = msgget(key, msgflg )) < 0) //Get the message queue ID for the given key die("msgget"); //Message Type sbuf.mtype = 1; printf("Enter a message to add to message queue : "); scanf("%[^\n]",sbuf.mtext); getchar(); buflen = strlen(sbuf.mtext) + 1 ; if (msgsnd(msqid, &sbuf, buflen, IPC_NOWAIT) < 0) { printf ("%d, %d, %s, %d\n", msqid, sbuf.mtype, sbuf.mtext, buflen); die("msgsnd"); } else printf("Message Sent\n"); exit(0); } Prepared by : Mrs. M.Nirmala / AP / MCA Page : 34 MC7404 NETWORK PROGRAMMING UNIT – I //IPC_msgq_rcv.c #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <stdio.h> #include <stdlib.h> #define MAXSIZE 128 void die(char *s) { perror(s); exit(1); } typedef struct msgbuf { long mtype; char mtext[MAXSIZE]; }; int main() { int msqid; key_t key; struct msgbuf rcvbuffer; key = 1234; if ((msqid = msgget(key, 0666)) < 0) die("msgget()"); //Receive an answer of message type 1. if (msgrcv(msqid, &rcvbuffer, MAXSIZE, 1, 0) < 0) die("msgrcv"); printf("%s\n", rcvbuffer.mtext); exit(0); } //sender should be executed then receiver program [root@localhost ~]# cc IPCmsgsend.c [root@localhost ~]# ./a.out Enter a message to add to message queue : network Message Sent [root@localhost ~]# ./a.out Enter a message to add to message queue : programming Message Sent [root@localhost ~]# ipcs -q ------ Message Queues -------key msqid owner perms 0x000004d2 0 root 666 used-bytes messages 20 2 Prepared by : Mrs. M.Nirmala / AP / MCA Page : 35 MC7404 NETWORK PROGRAMMING UNIT – I [root@localhost ~]# [root@localhost ~]# Enter a message to Message Sent [root@localhost ~]# cc IPCmsgsend.c ./a.out add to message queue : laboratory ipcs -q ------ Message Queues -------key msqid owner perms 0x000004d2 0 root 666 [root@localhost [root@localhost network [root@localhost programming [root@localhost used-bytes messages 31 3 ~]# cc IPCmsgrcv.c ~]# ./a.out ~]# ./a.out ~]# ipcs -q ------ Message Queues -------key msqid owner perms 0x000004d2 0 root 666 used-bytes messages 11 1 [root@localhost ~]# ./a.out laboratory [root@localhost ~]# ./a.out [6]+ Stopped ./a.out [root@localhost ~]# ipcs -q ------ Message Queues -------key msqid owner perms 0x000004d2 0 root 666 used-bytes messages 0 0 [root@localhost ~]# ./a.out SHARED MEMORY Sharing memory in POSIX (and many other systems) requires creating a persistent ―object‖ associated with the shared memory, and allowing processes to connect to the object.Creating or connecting to the persistent object is done in a manner similar to that for a file, but uses the shm_open system call. In the fork() system call, the parent and children have separateaddress space or memory. The parent and child will no way communicate and can execute independent of each other Prepared by : Mrs. M.Nirmala / AP / MCA Page : 36 MC7404 NETWORK PROGRAMMING UNIT – I A shared memory is an extra piece of memory that is attached to some address spaces for their owners to use. All of these processes share the same memory segment and have access to it. Consequently, race conditions may occur if memory accesses are not handled properly. The following figure shows two processes and their address spaces. The yellow rectangle is a shared memory attached to both address spaces and both process 1 and process 2 can have access to this shared memory as if the shared memory is part of its own address space. One process must explicitly ask for an area, using a key, to be shared by other processes. This process will be called the server. All other processes, the clients, that know the shared area can access it. However, there is no protection to a shared memory and any process that knows it can access it freely. To protect a shared memory from being accessed at the same time by several processes, a synchronization protocol must be setup. A shared memory segment is identified by a unique integer, the shared memory ID. The shared memory itself is described by a structure of type shmid_ds in header file sys/shm.h. To use this file, files sys/types.h and sys/ipc.h must be included. #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> A general scheme of using shared memory is the following: For a server, it should be started before any client. The server should perform the following tasks: 1. Ask for a shared memory with a memory key and memorize the returned shared memory ID. This is performed by system call shmget(). 2. Attach this shared memory to the server's address space with system call shmat(). 3. Initialize the shared memory, if necessary. 4. Do something and wait for all clients' completion 5. Detach the shared memory with system call shmdt(). Prepared by : Mrs. M.Nirmala / AP / MCA Page : 37 MC7404 NETWORK PROGRAMMING UNIT – I 6. Remove the shared memory with system call shmctl(). For the client part, the procedure is almost the same: 1. Ask for a shared memory with the same memory key and memorize the returned shared memory ID. 2. Attach this shared memory to the client's address space. 3. Use the memory. 4. Detach all shared memory segments, if necessary. 5. Exit. shmget() shm_id = shmget ( key_t k, /* the key for the segment */ int size, /* the size of the segment */ int flag ); /* create/use flag */ In the above definition, k is of type key_t or IPC_PRIVATE. It is the numeric key to be assigned to the returned shared memory segment. size is the size of the requested shared memory. The purpose of flag is to specify the way that the shared memory will be used. For our purpose, only the following two values are important: 1. IPC_CREAT | 0666 for a server (i.e., creating and granting read and write access to the server) 2. 0666 for any client (i.e., granting read and write access to the client) If shmget( ) can successfully get the requested shared memory, its function value is a non-negative integer, the shared memory ID; otherwise, the function value is negative UNIX requires a key of type key_t defined in file sys/types.h for requesting resources such as shared memory segments, message queues and semaphores. A key is simply an integer of type key_t; however, you should not use int or long, since the length of a key is system dependent The ftok( ) function has the following prototype: key_t ftok ( const char *path, /* a path string */ int id /* an integer value */ ); Function ftok( ) takes a character string that identifies a path and an integer (usually a character) value, and generates an integer of type key_t based on the first argument with the value of id in the most significant position Function ftok( ) takes a character string that identifies a path and an integer (usually a character) value, and generates an integer of type key_t based on the first argument with the value of id in the most significant position. For example, if the generated integer is 35028A5D16 and the value of id is 'a' (ASCII value = 6116), then ftok( ) returns 61028A5D16. That is, 6116 replaces the first byte of 35028A5D16,generating 61028A5D16 Prepared by : Mrs. M.Nirmala / AP / MCA Page : 38 MC7404 NETWORK PROGRAMMING UNIT – I After a shared memory ID is returned, the next step is to attach it to the address space of a process. This is done with system call shmat( ). The use of shmat( ) is as follows: shm_ptr = shmat ( int shm_id, /* shared memory ID */ char *ptr, /* a character pointer */ int flag ); /* access flag */ System call shmat( ) accepts a shared memory ID, shm_id, and attaches the indicated shared memory to the program's address space. The returned value is a pointer of type (void *) to the attached shared memory. Thus, casting is usually necessary. If this call is unsuccessful, the return value is -1. Normally, the second parameter is NULL. If the flag is SHM_RDONLY, this shared memory is attached as a read-only memory; otherwise, it is readable and writable. Detaching and Removing a Shared Memory Segment - shmdt( ) and shmctl( ): System call shmdt( ) is used to detach a shared memory. After a shared memory is detached, it cannot be used. However, it is still there and can be re -attached back to a process's address space, perhaps at a different address. To remove a shared memory, use shmctl( ). Two different processes communicating via shared memory we develop two programs here that illustrate the passing of a simple piece of memory (a string) between the processes if running simultaneously: /* shm_server.c */ #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <stdio.h> #include <stdlib.h> #define SHMSIZE 27 main() { char c; int shmid; key_t key; char *shm, *s; /* * We'll name our shared memory segment * "5678". */ key = 5678; /* * create the segment.* */ if ((shmid = shmget(key, SHMSIZE, IPC_CREAT | 0666)) < 0) Prepared by : Mrs. M.Nirmala / AP / MCA Page : 39 MC7404 NETWORK PROGRAMMING UNIT – I { perror("shmget"); exit(1); } printf("%d",shmid); /** Now we attach the segment to our data space.*/ shm = (char*) shmat(shmid, NULL,0); if (shm == (char *)-1) { perror("shmat"); exit(1); } /** Now put some things into the memory for the other process to read. */ s = shm; for (c = 'a'; c <= 'z'; c++) { *s++ = c; } *s = '\0'; /** Finally, we wait until the other process * Changes the first character of our memory * to '*', indicating that it has read what * we put there. */ while (*shm != '*') sleep(1); printf("%c",*shm); exit(0); } /* shm_client.c */ /* * shm-client - client program to demonstrate shared memory. */ #include <sys/types.h> #include <sys/ipc.h> #include <stdlib.h> #include <sys/shm.h> #include <stdio.h> #define SHMSIZE 27 main() { int shmid; key_t key; char *shm, *s; /* Prepared by : Mrs. M.Nirmala / AP / MCA Page : 40 MC7404 NETWORK PROGRAMMING UNIT – I * We need to get the segment named * "5678", created by the server. */ key = 5678; /* * Locate the segment. */ if ((shmid = shmget(key, SHMSIZE, 0666)) < 0) { perror("shmget"); exit(1); } /* Now we attach the segment to our data space. */ if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) { perror("shmat"); exit(1); } /* Now read what the server put in the memory. */ for (s = shm; *s != '\0'; s++) putchar(*s); putchar('\n'); /* * Finally, change the first character of the * segment to '*', in dicating we have read * the segment. */ *shm = '*'; printf ("\nIts done from client.\n\n\n"); exit(0); } //output Execute server first //server [root@localhost ~]# cc shmserver.c [root@localhost ~]# ./a.out 4915214*[root@localhost ~]# Client [root@localhost ~]# cc shmclient.c [root@localhost ~]# ./a.out abcdefghijklmnopqrstuvwxyz Its done from client. [root@localhost ~]# Characteristics of TCP TCP also provides reliability. TCP contains algorithms to estimate the round-trip time (RTT) between a client and server dynamically so that it knows how long to wait for an acknowledgment. TCP also sequences the data by associating a sequence number with every byte that it sends. Prepared by : Mrs. M.Nirmala / AP / MCA Page : 41 MC7404 NETWORK PROGRAMMING UNIT – I TCP provides flow control. TCP always tells its peer exactly how many bytes of data it is willing to accept from the peer at any one time. This is called the advertised window. TCP connection is full-duplex. This means that an application can send and receive data in both directions on a given connection at any time. TCP Connection Establishment and Termination Three-Way Handshake The following scenario occurs when a TCP connection is established: 1. The server must be prepared to accept an incoming connection. This is normally done by calling socket, bind, and listen and is called a passive open. 2. The client issues an active open by calling connect. This causes the client TCP to send a "synchronize" (SYN) segment, which tells the server the client's initial sequence number for the data that the client will send on the connection. Normally, there is no data sent with the SYN; it just contains an IP header, a TCP header, and possible TCP options. 3. The server must acknowledge (ACK) the client's SYN and the server must also send its own SYN containing the initial sequence number for the data that the server will send on the connection. The server sends its SYN and the ACK of the client's SYN in a single segment. 4. The client must acknowledge the server's SYN. The minimum number of packets required for this exchange is three; hence, this is called TCP's three-way handshake. TCP Three-way Handshake TCP Connection Termination While it takes three segments to establish a connection, it takes four to terminate a connection. 1. One application calls close first, and we say that this end performs the active close. This end's TCP sends a FIN segment, which means it is finished send ing data. 2. The other end that receives the FIN performs the passive close. The received FIN is acknowledged by TCP. The receipt of the FIN is also passed to the Prepared by : Mrs. M.Nirmala / AP / MCA Page : 42 MC7404 NETWORK PROGRAMMING UNIT – I application as an end-of-file (after any data that may have already been queued for the application to receive), since the receipt of the FIN means the application will not receive any additional data on the connection. Packets exchanged when a TCP connection is closed 3. Sometime later, the application that received the end-of-file will close its socket. This causes its TCP to send a FIN. 4. The TCP on the system that receives this final FIN (the end that did the active close) acknowledges the FIN. Since a FIN and an ACK are required in each direction, four segments are normally required. We use the qualifier "normally" because in some scenarios, the FIN in Step 1 is sent with data. Also, the segments in Steps 2 and 3 are both from the end performing the passive close and could be combined into one segment. Prepared by : Mrs. M.Nirmala / AP / MCA Page : 43