Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 8a17484

Browse files
author
Anton Yarkov
committed
Examples of multiprocess tcp servers working in Prefork or Process-per-request modes.
1 parent 92b5f73 commit 8a17484

File tree

4 files changed

+478
-0
lines changed

4 files changed

+478
-0
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <strings.h>
4+
#include <sys/types.h> /*для совместимости */
5+
#include <sys/socket.h>
6+
#include <arpa/inet.h> // Для преобразования htonl, htons, ntohl, ntohs
7+
#include <netinet/in.h> // для sockaddr_in
8+
#include <fcntl.h>
9+
#include <netdb.h>
10+
#include <unistd.h> // Для close()
11+
//#include <errno> - не используем, иногда может содержать ошибку другого процесса
12+
13+
#define EXIT_FAILURE 1
14+
#define PORTNUM 1500 // Port > 1024 because program will not work not as root.
15+
16+
void main(int argc, char *argv[])
17+
{
18+
struct hostent *hp;
19+
if ((hp = gethostbyname(argv[1])) == 0)
20+
{
21+
perror("Error of calling gethostbyname"); /* или strerror */
22+
exit(EXIT_FAILURE);
23+
}
24+
25+
struct sockaddr_in serv_addr;
26+
bzero(&serv_addr, sizeof(serv_addr)); // устаревшая, TODO use memset
27+
bcopy(hp->h_addr_list[0], &serv_addr.sin_addr, hp->h_length); // устаревшая, TODO use memcpy, memmove
28+
serv_addr.sin_family = hp->h_addrtype;
29+
serv_addr.sin_port = htons(PORTNUM);
30+
31+
int sockfd = -1;
32+
if ((sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
33+
{
34+
perror("Error of calling socket");
35+
exit(EXIT_FAILURE);
36+
}
37+
38+
fprintf(stderr, "Server address: %s\n", inet_ntoa(serv_addr.sin_addr));
39+
40+
if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1)
41+
{
42+
perror("Error of calling connect");
43+
exit(EXIT_FAILURE);
44+
}
45+
46+
char buf[80] = "Hello, world!";
47+
send(sockfd, buf, sizeof(buf), MSG_NOSIGNAL);
48+
49+
if (recv(sockfd, buf, sizeof(buf), MSG_NOSIGNAL) < 0)
50+
{
51+
perror("Error of calling recv");
52+
exit(EXIT_FAILURE);
53+
}
54+
55+
printf("Received from server: %s\n", buf);
56+
57+
// Если был вызыван fork, то дескриптор будет доступен и в процессе родителя и child-процессе.
58+
// Соединение разрывается только когда закрыты все дескрипторы, связанные с сокетом.
59+
close(sockfd);
60+
printf("Client off!\n\n");
61+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <strings.h>
4+
#include <sys/types.h> // для совместимости
5+
#include <sys/socket.h>
6+
#include <arpa/inet.h> // Для преобразования htonl, htons, ntohl, ntohs
7+
#include <fcntl.h>
8+
#include <netdb.h>
9+
#include <unistd.h> // Для close()
10+
//#include <errno> - не используем, иногда может содержать ошибку другого процесса
11+
12+
#define EXIT_FAILURE 1
13+
#define PORTNUM 1500 // Port > 1024 because program will not work not as root.
14+
15+
void main()
16+
{
17+
// Create socket
18+
int sockfd = -1;
19+
if ((sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
20+
{
21+
perror("Error of calling socket"); /* или strerror */
22+
exit(EXIT_FAILURE);
23+
}
24+
25+
// For UDP SO_REUSEADDR may mean some problems...
26+
int optval = 1;
27+
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(int)) == -1)
28+
{
29+
perror("Error of calling setsockopt");
30+
exit(EXIT_FAILURE);
31+
}
32+
33+
// Set address
34+
struct sockaddr_in serv_addr;
35+
bzero(&serv_addr, sizeof(serv_addr)); // устаревшая, TODO use memset
36+
serv_addr.sin_family = AF_INET;
37+
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 0.0.0.0
38+
39+
// Change bytes order to network'
40+
serv_addr.sin_port = htons((int)PORTNUM);
41+
42+
// Link socket with address
43+
if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1)
44+
{
45+
perror("Error of calling bind");
46+
exit(EXIT_FAILURE);
47+
}
48+
49+
fprintf(stderr, "Server is ready: %s\n", inet_ntoa(serv_addr.sin_addr));
50+
51+
// Server is ready to get SOMAXCONN connection requests (128).
52+
// This is *SHOULD* be enought to call accept and create child process.
53+
if (listen(sockfd, SOMAXCONN) == -1)
54+
{
55+
perror("Error of calling listen");
56+
exit(EXIT_FAILURE);
57+
}
58+
59+
struct sockaddr_in clnt_addr;
60+
int ns, pid;
61+
62+
while (1)
63+
{
64+
socklen_t addrlen;
65+
66+
bzero(&clnt_addr, sizeof(clnt_addr)); // устаревшая, TODO use memset
67+
addrlen = sizeof(clnt_addr);
68+
69+
if ((ns = accept(sockfd, (struct sockaddr *)&clnt_addr, &addrlen)) == -1)
70+
{
71+
perror("Error of calling accept");
72+
exit(EXIT_FAILURE);
73+
}
74+
75+
fprintf(stderr, "Client = %s \n", inet_ntoa(clnt_addr.sin_addr));
76+
77+
if ((pid = fork()) == -1)
78+
{
79+
perror("Error of calling fork");
80+
exit(EXIT_FAILURE);
81+
}
82+
83+
if (pid == 0)
84+
{
85+
int nbytes;
86+
int fout;
87+
88+
close(sockfd);
89+
90+
char buf[80];
91+
while ((nbytes = recv(ns, buf, sizeof(buf), MSG_NOSIGNAL)) != 0)
92+
{
93+
send(ns, buf, sizeof(buf), 0);
94+
}
95+
96+
close(ns);
97+
exit(0);
98+
}
99+
100+
// Если был вызыван fork, то дескриптор будет доступен и в процессе родителя и child-процессе.
101+
// Соединение разрывается только когда закрыты все дескрипторы, связанные с сокетом.
102+
close(ns);
103+
104+
printf("Server off! To change this behavior, look in code!\n\n");
105+
// To change this behavior just comment eixt(0) below:
106+
exit(0);
107+
}
108+
}
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <strings.h>
4+
#include <sys/types.h> // For compatibility
5+
#include <sys/socket.h>
6+
#include <arpa/inet.h> // For convertions htonl, htons, ntohl, ntohs
7+
#include <fcntl.h>
8+
#include <netdb.h>
9+
#include <unistd.h> // For close()
10+
#include <sys/wait.h> // For wait, waitpid
11+
//#include <errno> - don't use it because sometimes it may contains an error from another process
12+
13+
// Task:
14+
// Create a prefork TCP server which sends «Hi there!\n» to client 5 times with 1 second time shift
15+
// Client: $> nc 127.0.0.1 1500
16+
17+
#define EXIT_FAILURE 1
18+
#define PORTNUM 1500 // Port > 1024 because program will not work not as root.
19+
#define NUMBER_OF_PROCESSES 2
20+
21+
void main()
22+
{
23+
// Create socket
24+
int sockfd = -1;
25+
if ((sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
26+
{
27+
perror("Error of calling socket"); /* или strerror */
28+
exit(EXIT_FAILURE);
29+
}
30+
31+
int optval = 1;
32+
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(int)) == -1)
33+
{
34+
perror("Error of calling setsockopt");
35+
exit(EXIT_FAILURE);
36+
}
37+
38+
// Set address
39+
struct sockaddr_in serv_addr;
40+
bzero(&serv_addr, sizeof(serv_addr));
41+
serv_addr.sin_family = AF_INET;
42+
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 0.0.0.0 (INADDR_LOOPBACK - 127.0.0.1)
43+
44+
// Change bytes order to network'
45+
serv_addr.sin_port = htons((int)PORTNUM);
46+
47+
// Link socket with address
48+
if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1)
49+
{
50+
perror("Error of calling bind");
51+
exit(EXIT_FAILURE);
52+
}
53+
54+
fprintf(stderr, "Server is ready: %s\n", inet_ntoa(serv_addr.sin_addr));
55+
56+
// Server is ready to get SOMAXCONN connection requests (128).
57+
// This is *SHOULD* be enought to call accept and create child process.
58+
if (listen(sockfd, SOMAXCONN) == -1)
59+
{
60+
perror("Error of calling listen");
61+
exit(EXIT_FAILURE);
62+
}
63+
64+
pid_t childs[NUMBER_OF_PROCESSES];
65+
struct sockaddr_in clnt_addr;
66+
int ns;
67+
68+
// Create and handle child processes.
69+
for (int i = 0; i < NUMBER_OF_PROCESSES; i++)
70+
{
71+
pid_t pid;
72+
int status;
73+
switch (pid = fork())
74+
{
75+
case -1:
76+
perror("Error of calling fork"); /* произошла ошибка */
77+
exit(EXIT_FAILURE); /*выход из родительского процесса*/
78+
case 0:
79+
{
80+
int cpid = getpid();
81+
printf("NEW CHILD: PID -- %d, Parent PID -- %d\n", cpid, getppid());
82+
83+
socklen_t addrlen;
84+
bzero(&clnt_addr, sizeof(clnt_addr));
85+
addrlen = sizeof(clnt_addr);
86+
87+
88+
printf("CHILD %d: Waiting to accept connection...\n", cpid);
89+
if ((ns = accept(sockfd, (struct sockaddr *)&clnt_addr, &addrlen)) == -1)
90+
{
91+
perror("Error of calling accept");
92+
exit(EXIT_FAILURE);
93+
}
94+
95+
fprintf(stderr, "CHILD %d: Client = %s \n", cpid, inet_ntoa(clnt_addr.sin_addr));
96+
97+
int counter = 0;
98+
char buf[11] = "Hi there!\n";
99+
while (counter != 5)
100+
{
101+
send(ns, buf, sizeof(buf), MSG_NOSIGNAL);
102+
++counter;
103+
sleep(1);
104+
}
105+
106+
// Если был вызыван fork, то дескриптор будет доступен и в процессе родителя и child-процессе.
107+
// Соединение разрывается только когда закрыты все дескрипторы, связанные с сокетом.
108+
close(ns);
109+
printf("CHILD %d: Exit!\n", cpid);
110+
exit(0);
111+
}
112+
default:
113+
printf("PARENT: PID -- %d, remember NEW CHILD -- %d\n", getpid(), pid);
114+
childs[i] = pid;
115+
break;
116+
}
117+
}
118+
119+
// Wait for ending child processes.
120+
for (int i = 0; i < NUMBER_OF_PROCESSES; i++)
121+
{
122+
int status;
123+
printf("PARENT: Waiting while CHILD %d calls exit()...\n", childs[i]);
124+
while (-1 == waitpid(childs[i], &status, 0));
125+
printf("PARENT: Exit code of CHILD %d is: %d\n", childs[i], WEXITSTATUS(status));
126+
127+
// If the child process fails to exit normally with a status of 0, then it didn't complete its work.
128+
// If the child processes are supposed to be killed by signals, or different exit codes are used, need to change this check accordingly.
129+
short isNormalTermination = WIFEXITED(status);
130+
if (!isNormalTermination ||
131+
// WEXITSTATUS should be used only if normal termination = true.
132+
(isNormalTermination && WEXITSTATUS(status) != 0))
133+
{
134+
printf("PARENT: CHILD %d failed...\n", childs[i]);
135+
exit(0);
136+
}
137+
}
138+
139+
close(sockfd);
140+
exit(0);
141+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /