-
Notifications
You must be signed in to change notification settings - Fork 0
/
image_server.c
164 lines (136 loc) · 4.79 KB
/
image_server.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
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
https://powcoder.com
代写代考加微信 powcoder
Assignment Project Exam Help
Add WeChat powcoder
https://powcoder.com
代写代考加微信 powcoder
Assignment Project Exam Help
Add WeChat powcoder
https://powcoder.com
代写代考加微信 powcoder
Assignment Project Exam Help
Add WeChat powcoder
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/socket.h>
#include <errno.h>
#include <netinet/in.h> /* Internet domain header */
#include "socket.h"
#include "request.h"
#include "response.h"
#ifndef PORT
#define PORT 30000
#endif
#define BACKLOG 10
#define MAX_CLIENTS 10
/*
* Read data from a client socket, and, if there is enough information to
* determine the type of request, spawn a child process to respond to the
* request.
*
* Return 1 if one of the conditions hold:
* a) No bytes were read from the socket. (The client has likely closed the
* connection.)
* b) A child process has been created to respond to the request.
*
* This return value indicates that the server process should close the socket.
* Otherwise, return 0 (indicating that the server must continue to monitor the
* socket).
*
* Complete this function according to the comments within.
* Note that you'll be doing this incrementally, adding to the function as you
* complete the different parts of the assignment.
*/
int handle_client(ClientState *client) {
// Read in data from the client's socket into its buffer,
// and update num_bytes. If no bytes were read, return 1.
//IMPLEMENT THIS
// At this point client->reqData is not null, and so we are guaranteed
// to spawn a child process to handle the request (so we return 1).
// First, call fork. In the *parent* process, just return 1.
// In the *child* process, check the values in client->reqData to determine
// how to respond to the request.
// The child should call exit(0) (rather than return) to prevent it from
// executing the main server loop that listens for new requests.
//IMPLEMENT THIS
close(client->sock);
exit(0);
}
int main(int argc, char **argv) {
ClientState *clients = init_clients(MAX_CLIENTS);
struct sockaddr_in *servaddr = init_server_addr(PORT);
// Create an fd to listen to new connections.
int listenfd = setup_server_socket(servaddr, BACKLOG);
// Print out information about this server
char host[MAX_HOSTNAME];
if ((gethostname(host, sizeof(host))) == -1) {
perror("gethostname");
exit(1);
}
fprintf(stderr, "Server hostname: %s\n", host);
fprintf(stderr, "Port: %d\n", PORT);
// Set up the arguments for select
int maxfd = listenfd;
fd_set allset;
FD_ZERO(&allset);
FD_SET(listenfd, &allset);
// Set up a timer for select (This is only necessary for debugging help)
struct timeval timer;
// Main server loop.
while (1) {
fd_set rset = allset;
timer.tv_sec = 2;
timer.tv_usec = 0;
int nready = select(maxfd + 1, &rset, NULL, NULL, &timer);
if(nready == -1) {
perror("select");
exit(1);
}
if(nready == 0) { // timer expired
// Check if any children have failed
int status;
int pid;
errno = 0;
if((pid = waitpid(-1, &status, WNOHANG)) > 0) {
if(WIFSIGNALED(status)) {
fprintf(stderr, "Child [%d] failed with signal %d\n", pid,
WTERMSIG(status));
}
}
continue;
}
if (FD_ISSET(listenfd, &rset)) { // New client connection.
int new_client_fd = accept_connection(listenfd);
if (new_client_fd >= 0) {
maxfd = (new_client_fd > maxfd) ? new_client_fd : maxfd;
FD_SET(new_client_fd, &allset); // Add new descriptor to set.
for(int i = 0; i < MAX_CLIENTS; i++) {
if (clients[i].sock < 0) {
clients[i].sock = new_client_fd;
break;
}
}
}
nready -= 1;
}
// The nready is just an optimization; no harm in checking all fds
// except efficiency
for (int i = 0; i < MAX_CLIENTS && nready > 0; i++) {
// Check whether clients[i] has an active, ready socket.
if (clients[i].sock < 0 || !FD_ISSET(clients[i].sock, &rset)) {
continue;
}
int done = handle_client(&clients[i]);
if (done) {
FD_CLR(clients[i].sock, &allset);
remove_client(&clients[i]);
}
nready -= 1;
}
}
}