Saturday, September 26, 2020

Message Queue - message types reception

Consider this the extension of the previous post on Message Queue.  We will see how we can retrieve messages of different types.

Write2.c

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>

struct msgbuf {
	long mtype;
	char mtext[20];
} mymsg;

int main()
{
	key_t key;
	int msgid;
	
	key=ftok("dummy.txt",65);
	msgid = msgget(key,0666 | IPC_CREAT);
	printf("Key - %x ;MessageId - %d \n",key,msgid);

	mymsg.mtype = 1;	
	strcpy(mymsg.mtext,"its my world 1 \0");
	msgsnd(msgid,&mymsg,strlen(mymsg.mtext),0);	
	printf("Sent Type: %d Data: %s\n",mymsg.mtype,mymsg.mtext);

	mymsg.mtype = 2;	
	strcpy(mymsg.mtext,"its my world 2 \0");
	msgsnd(msgid,&mymsg,strlen(mymsg.mtext),0);	
	printf("Sent Type: %d Data: %s\n",mymsg.mtype,mymsg.mtext);
	
	mymsg.mtype = 3;	
	strcpy(mymsg.mtext,"its my world 3 \0");
	msgsnd(msgid,&mymsg,strlen(mymsg.mtext),0);	
	printf("Sent Type: %d Data: %s\n",mymsg.mtype,mymsg.mtext);
	
	mymsg.mtype = 4;	
	strcpy(mymsg.mtext,"its my world 4 \0");
	msgsnd(msgid,&mymsg,strlen(mymsg.mtext),0);	
	printf("Sent Type: %d Data: %s\n",mymsg.mtype,mymsg.mtext);
	
	return 0;
}

We have created message queue, and passing 4 messages of different types 1,2,3 and 4.

Read2.c

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include<stdio.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <errno.h>

struct msgbuf {
	long mtype;
	char mtext[20];
} mymsg;

int main(int argc, char *argv[])
{
	key_t key;
	int msgid;
	int type;
	type = atoi(argv[1]);

	key=ftok("dummy.txt",65);
	msgid=msgget(key,0644);
	printf("Key - %x ;MessageId - %d \n",key,msgid);
	
	while (1)
	{			
		msgrcv(msgid,&mymsg,sizeof(mymsg),type,IPC_NOWAIT);
		if (errno == ENOMSG) {
			printf("No messages\n");
			break;
		} else {
			printf("Received Data,%s\n",mymsg.mtext);
			printf("Received Data type, %d\n\n",mymsg.mtype);
		}
	}
	return 0;
}
  • Line 16 - Passing the 'message type' as command line argument
  • Line 22 - We run the while loop to receive all the messages available with the mentioned message type.
  • Line 24 - The last argument IPC_NOWAIT is used to instruct 'msgrcv' to return immediately if there is no message present in queue.  'errno' will be set with 'ENOMSG' when this happens.

Demonstration

For different values of msgtypes, the msgrcv behave accordingly

Positive: Picks the first message in the queue corresponding to this type

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
[root@msgq]# ./write2
Key - 41014da0 ;MessageId - 327680
Sent Type: 1 Data: its my world 1
Sent Type: 2 Data: its my world 2
Sent Type: 3 Data: its my world 3
Sent Type: 4 Data: its my world 4

[root@msgq]# ./read2 3
Key - 41014da0 ;MessageId - 327680
Received Data,its my world 3
Received Data type, 3

No messages

[root@msgq]# ./read2 3
Key - 41014da0 ;MessageId - 327680
No messages

[root@msgq]# ./read2 2
Key - 41014da0 ;MessageId - 327680
Received Data,its my world 2
Received Data type, 2

No messages

[root@msgq]# ./read2 4
Key - 41014da0 ;MessageId - 327680
Received Data,its my world 4
Received Data type, 4

No messages
  • Line 1-6 - Populating 4 types of messages in the message queue
  • Line 8 - Receive message type 3. Successful
  • Line 15 - Receive message type 3.  No message present
  • Line 19 - Receive message type 2. Successful
  • Line 26 - Receive message type 4. Successful
Lets clear the queue using 'ipcrm -a' and proceed to next type

Zero: Reads the first receive message in the whole message queue, irrespective of the type

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
[root@msgq]# ./write2
Key - 41014da0 ;MessageId - 360448
Sent Type: 1 Data: its my world 1
Sent Type: 2 Data: its my world 2
Sent Type: 3 Data: its my world 3
Sent Type: 4 Data: its my world 4

[root@msgq]# ./read2 0
Key - 41014da0 ;MessageId - 360448
Received Data,its my world 1
Received Data type, 1

Received Data,its my world 2
Received Data type, 2

Received Data,its my world 3
Received Data type, 3

Received Data,its my world 4
Received Data type, 4

No messages
  • Line 1-6 - Populating messages of different type
  • Line 8 - Passing the value of type 0
  • Line 10-20 - Receiving the messages 1, 2, 3, 4 in the same order as in lines 1-6
Negative: Receives all the messages belonging to the types less than the absolute value of the number passed in fifo order

 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
[root@msgq]# ./write2
Key - 41014da0 ;MessageId - 360448
Sent Type: 1 Data: its my world 1
Sent Type: 2 Data: its my world 2
Sent Type: 3 Data: its my world 3
Sent Type: 4 Data: its my world 4

[root@msgq]# ./read2 -2
Key - 41014da0 ;MessageId - 360448
Received Data,its my world 1
Received Data type, 1

Received Data,its my world 2
Received Data type, 2

No messages

[root@msgq]# ipcrm -a

[root@msgq]# ./write2
Key - 41014da0 ;MessageId - 393216
Sent Type: 1 Data: its my world 1
Sent Type: 2 Data: its my world 2
Sent Type: 3 Data: its my world 3
Sent Type: 4 Data: its my world 4

[root@msgq]# ./read2 -3
Key - 41014da0 ;MessageId - 393216
Received Data,its my world 1
Received Data type, 1

Received Data,its my world 2
Received Data type, 2

Received Data,its my world 3
Received Data type, 3

No messages
  • Line 1-6 - Populating messages of different types
  • Line 8 - Receiving the type '-2', meaning retrieve all messages less than type 2 in FIFO order
  • Line 18 - Clearing the message queue
  • Line 20-25 - Populating messages of different types
  • Line 27 - Receiving the type '-3', meaning retrieve all messages less than type 3 in  FIFO order

Message Queue - Basic

 Today, we see the message queues.  The advantages is available everywhere on the internet.  Summary is one process can communicate with another process.  Better picture is available in this link:

https://www.tutorialspoint.com/inter_process_communication/images/multiple_message_queue.jpg

Here we have two programs 'write.c' and 'read1.c'.  Write.c will write a message into message queue of type 1.  It will be taken by read1.c.

Write.c

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>

struct msgbuf {
	long mtype;
	char mtext[20];
}mymsg;

int main()
{
	key_t key;
	int msgid;
	
	key=ftok("dummy.txt",65);
	msgid = msgget(key,0666 | IPC_CREAT);
	printf("Key - %x ;MessageId - %d \n",key,msgid);

	mymsg.mtype = 1;	
	strcpy(mymsg.mtext,"its my world 1 \0");
	
	msgsnd(msgid,&mymsg,strlen(mymsg.mtext),0);	
	
	printf("Sent Data\n");

	return 0;
}
  • Line 6 - This is the typical template of message used in message queues.  First long will be message type.  Rest of it is message.  It can be further defined as any data type.
  • Line 16 - We need a unique key for creating a msgq.  We use 'ftok' command that takes in two arguments. File that the process can read and any character.  Retriever process should also use the same arguments and create the key.
  • Line 17 - 'msgget' creates a message queue(because we use IPC_CREAT mask) with key from 'ftok' and some permissions.  It gives message queue identifier, just like file identifier to communicate
  • Line 20-21 - Populate the message with message type '1' and the text.
  • Line 23 - 'msgsnd' to send the message to queue to let others take it.  Arguments will be message identifier, Address of message, size of message(excluding the 'long' type)

Read1.c

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include<stdio.h>
#include <sys/ipc.h>
#include <sys/msg.h>

struct msgbuf {
	long mtype;
	char mtext[20];
} mymsg;

int main()
{
	key_t key;
	int msgid;
	
	key=ftok("dummy.txt",65);
	msgid=msgget(key,0644);
	printf("Key - %x ;MessageId - %d \n",key,msgid);
	
	msgrcv(msgid,&mymsg,sizeof(mymsg),1,0);
	printf("Received Data,%s\n",mymsg.mtext);
	printf("Received Data type, %d\n",mymsg.mtype);
	
	msgctl(msgid,IPC_RMID,NULL);
	return 0;
}
  • Line 5-8 - Same as in write.c
  • Line 15 - To 'ftok' we pass the same arguments as in write.c.
  • Line 16 - 'msgget' to get message identifier.  We do not use IPC_CREAT as message queue already created by write.c
  • Line 19 - 'msgrcv' to read the message into mymsg.  4th argument is message type that we wish to read.
  • Line 23 - 'msgctl' to delete the memory of message queue.

Demonstrate

Lets take the programs for a ride

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
[root@msgq]# gcc write.c -o write
[root@msgq]# ./write
Key - 41014da0 ;MessageId - 327680
Sent Data
[root@msgq]# ipcs

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages
0x41014da0 327680     root       666        15           1

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status
0x00000000 131072     root       600        393216     2          dest
0x00000000 262146     root       600        524288     2          dest

------ Semaphore Arrays --------
key        semid      owner      perms      nsems

[root@svtap01end1 msgq]#

We have sent the message to message queue. 'ipcs' is the linux command that shows the details of message queue. 'ipcrm -a' is one of the commands that will delete all the details of the shared memory listed here.  We haven't used it though.  In another terminal or the same terminal lets run read1.c.

1
2
3
4
5
[root@msgq]# gcc read1.c -o read1
[root@msgq]# ./read1
Key - 41014da0 ;MessageId - 294912
Received Data,its my world 1
Received Data type, 1

You see that the message 'its my world 1' is received by read1.c

Tuesday, September 8, 2020

Native VLAN - Demo

 Usually, for a multi-VLAN network the PCs are connected to 'access' ports of the switch.  Instead of 'access' port, we use the combination of 'trunk' port and 'native-vlan'.

Trunk port - Port in switch where VLAN-tagged packets will pass through.
Native VLAN - Packets passing through the port that belongs to Native VLAN Id will have no-VLAN tagging.

Steps usually will be

  1. Create VLANs in the switch that will be used.(vlan x)
  2. Assign vlan id as Native VLAN to the port(switchport trunk native vlan x)
  3. Allow the same vlan id in the port(switchport trunk allowed vlan x)
  4. If there is a switch on the other side of the link, it should also have same native vlan id.  Else port will be blocked by STP.
We use the following topology:


VL20-1 and VL20-2 are separated by series of switches.  VL20-1, connected to Trunk port having native vlan 20.  VL20-2 is connected to access port of vlan 20.

VL30-1 and VL30-2, belonging to VLAN 30, separted by couple of switches.  VL30-1, connected to Trunk port having native vlan 30.  VL30-2 is connected to access port of vlan 30.

Lets go through the configurations of switches one by one. Starting with 

Switch4

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
Switch#conf t
Enter configuration commands, one per line.  End with CNTL/Z.
Switch(config)#vlan 20
Switch(config-vlan)#ex
Switch(config)#vlan 30
Switch(config-vlan)#ex
Switch(config)#int fa0/2
Switch(config-if)#switchport mode access 
Switch(config-if)#switchport access vlan 20
Switch(config-if)#no shut
Switch(config-if)#ex
Switch(config)#int fa0/1
Switch(config-if)#switchport mode access
Switch(config-if)#switchport access vlan 30
Switch(config-if)#ex
Switch(config)#int fa0/3
Switch(config-if)#switchport trunk encapsulation dot1q
Switch(config-if)#switchport mode trunk
Switch(config-if)#switchport trunk allowed vlan 20,30
  • Creating VLAN (Lines 3 to 6)
  • Making Ports fa0/2 and fa0/1 as access ports to vlan 20 and 30 respectively(Lines 8 to 15)
  • Making Port fa0/3 as Trunk port allowing vlans 20 and 30(Lines 16 to 19)

Switch6

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
Switch(config)#vlan 20
Switch(config-vlan)#ex
Switch(config)#vlan 30
Switch(config-vlan)#ex
Switch(config)#int fa0/2
Switch(config-if)#switchport trunk encapsulation dot1q
Switch(config-if)#switchport mode trunk
Switch(config-if)#switchport trunk allowed vlan 20
Switch(config-if)#ex
Switch(config)#int fa0/1
Switch(config-if)#switchport trunk encapsulation dot1q
Switch(config-if)#switchport mode trunk
Switch(config-if)#switchport trunk allowed vlan 20,30
Switch(config-if)#ex
Switch(config)#int fa0/3
Switch(config-if)#switchport trunk encapsulation dot1q
Switch(config-if)#switchport mode trunk
Switch(config-if)#switchport trunk native vlan 30
Switch(config-if)#switchport trunk allowed vlan 30
  • Create VLANs 20 and 30, as both are used in this switch(Lines 1 to 4)
  • Make fa0/2 as Trunk to pass vlan 20 from Switch5(lines 5 to 9)
  • Make fa0/1 as Trunk to pass vlans 20 and 30 to and from Switch4 (Lines 10 to 14)
  • Make fa0/3 as Trunk, to allow vlan30 as Native vlan(equal to access port) (Lines 15 to 19)

Switch5

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
Switch#conf t
Switch(config)#vlan 20
Switch(config-vlan)#ex
Switch(config)#int fa0/3
Switch(config-if)#switchport trunk encapsulation dot1q
Switch(config-if)#switchport mode trunk
Switch(config-if)#switchport trunk allowed vlan 20
Switch(config-if)#ex
Switch(config)#int fa0/1
Switch(config-if)#switchport trunk encapsulation dot1q
Switch(config-if)#switchport mode trunk
Switch(config-if)#switchport trunk allowed vlan 20
Switch(config-if)#switchport trunk native vlan 20
Switch(config-if)#ex
  • Create VLAN 20, as it is the only VLAN used (Lines 2 to 3)
  • Make fa0/3 as Trunk to allow vlan 20 to other switches(Lines 4 to 8)
  • Make fa0/1 as Trunk to allow vlan 20 as Native vlan id(equal to access port) (Lines 9 to 14)

Testing

  • Configured VL20-1 and VL20-2 with IP address as 20.0.0.20/8 and 20.0.0.2/8 respectively.  Ping is successful.
  • Configured VL30-1 and VL30-2 with IP addresses 30.0.0.30/8 and 30.0.0.3/8 respectively.  Ping is successful

Sunday, August 16, 2020

Spanning Tree - Tree Creation

Today, we pick a network with switches and see step by step how the final tree is formed.  Steps will be 

  1. Selecting Root Bridge in the network
  2. Selecting Root Port for every switch
  3. Selecting Designated Port for every segment/link
  4. Selecting Alternate Ports 
  5. Forwarding/Blocking/Tree

Topology

Selecting Root Bridge

We select the Root Bridge that has least (priority.mac address) value.  As default priority is 32769 for all switches.  Now the switch with least mac address, i.e. Switch A having  0001.439C.7B5E is selected as Root Bridge.


Selecting Root Ports in Every Switch

One of its connected port will be elected as Root Port in a switch. The selecting process will be:
  • Lowest Root path cost
  • Lowest Sender Bridge ID
  • Lowest Sender Port Priority Value
  • Lowest port priority value within the switch
Cost of traversing a link depends on the type of physical link used:
  • Fast Ethernet 100Mbps costs 19
  • Gigabit Ethernet 1000Mbps costs 4
When calculating the cost, we calculate both at the start and the end.  Start of the link incurs zero cost. At the end of the link the cost depends on the physical link.

Root Port of Switch B

We can reach Switch B from Root Bridge through 
  • A.Fa0/1 - B.Fa0/1
  • A.Fa0/2 - C.Fa0/2 - C.Ga0/1 - B.Ga0/1
  • A.Fa0/3 - C.Fa0/3 - C.Ga0/1 - B.Ga0/1
  • A.Fa0/2 - C.Fa0/2 - C.Fa0/4 - D.Fa0/4 - D.Fa0/3 - B.Fa0/3
  • A.Fa0/3 - C.Fa0/3 - C.Fa0/4 - D.Fa0/4 - D.Fa0/3 - B.Fa0/3 
Have a look at the diagram, we will traverse the path "A.Fa0/3 - C.Fa0/3 - C.Ga0/1 - B.Ga0/1".  From A.Fa0/3, as the distance is not covered yet, path cost will be 0.  When it reaches C.Fa0/3, as it travelled through fast ethernet link, the cost is 19.  At CGa0/1, as it only changed the port within the switch, no additional cost will be incurred.  So, at Ga0/1, cost remains unchanged at 19.  When reaching B.Ga0/1, we would have crossed a Gigabit Ethernet Link that costs '4'.  So, the adding 4 to the cost, the root path cost at B.Ga0/1 will be 23.

Similary, we mark the costs at all the links and choose B.Fa0/1 as Root Port for switch B.

Root Port of Switch C

Root Port of Switch D


Selecting Designated Port for every link/segment

Every link here has 2 points.  There may be cases where a hub will be in between and segment will comprise of more than 2 points.  Selection process
  • Lowest Root path cost
  • Lowest Bridge ID
  • Lowest Port Priority Value
Here is the diagram with all the root path cost calculated for all segments/links.  For every link, we selected Designated port with least root path cost.  One exception, B.Ga0/1 - C.Ga0/1 has equal root path cost.  As Bridge ID of switch B is lesser, B.Ga0/1 gets chosen as Designated port.  Also, observe that all the ports of Root Bridge will be selected as Designated Ports.

Selecting Alternate Port

Any port that is not Root or Designated will become Alternate Port.

Forwarding/Blocking/Tree

All Alternate Ports will be blocked.  All Root Ports and Designated Ports will be in forwarding State.  
For a link to be active, both ends has to be in forwarding state.  If we trace that, final tree will be the result.


Remember, Blocking ports only mean that switch will not pass any data towards that, but BPDUs will be sent and received.  This is because if there is any change in topology then the calculation will happen again, and may be one of the blocking ports comes to forward state or vice-versa.

In Cisco Packet Tracer, we make the setup observe the interface and role columns.  It will match with the tree diagram.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
switch-A#show spanning-tree 
VLAN0001
  Spanning tree enabled protocol ieee
  Root ID    Priority    32769
             Address     0001.439C.7B5E
             This bridge is the root
             Hello Time  2 sec  Max Age 20 sec  Forward Delay 15 sec

  Bridge ID  Priority    32769  (priority 32768 sys-id-ext 1)
             Address     0001.439C.7B5E
             Hello Time  2 sec  Max Age 20 sec  Forward Delay 15 sec
             Aging Time  20

Interface        Role Sts Cost      Prio.Nbr Type
---------------- ---- --- --------- -------- --------------------------------
Fa0/3            Desg FWD 19        128.3    P2p
Fa0/1            Desg FWD 19        128.1    P2p
Fa0/2            Desg FWD 19        128.2    P2p

switch-B#show spanning-tree 
VLAN0001
  Spanning tree enabled protocol ieee
  Root ID    Priority    32769
             Address     0001.439C.7B5E
             Cost        19
             Port        1(FastEthernet0/1)
             Hello Time  2 sec  Max Age 20 sec  Forward Delay 15 sec

  Bridge ID  Priority    32769  (priority 32768 sys-id-ext 1)
             Address     000B.BE33.284A
             Hello Time  2 sec  Max Age 20 sec  Forward Delay 15 sec
             Aging Time  20

Interface        Role Sts Cost      Prio.Nbr Type
---------------- ---- --- --------- -------- --------------------------------
Fa0/3            Desg FWD 19        128.3    P2p
Fa0/1            Root FWD 19        128.1    P2p
Gi0/1            Desg FWD 4         128.25   P2p


switch-C#show spanning-tree 
VLAN0001
  Spanning tree enabled protocol ieee
  Root ID    Priority    32769
             Address     0001.439C.7B5E
             Cost        19
             Port        2(FastEthernet0/2)
             Hello Time  2 sec  Max Age 20 sec  Forward Delay 15 sec

  Bridge ID  Priority    32769  (priority 32768 sys-id-ext 1)
             Address     00D0.58CE.8C09
             Hello Time  2 sec  Max Age 20 sec  Forward Delay 15 sec
             Aging Time  20

Interface        Role Sts Cost      Prio.Nbr Type
---------------- ---- --- --------- -------- --------------------------------
Fa0/4            Desg FWD 19        128.4    P2p
Fa0/2            Root FWD 19        128.2    P2p
Fa0/3            Altn BLK 19        128.3    P2p
Gi0/1            Altn BLK 4         128.25   P2p

switch-D#show spanning-tree 
VLAN0001
  Spanning tree enabled protocol ieee
  Root ID    Priority    32769
             Address     0001.439C.7B5E
             Cost        38
             Port        3(FastEthernet0/3)
             Hello Time  2 sec  Max Age 20 sec  Forward Delay 15 sec

  Bridge ID  Priority    32769  (priority 32768 sys-id-ext 1)
             Address     0001.C717.DA66
             Hello Time  2 sec  Max Age 20 sec  Forward Delay 15 sec
             Aging Time  20

Interface        Role Sts Cost      Prio.Nbr Type
---------------- ---- --- --------- -------- --------------------------------
Fa0/3            Root FWD 19        128.3    P2p
Fa0/4            Altn BLK 19        128.4    P2p

Saturday, August 15, 2020

FIFO - file to file transfer

 Today, we try to send a message through FIFO file from one program to another program.

(write)file_send|>>----------------file_fifo.txt----------------------->>|file_recv(read)

Sender Script

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<fcntl.h>

int main()
{
	char fil[15]="file_fifo.txt";
	
	char wrch[20];
	int siz=20;

	memset(wrch,'\0',siz);
	strcpy(wrch,"hello world");
	
	int fd = open(fil,O_WRONLY);
	int cw=write(fd,wrch,siz);
	printf("Sender: write -%s- of %d chars to %s\n",wrch,cw,fil);
	
	return 0;
}

Lets breakdown the script 

  1. Line 8: Take the fifo file into a string
  2. Line 10-14: Initialize the string with "hello world"
  3. Line 16: Open the file in write only mode
  4. Line 17: Send the text

Receiver Script

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>

int main()
{
	
	char fil[15]="file_fifo.txt";
	mkfifo(fil,0666);
	
	char rdch[20];
	int siz=20;

	int fd = open(fil,O_RDONLY);
	printf("Receiver: Waiting for message from Sender\n");
	int rd=read(fd,rdch,siz);
	printf("Receiver: read -%s- of %d chars to %s\n",rdch,rd,fil);
	
	return 0;
}

Lets breakdown the script
  1. Line 8-9: Create a fifo file using mkfifo function. As receiver is to the executed before sender, we have to create fifo file here.
  2. Line 11-12: Initialize character array to read the message from Sender program.
  3. Line 14: Open the fifo file in read only mode
  4. Line 16: Read the message from sender into rdch string

Execution

Start the receiver first.  It will be blocked waiting for message from Sender.
1
2
3
# gcc fifo-recv.c -o fifo-recv
# ./fifo-recv
Receiver: Waiting for message from Sender

Start the sender in another terminal.  It will send the message.
1
2
3
# gcc fifo-send.c -o fifo-send
# ./fifo-send
Sender: write -hello world- of 20 chars to file_fifo.txt

Verify in the receiver terminal, receive program would have received the message.
1
2
3
4
# gcc fifo-recv.c -o fifo-recv
# ./fifo-recv
Receiver: Waiting for message from Sender
Receiver: read -hello world- of 20 chars to file_fifo.txt

FIFO - Basic

Today, we replicate whatever we did on Pipes-Basic using FiFo.  It is a pipe, but a name assigned to it.  If I have a pipe, I can access only within the program, forked program and its decendants.  I have to call it using integer array.

If I have a fifo, I can access it just like any other file.  I can pass the information from one program to another.  Now, we pass information from parent to child and then from child to parent using 2 FIFO files.

(read)child|<<----------------file_p2c.txt-----------------------<<|parent(write)

(write)parent|>>----------------file_c2p.txt----------------------->>|child(read)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<fcntl.h>

int main()
{
	char p2c[15]="file_p2c.txt";
	char c2p[15]="file_c2p.txt";
	mkfifo(p2c,0666);
	mkfifo(c2p,0666);
	
	char wrch[20],rdch[20];
	int siz=20;

	memset(wrch,'\0',siz);
	strcpy(wrch,"hello world");
	
	pid_t id=fork();
	if(id != 0)
	{
		int wfd = open(p2c,O_WRONLY);
		int cw=write(wfd,wrch,siz);
		printf("write -%s- of %d chars to %s\n",wrch,cw,p2c);
		
		int rfd = open(c2p,O_RDONLY);
		int cr=read(rfd,rdch,siz);
		printf("read -%s- of %d chars from %s\n",rdch,cr,c2p);
		
		wait(id,NULL,0);
	} else {
		int rfd = open(p2c,O_RDONLY);
		int cr=read(rfd,rdch,siz);
		printf("Read -%s- of %d chars from %s\n",rdch,cr,p2c);
		
		printf("Sleeping for 5 seconds\n");
		sleep(5);
		
		int wfd = open(c2p,O_WRONLY);
		int cw=write(wfd,wrch,siz);
		printf("write -%s- of %d chars to %s\n",wrch,cw,c2p);
	}
	return 0;
}

Lets get into breaking down the code: 

Creating FiFo files (#9 to #12)
Use mkfifo procedure to create 2 fifo files with 666 permission(read and write and not execute for all)

Initializing string buffers (#14 to #18)
Create 2 read and write strings.  Initialize write string with "hello world"

Fork a child (#20)

Opening FiFO files;parent to child (#23, #33)
Parent opens the file_p2c.txt in write mode, child opens file_p2c.txt in read mode

Send traffic; parent to child(#24,#25,#34,#35)
Parent writes the wrch string and child reads into rdch string.

Sleep for 5 seconds(#38)

Opening FiFO files; child to parent(#27, #40)
Child opens the file_c2p.txt in write mode, parent opens file_c2p.txt in read mode

Send traffic; child to parent(#28,#29,#41,#42)
Child writes the wrch string and parent reads into rdch string.

Harvest Time

When this program is run

1
2
3
4
5
6
# ./a.out
write -hello world- of 20 chars to file_p2c.txt
Read -hello world- of 20 chars from file_p2c.txt
Sleeping for 5 seconds
write -hello world- of 20 chars to file_c2p.txt
read -hello world- of 20 chars from file_c2p.txt

Observe that first 2 lines, we transfer data from parent to child.  Sleep for 5 seconds and then transfer the same string from child to parent.

Wednesday, August 12, 2020

Pipes - Basic

 Today, we demonstrate pipe using a simple example.  It is a way to transfer data between different processes created by fork and its descendants.  It is a unidirectional way of communication.  It is created and handled by kernel and will be controlled by our program.

(read)fdx[0]|<<----------------FDX-----------------------<<|fdx[1](write)

(write)fdy[0]|>>----------------FDY----------------------->>|fdy[1](read)

In the program, we create two pipes FDX and FDY.  We send a string "hello world" from parent to child.  Sleep for 5 seconds.  Send the same string back from child to parent.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>

int main()
{
	int fdx[2];
	int fdy[2];
	char s[20];
	int siz,cw,cr;
	
	siz=sizeof(s);
	memset(s,'\0',siz);
	strcpy(s,"hello world");
	
	pipe(fdx);
	pipe(fdy);
	
	pid_t fk = fork();
	if(fk != 0) 
	{
		cw = write(fdx[1],s,siz);
		fprintf(stdout,"PIPE FDX: sent %d chars\n",cw);
		
		cr = read(fdy[0],s,siz);
		fprintf(stdout,"PIPE FDY: received -%s- of %d chars\n",s,cr);
		wait(fk,NULL,0);
		
	} else {
		cr = read(fdx[0],s,siz);
		fprintf(stdout,"PIPE FDX: received -%s- of %d chars\n",s,cr);
		
		fprintf(stdout,"Sleeping for 5 seconds\n");
		sleep (5);
		
		cw=write(fdy[1],s,siz);
		fprintf(stdout,"PIPE FDY: sent the received fdx string -%s- of %d chars\n",s,cw);
		
	}
	return (0);
}

Lets skip the library declarations.  Breaking down the code.

Preparing String(#13 to #15)

Create string of size 20.  Fill it with all NULLs.  Initialize with "hello world".

Creating Pipes(#17 and #18)

Creating two pipes fdx and fdy

Forking(#20)

Fork the process

Send Traffic from Parent to Child(#23, #24, #31, #32)

Pass string 's' to write function with (write end of the pipe)fdx[1] and read it in the child with (read end of the pipe)fdx[0].

After sleeping for 5 seconds.

Same string is passed to (write end of pipe)fdy[1] at the child and read in the parent using read function with (read end of the pipe)fdy[0].

Conclusion(#28)

Use wait function to pause the parent till child ends.

Harvesting

When executed the shell shows like this

1
2
3
4
5
6
# ./a.out
PIPE FDX: sent 20 chars
PIPE FDX: received -hello world- of 20 chars
Sleeping for 5 seconds
PIPE FDY: sent the received fdx string -hello world- of 20 chars
PIPE FDY: received -hello world- of 20 chars