Showing posts with label cbasic. Show all posts
Showing posts with label cbasic. Show all posts

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

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

Monday, April 27, 2020

Simple web server program

Today we discuss simple web server program.  It accepts only one connection from a web client.  Reads the HTTP messages from the client.  Sends the HTTP message to the client.

  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
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101

#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int main()
{
 int servsockfd,clisockfd;
 struct sockaddr_in servaddr, cliaddr;
 
 // Create a TCP Socket
 servsockfd=socket(AF_INET,SOCK_STREAM,0);
 if (servsockfd == -1)
 {
  printf("socket creation failed\n");
  exit(0);
 }
 
 //Populate IP Address and Port Number
 servaddr.sin_family=AF_INET;
 servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
 servaddr.sin_port=htons(80);
 
 //Bind the socket to the Structure sockaddr_in containing IP address and Port number 
 if((bind(servsockfd,(struct sockaddr *)&servaddr, sizeof(servaddr))) != 0)
 {
  printf("socket bind failed with %d\n",errno);
  exit(0);
 }
 
 //Start the server and keep listening for connections
 if((listen(servsockfd,5)) != 0)
 {
  printf("Listen failed\n");
  exit(0);
 } else
  printf("Waiting for client to connect...\n");
 
 //Accept the client connection
 int cliaddr_len=sizeof(cliaddr);
 clisockfd = accept(servsockfd,(struct sockaddr *)&cliaddr, &cliaddr_len);
 
 if(clisockfd <0)
 {
  printf("server accept failed\n");
  exit(0);
 } else
  printf("Server accepted client\n");

 //Store and display the client IP address and Port details
 char *client_ipaddr = inet_ntoa(cliaddr.sin_addr);
 int client_port=ntohs(cliaddr.sin_port);
 char client_port_ascii[10];
 sprintf(client_port_ascii,"%d",client_port);
 printf("Client IP = %s\nClient Port Number=%d\n",client_ipaddr,client_port);
  
 char recvline[60];
 int i,readlen,linecounter=1;
 
 // Read the characters in batches of 60
 while ((readlen=read(clisockfd,recvline,60)) >0)
 {
  printf("%d  -",linecounter,recvline);
  
  //Print the HTTP messages from the client in batches of 60 characters
  for (i=0; i<readlen; i++) { 
   if (recvline[i] == '\n') {
    printf("\\n");
   } else if (recvline[i] == '\r') {
    printf("\\r");
   } else {
    printf("%c",recvline[i]);
   }
  }
  linecounter++;
  printf("\n");
  
  //Break the loop if it sees \r\n at the end of messagae
  if(recvline[readlen-1] == '\n' && recvline[readlen-2] == '\r')
  {
   break;
  }
 }
 
 //Make a HTTP Message to send to client
 char msg[80];
 strcat(msg,"HTTP/1.1 200 OK\nContent-Type: text/plain\n\nHello world!\n");
 strcat(msg,"Your IP Address:");
 strcat(msg,client_ipaddr);
 strcat(msg,"\nYour Port Number:");
 strcat(msg,client_port_ascii);
 
 //Send the message to client
 write(clisockfd,msg,strlen(msg));
 
 //Close the connections
 close(clisockfd);
 close(servsockfd);
}

Listening to the HTTP Port

Line 13 - Create a TCP Socket Stream
Line 23 - Fill in the details of IP Address on which server has to run and also port number
Line 27 - Bind the socket and the structure (Observe that 2nd argument is typecasted as 'struct sockaddr  *' for the pointer of 'struct sockaddr_in')
Line 34 - Start listening for connections

Accepting the client

Line 43 - Accept the connection. (Observe that 2nd argument is type casted as 'struct sockaddr  *' for the pointer of 'struct sockaddr_in'.  Also the 3rd argument is pointer to the integer of size, not integer)
Line 43 - Return value of Accept function is client socket ID.  This is the ID that we use for reading and writing from that particular client.
Line 53 - Extract IP Address and Port number from the struct sockaddr cliaddr.

Structure of sockaddr_in will be like

#include <netinet/in.h>

struct sockaddr_in {
    short            sin_family;   // e.g. AF_INET
    unsigned short   sin_port;     // e.g. htons(3490)
    struct in_addr   sin_addr;     // see struct in_addr, below
    char             sin_zero[8];  // zero this if you want to
};

struct in_addr {
    unsigned long s_addr;  // load with inet_aton()
};

Read Client Message

When a browser is opened with the IP Address of machine, it sends out HTTP Get message.
Line 64 - While loop that displays the incoming message from client in batches of 60 characters
And breaking the loop whenever it seen \r\n at the end of message.  We are hoping that \r and \n doesnt come in different batches.  The probability of occurrence is less

Write Client Message

Line 89 - Start composing Hello Message along with its IP Address and Client Port number
Line 97 - 'Write' the message.

Close Sockets

Line 99 - Close the client socket and also server socket.

Compiling and Executing

# gcc -o webserver webserver.c
# ./webserver
Waiting for client to connect...
Client IP = 10.230.45.13
Client Port Number=63836
Server accepted client
1  -GET / HTTP/1.1\r\nHost: 10.123.8.110\r\nConnection: keep-alive\r\n

This is the execution of the program.  Means at the server end.  We use curl command line web client, for simplicity.  So, the GET message is very simple.

Web Client View

Use the curl command and the IP address.  We can see the Hello Message, IP Address and Port Numbers as well.


# curl http://10.123.8.110/
Hello world!
Your IP Address:10.123.8.231
Your Port Number:50416

Instead of curl, we can issue http://10.123.8.110 from chrome or firefox.  The messages will be seen on browser.

Sunday, April 26, 2020

Simple Web Client Program

We are going to attempt a simple web client program.  We request a webpage from "yahoo.com".  Get the IP Address using ping command.  It is "98.137.246.7".  Use it in the program.

1
2
3
4
5
[root@svtap01end1 work]# ping yahoo.com
PING yahoo.com (98.137.246.7) 56(84) bytes of data.
64 bytes from media-router-fp1.prod1.media.vip.gq1.yahoo.com (98.137.246.7): icmp_seq=1 ttl=51 time=265 ms
64 bytes from media-router-fp1.prod1.media.vip.gq1.yahoo.com (98.137.246.7): icmp_seq=2 ttl=51 time=265 ms
64 bytes from media-router-fp1.prod1.media.vip.gq1.yahoo.com (98.137.246.7): icmp_seq=3 ttl=51 time=265 ms

 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
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>

int main(int argc, char const *argv[])
{
 int sock;

 // Create a socket
 if ((sock = socket(AF_INET,SOCK_STREAM,0))<0) {
  printf("socket creation error\n");
  return -1;
 }

 
 struct sockaddr_in serv_addr;
 serv_addr.sin_family=AF_INET;
 serv_addr.sin_port=htons(80);
 
 // Convert IP Address in binary format
 if(inet_pton(AF_INET,"98.137.246.7",&serv_addr.sin_addr) <= 0) {
  printf("Address conversion to binary\n");
  return -1;
 }

 // Connect client socket to the web server
 if(connect(sock,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) <0)
 {
  printf("Connection Error\n");
  return -1;
 }

 // Request for a web page by sending HTTP Get Packet
 if(write(sock, "GET / HTTP/1.1\r\n\r\n",strlen("GET / HTTP/1.1\r\n\r\n")) != strlen("GET / HTTP/1.1\r\n\r\n"))
 {
  printf("Error write\n");
  return -1;
 }

 char recvline[80];
 memset(recvline,0,80); //Fill all 80 characters to 0
 int i,readlen,linecounter=1;
 
 // Read the characters in batches of 80
 while ((readlen=read(sock,recvline,80)) >0)
 {
  printf("%d  -",linecounter);
  
  //Carriage Return and New Line Character has to be displayed as it is
  for (i=0; i<readlen; i++) { 
   if (recvline[i] == '\n') {
    printf("\\n");
   } else if (recvline[i] == '\r') {
     printf("\\r");
   } else {
    printf("%c",recvline[i]);
   }
  }
  linecounter++;
  printf("\n");
 }

 //Close the socket
 close(sock);
 printf("Successful creation");
 return 0;
}

Regular steps involved in creating a socket:

Line 11 - Creating a socket.  Stream Socket as HTTP involves TCP.
Line 22 - IP Address to be copied in the binary format
Line 28 - Connect to yahoo server with the port 80

Retrieving Data will be:

Line 35 - Send a HTTP Get packet to retrieve a web page
Line 46 - Loop to retrieve characters in the batches of 80
Line 52 - Carriage Return and New Line Characters has to be displayed as \r and \n

Close the connection:

Line 65 - Close the socket

When executed, Line Batch number and the Contents are displayed as


# gcc -o webclient webclient.c
# ./webclient
1  -HTTP/1.1 400 Host Header Required\r\nDate: Sun, 26 Apr 2020 16:48:32 GMT\r\nConnecti
2  -on: close\r\nServer: ATS\r\nCache-Control: no-store\r\nContent-Type: text/html\r\nConten
3  -t-Language: en\r\nX-Frame-Options: SAMEORIGIN\r\nContent-Length: 4383\r\n\r\n<!DOCTYPE h
4  -tml>\n<html lang="en-us">\n  <head>\n    <meta http-equiv="content-type" content="t
5  -ext/html; charset=UTF-8">\n    <meta charset="utf-8">\n    <title>Yahoo</title>\n
6  -  <meta name="viewport" content="width=device-width,initial-scale=1,minimal-ui">
7  -\n    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">\n    <style>\n
8  -      html {\n          height: 100%;\n      }\n      body {\n          background:
9  -#fafafc url(https://s.yimg.com/nn/img/sad-panda-201402200631.png) 50% 50%;\n
10  -     background-size: cover;\n          height: 100%;\n          text-align: cente
11  -r;\n          font: 300 18px "helvetica neue", helvetica, verdana, tahoma, arial,
12  - sans-serif;\n          margin: 0;\n      }\n      table {\n          height: 100%;\n
13  -          width: 100%;\n          table-layout: fixed;\n          border-collapse:
14  - collapse;\n          border-spacing: 0;\n          border: none;\n      }\n      h1
15  - {\n          font-size: 42px;\n          font-weight: 400;\n          color: #4000
16  -90;\n      }\n      p {\n          color: #1A1A1A;\n      }\n      #message-1 {\n
17  -     font-weight: bold;\n          margin: 0;\n      }\n      #message-2 {\n
18  -  display: inline-block;\n          *display: inline;\n          zoom: 1;\n
19  -  max-width: 17em;\n          _width: 17em;\n      }\n      </style>\n      <script>
20  -\n      \n      </script>\n  </head>\n  <body>\n  <!-- status code : 400 -->\n  <!-- H
21  -ost Header Required -->\n  <!-- host machine: media-router-fp1001.prod.media.gq1.
22  -yahoo.com -->\n  <!-- timestamp: 1587919712.936 -->\n  <!-- url: http:///-->\n  <sc
23  -ript type="text/javascript">\n    function buildUrl(url, parameters){\n      var q
24  -s = [];\n      for(var key in parameters) {\n        var value = parameters[key];\n
25  -        qs.push(encodeURIComponent(key) + "=" + encodeURIComponent(value));\n
26  -  }\n      url = url + "?" + qs.join('&');\n      return url;\n    }\n\n    function
27  -generateBRBMarkup(site) {\n      params.source = 'brb';\n      generateBeaconMarku
28  -p(params);\n      var englishHeader = 'Will be right back...';\n      var englishM
29  -essage1 = 'Thank you for your patience.';\n      var englishMessage2 = 'Our engin
30  -eers are working quickly to resolve the issue.';\n      var defaultLogoStyle = ''
31  -;\n      var siteDataMap = {\n        'default': {\n          logo: 'https://s.yimg
32  -.com/rz/p/yahoo_frontpage_en-US_s_f_p_205x58_frontpage.png',\n          logoAlt:
33  -'Yahoo Logo',\n          logoStyle: defaultLogoStyle,\n          header: englishHe
34  -ader,\n          message1: englishMessage1,\n          message2: englishMessage2\n
35  -       }\n      };\n\n      var siteDetails = siteDataMap['default'];\n\n      docume
36  -nt.write('<table><tbody><tr><td>');\n      document.write('<div id="content">');\n
37  -      document.write('<img src="' + siteDetails['logo'] + '" alt="' + siteDetail
38  -s['logoAlt'] + '" style="' + siteDetails['logoStyle'] + '">');\n      document.wr
39  -ite('<h1 style="margin-top:20px;">' + siteDetails['header'] + '</h1>');\n      do
40  -cument.write('<p id="message-1">' + siteDetails['message1'] + '</p>');\n      doc
41  -ument.write('<p id="message-2">' + siteDetails['message2'] + '</p>');\n      docu
42  -ment.write('</div>');\n      document.write('</td></tr></tbody></table>');\n    }\n
43  -\n    function generateBeaconMarkup(params) {\n        document.write('<img src="'
44  - + buildUrl('//geo.yahoo.com/b', params) + '" style="display:none;" width="0px"
45  -height="0px"/>');\n        var beacon = new Image();\n        beacon.src = buildUr
46  -l('//bcn.fp.yahoo.com/p', params);\n    }\n\n    var hostname = window.location.hos
47  -tname;\n    var device = '-';\n    var ynet = ('-' === '1');\n    var time = new Da
48  -te().getTime();\n    var params = {\n        s: '1197757129',\n        t: time,\n
49  -     err_url: document.URL,\n        err: '400',\n        test: '-',\n        ats_h
50  -ost: 'media-router-fp1001.prod.media.gq1.yahoo.com',\n        rid: '-',\n        m
51  -essage: 'Host Header Required'\n    };\n\n    if(ynet) {\n        document.write('<d
52  -iv style="height: 5px; background-color: red;"></div>');\n    }\n    generateBRBMa
53  -rkup(hostname, params);\n\n  </script>\n  <noscript>\n  <table>\n    <tbody>\n      <t
54  -r>\n        <td>\n          <div id="englishContent">\n            <h1 style="margi
55  -n-top:20px;">Will be right back...</h1>\n            <p id="message-1">Thank you
56  -for your patience.</p>\n            <p id="message-2">Our engineers are working q
57  -uickly to resolve the issue.</p>\n          </div>\n        </td>\n      </tr>\n
58  -</tbody>\n  </table>\n  </noscript>\n  </body>\n</html>\n
Successful creation

Sunday, April 19, 2020

Threads in C - Input and Output

Today, we will see only to pass values to a thread.  Retrieve value from thread.

 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
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>

//Thread to change value from 20 to 30
void * threadtak (void * poin)
{
    int *inttak = (int *)poin;
    *inttak=30;
    return NULL;
}

//Thread to return a value 60
void * threadret ()
{
  int *ret=malloc(sizeof(int));
  *ret=60;
  printf("%d\n",*ret);
  return ret;
}
int main()
{
    pthread_t tak,ret;
    pthread_attr_t attr;
    pthread_attr_init(&attr);

    int vartak=20;
    pthread_create(&tak, &attr,threadtak, &vartak);
    pthread_join(tak,NULL);
    printf("Modified vartak = %d\n",vartak);

    int *varret;
    pthread_create(&ret, &attr,threadret, NULL);
    pthread_join(ret,(void *)&varret);
    printf("Returned varret=%d\n",*varret);
    
    return 0;
}

Lets break the explanation into 2.

Passing the value

Line 29: Address of vartak is passed as argument
Line 9: As it is declared void pointer, it can take the address of integer/any other data type.
Line 10: Value at inttak is changed to 30
Line 11: Returned as NULL
Line 31: vartak is already changed and can be accessed as normal int


1
2
3
4
5
# gcc -pthread -o a.out main.c
# ./a.out
Modified vartak = 30
60
Returned varret=60

Value is vartak is displayed as 30

Returning the value

Line 33: We try to retrieve the value from threadret into integer pointer.
Line 34: As we are not passing any argument to the thread, we keep it NULL
Line 15: The argument for the thread can be kept blank as no argument is passed
Line 17: We create a memory and assign the value 60
Line 20: Return the address of ret
Line 35: Join should have void **.  We keep it &varret.  Because, *varret is value. varret is the address of *varret. &varret is the address of varret.


1
2
3
4
5
# gcc -pthread -o a.out main.c
# ./a.out
Modified vartak = 30
60
Returned varret=60

Value of varret is displayed as 60.

Sunday, April 12, 2020

Threads in C

We have seen how fork() works in C.  They say, threads are light-weight processes.  Will see how it is done.  Sample program with 3 threads is given here:

 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
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

void * threadrun (void * poin)
{
    int k=*(int *)poin;
    
    for (int i=1;i<5;i++)
    {
      sleep(2);
      printf("iteration %d of thread %d\n",i,k);
    }
    return NULL;
}

int main()
{
    pthread_t tid1,tid2,tid3;
    pthread_attr_t attr;
    pthread_attr_init(&attr);

    int p=1;
    pthread_create(&tid1, &attr,threadrun, &p);
    int q=2;
    pthread_create(&tid2, &attr,threadrun, &q);
    int r=3;
    pthread_create(&tid3, &attr,threadrun, &r);
    
    pthread_join(tid1,NULL);
    pthread_join(tid2,NULL);
    pthread_join(tid3,NULL);
    
    return 0;
}

The thread function should take in a void pointer, return a void pointer to a pointer.  The function threadrun will print 4 iterations each while sleeping 2 seconds for each iteration.  We are returning NULL.

Thread Creation
Line 19 - Create an identifier
Line 20/21 - Create an attribute structure and initialize
Line 23 - Create a value to pass it to thread, so that we can identify the thread
Line 24 - Start the Thread

After thread is created, they will start executing independent of each other.  You can see the stdout the sequence in which the prints are made.

Thread Join
Line 30 - We wait till thread1 is returned.
Line 31 - We wait till thread2 is returned
Line 32 - We wait till thread3 is returned

As Thread1 is first in line,  even though thread 2 and 3 returns earlier, our program will wait till thread1 is completed.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# ./thread
iteration 1 of thread 1
iteration 1 of thread 3
iteration 1 of thread 2
iteration 2 of thread 1
iteration 2 of thread 2
iteration 2 of thread 3
iteration 3 of thread 3
iteration 3 of thread 2
iteration 3 of thread 1
iteration 4 of thread 3
iteration 4 of thread 2
iteration 4 of thread 1