2
This commit is contained in:
81151
server-exp2/abc
Normal file
81151
server-exp2/abc
Normal file
File diff suppressed because it is too large
Load Diff
BIN
server-exp2/cgi-bin/add
Normal file
BIN
server-exp2/cgi-bin/add
Normal file
Binary file not shown.
27
server-exp2/cgi-bin/add.c
Normal file
27
server-exp2/cgi-bin/add.c
Normal file
@@ -0,0 +1,27 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#define MAXLINE 8192
|
||||
|
||||
int main(void) {
|
||||
char *buf, *p;
|
||||
char content[MAXLINE];
|
||||
int n1=0, n2=0;
|
||||
|
||||
/* Extract the two arguments from standard input */
|
||||
scanf("%d&%d", &n1, &n2);
|
||||
|
||||
/* Make the response body */
|
||||
sprintf(content, "Welcome to add.com: ");
|
||||
sprintf(content, "%sTHE Internet addition portal.\r\n<p>", content);
|
||||
sprintf(content, "%sThe answer is: %d + %d = %d\r\n<p>",
|
||||
content, n1, n2, n1 + n2);
|
||||
sprintf(content, "%sThanks for visiting!\r\n", content);
|
||||
|
||||
/* Generate the HTTP response */
|
||||
printf("Content-length: %d\r\n", (int) strlen(content));
|
||||
printf("Content-type: text/html\r\n\r\n");
|
||||
printf("%s", content);
|
||||
fflush(stdout);
|
||||
exit(0);
|
||||
}
|
||||
243
server-exp2/common.c
Normal file
243
server-exp2/common.c
Normal file
@@ -0,0 +1,243 @@
|
||||
/* $begin common.c */
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* The Rio package - robust I/O functions
|
||||
**********************************************************************/
|
||||
/*
|
||||
* rio_readn - robustly read n bytes (unbuffered)
|
||||
*/
|
||||
/* $begin rio_readn */
|
||||
ssize_t rio_readn(int fd, void *usrbuf, size_t n)
|
||||
{
|
||||
size_t nleft = n;
|
||||
ssize_t nread;
|
||||
char *bufp = usrbuf;
|
||||
|
||||
while (nleft > 0) {
|
||||
if ((nread = read(fd, bufp, nleft)) < 0) {
|
||||
if (errno == EINTR) /* interrupted by sig handler return */
|
||||
nread = 0; /* and call read() again */
|
||||
else
|
||||
return -1; /* errno set by read() */
|
||||
}
|
||||
else if (nread == 0)
|
||||
break; /* EOF */
|
||||
nleft -= nread;
|
||||
bufp += nread;
|
||||
}
|
||||
return (n - nleft); /* return >= 0 */
|
||||
}
|
||||
/* $end rio_readn */
|
||||
|
||||
/*
|
||||
* rio_writen - robustly write n bytes (unbuffered)
|
||||
*/
|
||||
/* $begin rio_writen */
|
||||
ssize_t rio_writen(int fd, void *usrbuf, size_t n)
|
||||
{
|
||||
size_t nleft = n;
|
||||
ssize_t nwritten;
|
||||
char *bufp = usrbuf;
|
||||
|
||||
while (nleft > 0) {
|
||||
if ((nwritten = write(fd, bufp, nleft)) <= 0) {
|
||||
if (errno == EINTR) /* interrupted by sig handler return */
|
||||
nwritten = 0; /* and call write() again */
|
||||
else
|
||||
return -1; /* errorno set by write() */
|
||||
}
|
||||
nleft -= nwritten;
|
||||
bufp += nwritten;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
/* $end rio_writen */
|
||||
|
||||
|
||||
/*
|
||||
* rio_read - This is a wrapper for the Unix read() function that
|
||||
* transfers min(n, rio_cnt) bytes from an internal buffer to a user
|
||||
* buffer, where n is the number of bytes requested by the user and
|
||||
* rio_cnt is the number of unread bytes in the internal buffer. On
|
||||
* entry, rio_read() refills the internal buffer via a call to
|
||||
* read() if the internal buffer is empty.
|
||||
*/
|
||||
/* $begin rio_read */
|
||||
static ssize_t rio_read(rio_t *rp, char *usrbuf, size_t n)
|
||||
{
|
||||
int cnt;
|
||||
|
||||
while (rp->rio_cnt <= 0) { /* refill if buf is empty */
|
||||
rp->rio_cnt = read(rp->rio_fd, rp->rio_buf,
|
||||
sizeof(rp->rio_buf));
|
||||
if (rp->rio_cnt < 0) {
|
||||
if (errno != EINTR) /* interrupted by sig handler return */
|
||||
return -1;
|
||||
}
|
||||
else if (rp->rio_cnt == 0) /* EOF */
|
||||
return 0;
|
||||
else
|
||||
rp->rio_bufptr = rp->rio_buf; /* reset buffer ptr */
|
||||
}
|
||||
|
||||
/* Copy min(n, rp->rio_cnt) bytes from internal buf to user buf */
|
||||
cnt = n;
|
||||
if (rp->rio_cnt < n)
|
||||
cnt = rp->rio_cnt;
|
||||
memcpy(usrbuf, rp->rio_bufptr, cnt);
|
||||
rp->rio_bufptr += cnt;
|
||||
rp->rio_cnt -= cnt;
|
||||
return cnt;
|
||||
}
|
||||
/* $end rio_read */
|
||||
|
||||
/*
|
||||
* rio_readinitb - Associate a descriptor with a read buffer and reset buffer
|
||||
*/
|
||||
/* $begin rio_readinitb */
|
||||
void rio_readinitb(rio_t *rp, int fd)
|
||||
{
|
||||
rp->rio_fd = fd;
|
||||
rp->rio_cnt = 0;
|
||||
rp->rio_bufptr = rp->rio_buf;
|
||||
}
|
||||
/* $end rio_readinitb */
|
||||
|
||||
/*
|
||||
* rio_readnb - Robustly read n bytes (buffered)
|
||||
*/
|
||||
/* $begin rio_readnb */
|
||||
ssize_t rio_readnb(rio_t *rp, void *usrbuf, size_t n)
|
||||
{
|
||||
size_t nleft = n;
|
||||
ssize_t nread;
|
||||
char *bufp = usrbuf;
|
||||
|
||||
while (nleft > 0) {
|
||||
if ((nread = rio_read(rp, bufp, nleft)) < 0) {
|
||||
if (errno == EINTR) /* interrupted by sig handler return */
|
||||
nread = 0; /* call read() again */
|
||||
else
|
||||
return -1; /* errno set by read() */
|
||||
}
|
||||
else if (nread == 0)
|
||||
break; /* EOF */
|
||||
nleft -= nread;
|
||||
bufp += nread;
|
||||
}
|
||||
return (n - nleft); /* return >= 0 */
|
||||
}
|
||||
/* $end rio_readnb */
|
||||
|
||||
/*
|
||||
* rio_readlineb - robustly read a text line (buffered)
|
||||
*/
|
||||
/* $begin rio_readlineb */
|
||||
ssize_t rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen)
|
||||
{
|
||||
int n, rc;
|
||||
char c, *bufp = usrbuf;
|
||||
|
||||
for (n = 1; n < maxlen; n++) {
|
||||
if ((rc = rio_read(rp, &c, 1)) == 1) {
|
||||
*bufp++ = c;
|
||||
if (c == '\n')
|
||||
break;
|
||||
} else if (rc == 0) {
|
||||
if (n == 1)
|
||||
return 0; /* EOF, no data read */
|
||||
else
|
||||
break; /* EOF, some data was read */
|
||||
} else
|
||||
return -1; /* error */
|
||||
}
|
||||
*bufp = 0;
|
||||
return n;
|
||||
}
|
||||
/* $end rio_readlineb */
|
||||
|
||||
/**********************************
|
||||
* Wrappers for robust I/O routines
|
||||
**********************************/
|
||||
|
||||
|
||||
/********************************
|
||||
* Client/server helper functions
|
||||
********************************/
|
||||
/*
|
||||
* open_client_sock - open connection to server at <hostname, port>
|
||||
* and return a socket descriptor ready for reading and writing.
|
||||
* Returns -1 and sets errno on Unix error.
|
||||
* Returns -2 and sets h_errno on DNS (gethostbyname) error.
|
||||
*/
|
||||
/* $begin open_client_sock */
|
||||
int open_client_sock(char *hostname, int port)
|
||||
{
|
||||
int client_sock;
|
||||
struct hostent *hp;
|
||||
struct sockaddr_in serveraddr;
|
||||
|
||||
if ((client_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
|
||||
return -1; /* check errno for cause of error */
|
||||
|
||||
/* Fill in the server's IP address and port */
|
||||
if ((hp = gethostbyname(hostname)) == NULL)
|
||||
return -2; /* check h_errno for cause of error */
|
||||
bzero((char *) &serveraddr, sizeof(serveraddr));
|
||||
serveraddr.sin_family = AF_INET;
|
||||
bcopy((char *)hp->h_addr_list[0],
|
||||
(char *)&serveraddr.sin_addr.s_addr, hp->h_length);
|
||||
serveraddr.sin_port = htons(port);
|
||||
|
||||
/* Establish a connection with the server */
|
||||
if (connect(client_sock, (SA *) &serveraddr, sizeof(serveraddr)) < 0)
|
||||
return -1;
|
||||
return client_sock;
|
||||
}
|
||||
/* $end open_client_sock */
|
||||
|
||||
/*
|
||||
* open_listen_sock - open and return a listening socket on port
|
||||
* Returns -1 and sets errno on Unix error.
|
||||
*/
|
||||
/* $begin open_listen_sock */
|
||||
int open_listen_sock(int port)
|
||||
{
|
||||
int listen_sock, optval=1;
|
||||
struct sockaddr_in serveraddr;
|
||||
|
||||
/* Create a socket descriptor */
|
||||
if ((listen_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
|
||||
return -1;
|
||||
|
||||
/* Eliminates "Address already in use" error from bind. */
|
||||
if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR,
|
||||
(const void *)&optval , sizeof(int)) < 0)
|
||||
return -1;
|
||||
|
||||
/* Listen_sock will be an endpoint for all requests to port
|
||||
on any IP address for this host */
|
||||
bzero((char *) &serveraddr, sizeof(serveraddr));
|
||||
serveraddr.sin_family = AF_INET;
|
||||
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
serveraddr.sin_port = htons((unsigned short)port);
|
||||
if (bind(listen_sock, (SA *)&serveraddr, sizeof(serveraddr)) < 0)
|
||||
return -1;
|
||||
|
||||
/* Make it a listening socket ready to accept connection requests */
|
||||
if (listen(listen_sock, LISTENQ) < 0)
|
||||
return -1;
|
||||
return listen_sock;
|
||||
}
|
||||
/* $end open_listen_sock */
|
||||
|
||||
|
||||
/* $end wrapper.c */
|
||||
|
||||
|
||||
|
||||
|
||||
78
server-exp2/common.h
Normal file
78
server-exp2/common.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/* $begin common.h */
|
||||
#ifndef __COMMON_H__
|
||||
#define __COMMON_H__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <limits.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/msg.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/sem.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/* Default file permissions are DEF_MODE & ~DEF_UMASK */
|
||||
/* $begin createmasks */
|
||||
#define DEF_MODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH
|
||||
#define DEF_UMASK S_IWGRP|S_IWOTH
|
||||
/* $end createmasks */
|
||||
|
||||
/* Simplifies calls to bind(), connect(), and accept() */
|
||||
/* $begin sockaddrdef */
|
||||
typedef struct sockaddr SA;
|
||||
/* $end sockaddrdef */
|
||||
|
||||
/* Persistent state for the robust I/O (Rio) package */
|
||||
/* $begin rio_t */
|
||||
#define RIO_BUFSIZE 8192
|
||||
typedef struct {
|
||||
int rio_fd; /* descriptor for this internal buf */
|
||||
int rio_cnt; /* unread bytes in internal buf */
|
||||
char *rio_bufptr; /* next unread byte in internal buf */
|
||||
char rio_buf[RIO_BUFSIZE]; /* internal buffer */
|
||||
} rio_t;
|
||||
/* $end rio_t */
|
||||
|
||||
/* External variables */
|
||||
extern int h_errno; /* defined by BIND for DNS errors */
|
||||
extern char **environ; /* defined by libc */
|
||||
|
||||
/* Misc constants */
|
||||
#define MAXLINE 8192 /* max text line length */
|
||||
#define MAXBUF 8192 /* max I/O buffer size */
|
||||
#define LISTENQ 1024 /* second argument to listen() */
|
||||
|
||||
/* Rio (Robust I/O) package */
|
||||
ssize_t rio_readn(int fd, void *usrbuf, size_t n);
|
||||
ssize_t rio_writen(int fd, void *usrbuf, size_t n);
|
||||
void rio_readinitb(rio_t *rp, int fd);
|
||||
ssize_t rio_readnb(rio_t *rp, void *usrbuf, size_t n);
|
||||
ssize_t rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen);
|
||||
|
||||
/* Client/server helper functions */
|
||||
int open_client_sock(char *hostname, int portno);
|
||||
int open_listen_sock(int portno);
|
||||
|
||||
#endif /* __COMMON_H__ */
|
||||
/* $end common.h */
|
||||
BIN
server-exp2/example.jpg
Normal file
BIN
server-exp2/example.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 189 KiB |
BIN
server-exp2/favicon.ico
Normal file
BIN
server-exp2/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
13
server-exp2/index.html
Normal file
13
server-exp2/index.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<html>
|
||||
<head>
|
||||
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon"/>
|
||||
<title>the example web</title>
|
||||
</head>
|
||||
<body>
|
||||
<H1>webserver test page</H1>
|
||||
<p>
|
||||
Not pretty but should prove that webserver works:-)
|
||||
<p>
|
||||
<IMG SRC="example.jpg">
|
||||
</body>
|
||||
</html>
|
||||
200
server-exp2/perf.txt
Normal file
200
server-exp2/perf.txt
Normal file
@@ -0,0 +1,200 @@
|
||||
Flat profile:
|
||||
|
||||
Each sample counts as 0.01 seconds.
|
||||
% cumulative self self total
|
||||
time seconds seconds calls us/call us/call name
|
||||
42.86 0.09 0.09 23039432 0.00 0.00 rio_read
|
||||
28.57 0.15 0.06 15339432 0.00 0.01 rio_readlineb
|
||||
9.52 0.17 0.02 100001 0.20 1.69 read_requesthdrs
|
||||
9.52 0.19 0.02 100000 0.20 0.20 get_filetype
|
||||
4.76 0.20 0.01 100001 0.10 2.10 process_trans
|
||||
4.76 0.21 0.01 100001 0.10 0.10 rio_readinitb
|
||||
0.00 0.21 0.00 200000 0.00 0.00 rio_writen
|
||||
0.00 0.21 0.00 100000 0.00 0.20 feed_static
|
||||
0.00 0.21 0.00 100000 0.00 0.00 is_static
|
||||
0.00 0.21 0.00 100000 0.00 0.00 parse_static_uri
|
||||
0.00 0.21 0.00 1 0.00 0.00 open_listen_sock
|
||||
|
||||
% the percentage of the total running time of the
|
||||
time program used by this function.
|
||||
|
||||
cumulative a running sum of the number of seconds accounted
|
||||
seconds for by this function and those listed above it.
|
||||
|
||||
self the number of seconds accounted for by this
|
||||
seconds function alone. This is the major sort for this
|
||||
listing.
|
||||
|
||||
calls the number of times this function was invoked, if
|
||||
this function is profiled, else blank.
|
||||
|
||||
self the average number of milliseconds spent in this
|
||||
ms/call function per call, if this function is profiled,
|
||||
else blank.
|
||||
|
||||
total the average number of milliseconds spent in this
|
||||
ms/call function and its descendents per call, if this
|
||||
function is profiled, else blank.
|
||||
|
||||
name the name of the function. This is the minor sort
|
||||
for this listing. The index shows the location of
|
||||
the function in the gprof listing. If the index is
|
||||
in parenthesis it shows where it would appear in
|
||||
the gprof listing if it were to be printed.
|
||||
|
||||
Copyright (C) 2012-2024 Free Software Foundation, Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved.
|
||||
|
||||
Call graph (explanation follows)
|
||||
|
||||
|
||||
granularity: each sample hit covers 4 byte(s) for 4.76% of 0.21 seconds
|
||||
|
||||
index % time self children called name
|
||||
0.01 0.20 100001/100001 main [2]
|
||||
[1] 100.0 0.01 0.20 100001 process_trans [1]
|
||||
0.02 0.15 100001/100001 read_requesthdrs [3]
|
||||
0.00 0.02 100000/100000 feed_static [6]
|
||||
0.01 0.00 100001/100001 rio_readinitb [8]
|
||||
0.00 0.00 100001/15339432 rio_readlineb [4]
|
||||
0.00 0.00 100000/100000 is_static [10]
|
||||
0.00 0.00 100000/100000 parse_static_uri [11]
|
||||
-----------------------------------------------
|
||||
<spontaneous>
|
||||
[2] 100.0 0.00 0.21 main [2]
|
||||
0.01 0.20 100001/100001 process_trans [1]
|
||||
0.00 0.00 1/1 open_listen_sock [12]
|
||||
-----------------------------------------------
|
||||
0.02 0.15 100001/100001 process_trans [1]
|
||||
[3] 80.5 0.02 0.15 100001 read_requesthdrs [3]
|
||||
0.06 0.09 15239431/15339432 rio_readlineb [4]
|
||||
-----------------------------------------------
|
||||
0.00 0.00 100001/15339432 process_trans [1]
|
||||
0.06 0.09 15239431/15339432 read_requesthdrs [3]
|
||||
[4] 71.4 0.06 0.09 15339432 rio_readlineb [4]
|
||||
0.09 0.00 23039432/23039432 rio_read [5]
|
||||
-----------------------------------------------
|
||||
0.09 0.00 23039432/23039432 rio_readlineb [4]
|
||||
[5] 42.9 0.09 0.00 23039432 rio_read [5]
|
||||
-----------------------------------------------
|
||||
0.00 0.02 100000/100000 process_trans [1]
|
||||
[6] 9.5 0.00 0.02 100000 feed_static [6]
|
||||
0.02 0.00 100000/100000 get_filetype [7]
|
||||
0.00 0.00 200000/200000 rio_writen [9]
|
||||
-----------------------------------------------
|
||||
0.02 0.00 100000/100000 feed_static [6]
|
||||
[7] 9.5 0.02 0.00 100000 get_filetype [7]
|
||||
-----------------------------------------------
|
||||
0.01 0.00 100001/100001 process_trans [1]
|
||||
[8] 4.8 0.01 0.00 100001 rio_readinitb [8]
|
||||
-----------------------------------------------
|
||||
0.00 0.00 200000/200000 feed_static [6]
|
||||
[9] 0.0 0.00 0.00 200000 rio_writen [9]
|
||||
-----------------------------------------------
|
||||
0.00 0.00 100000/100000 process_trans [1]
|
||||
[10] 0.0 0.00 0.00 100000 is_static [10]
|
||||
-----------------------------------------------
|
||||
0.00 0.00 100000/100000 process_trans [1]
|
||||
[11] 0.0 0.00 0.00 100000 parse_static_uri [11]
|
||||
-----------------------------------------------
|
||||
0.00 0.00 1/1 main [2]
|
||||
[12] 0.0 0.00 0.00 1 open_listen_sock [12]
|
||||
-----------------------------------------------
|
||||
|
||||
This table describes the call tree of the program, and was sorted by
|
||||
the total amount of time spent in each function and its children.
|
||||
|
||||
Each entry in this table consists of several lines. The line with the
|
||||
index number at the left hand margin lists the current function.
|
||||
The lines above it list the functions that called this function,
|
||||
and the lines below it list the functions this one called.
|
||||
This line lists:
|
||||
index A unique number given to each element of the table.
|
||||
Index numbers are sorted numerically.
|
||||
The index number is printed next to every function name so
|
||||
it is easier to look up where the function is in the table.
|
||||
|
||||
% time This is the percentage of the `total' time that was spent
|
||||
in this function and its children. Note that due to
|
||||
different viewpoints, functions excluded by options, etc,
|
||||
these numbers will NOT add up to 100%.
|
||||
|
||||
self This is the total amount of time spent in this function.
|
||||
|
||||
children This is the total amount of time propagated into this
|
||||
function by its children.
|
||||
|
||||
called This is the number of times the function was called.
|
||||
If the function called itself recursively, the number
|
||||
only includes non-recursive calls, and is followed by
|
||||
a `+' and the number of recursive calls.
|
||||
|
||||
name The name of the current function. The index number is
|
||||
printed after it. If the function is a member of a
|
||||
cycle, the cycle number is printed between the
|
||||
function's name and the index number.
|
||||
|
||||
|
||||
For the function's parents, the fields have the following meanings:
|
||||
|
||||
self This is the amount of time that was propagated directly
|
||||
from the function into this parent.
|
||||
|
||||
children This is the amount of time that was propagated from
|
||||
the function's children into this parent.
|
||||
|
||||
called This is the number of times this parent called the
|
||||
function `/' the total number of times the function
|
||||
was called. Recursive calls to the function are not
|
||||
included in the number after the `/'.
|
||||
|
||||
name This is the name of the parent. The parent's index
|
||||
number is printed after it. If the parent is a
|
||||
member of a cycle, the cycle number is printed between
|
||||
the name and the index number.
|
||||
|
||||
If the parents of the function cannot be determined, the word
|
||||
`<spontaneous>' is printed in the `name' field, and all the other
|
||||
fields are blank.
|
||||
|
||||
For the function's children, the fields have the following meanings:
|
||||
|
||||
self This is the amount of time that was propagated directly
|
||||
from the child into the function.
|
||||
|
||||
children This is the amount of time that was propagated from the
|
||||
child's children to the function.
|
||||
|
||||
called This is the number of times the function called
|
||||
this child `/' the total number of times the child
|
||||
was called. Recursive calls by the child are not
|
||||
listed in the number after the `/'.
|
||||
|
||||
name This is the name of the child. The child's index
|
||||
number is printed after it. If the child is a
|
||||
member of a cycle, the cycle number is printed
|
||||
between the name and the index number.
|
||||
|
||||
If there are any cycles (circles) in the call graph, there is an
|
||||
entry for the cycle-as-a-whole. This entry shows who called the
|
||||
cycle (as parents) and the members of the cycle (as children.)
|
||||
The `+' recursive calls entry shows the number of function calls that
|
||||
were internal to the cycle, and the calls entry for each member shows,
|
||||
for that member, how many times it was called from other members of
|
||||
the cycle.
|
||||
|
||||
Copyright (C) 2012-2024 Free Software Foundation, Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved.
|
||||
|
||||
Index by function name
|
||||
|
||||
[6] feed_static [11] parse_static_uri [8] rio_readinitb
|
||||
[7] get_filetype [1] process_trans [4] rio_readlineb
|
||||
[10] is_static [3] read_requesthdrs [9] rio_writen
|
||||
[12] open_listen_sock [5] rio_read (common.c)
|
||||
6
server-exp2/t1.txt
Normal file
6
server-exp2/t1.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
hello
|
||||
world
|
||||
dgut
|
||||
computer
|
||||
Hello
|
||||
WORLD
|
||||
6
server-exp2/t2.txt
Normal file
6
server-exp2/t2.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
hello
|
||||
world
|
||||
dgut
|
||||
computer
|
||||
Hello
|
||||
WORLD
|
||||
45
server-exp2/taskline.c
Normal file
45
server-exp2/taskline.c
Normal file
@@ -0,0 +1,45 @@
|
||||
/* task pool management fucntions */
|
||||
/* task_pool_init */
|
||||
|
||||
#include "common.h"
|
||||
#include "taskline.h"
|
||||
void task_line_init(task_line_t *tlp, int n)
|
||||
{
|
||||
tlp->taskp = calloc(n, sizeof(task_t));
|
||||
tlp->cnt = n; /* socks holds max of n items */
|
||||
tlp->inpos= tlp->outpos = 0; /* Empty socks iff inpos== outpos */
|
||||
sem_init(&tlp->mutex, 0, 1); /* Binary semaphore for locking */
|
||||
sem_init(&tlp->avail, 0, tlp->cnt);/* Initially, socks has cnt empty cell */
|
||||
sem_init(&tlp->ready, 0, 0); /* Initially, socks has zero data items */
|
||||
}
|
||||
|
||||
/* Clean up task line */
|
||||
void task_line_deinit(task_line_t *tlp)
|
||||
{
|
||||
free(tlp->taskp);
|
||||
}
|
||||
|
||||
/* Insert item onto the rear of task line */
|
||||
void task_insert (task_line_t *tlp, task_t item)
|
||||
{ sem_wait(&tlp->avail); /* Wait for available cell */
|
||||
sem_wait(&tlp->mutex); /* Lock the shared variable inpos pointer */
|
||||
tlp->taskp[tlp->inpos] = item; /* Insert the item */
|
||||
tlp->inpos =(tlp-> inpos +1)%(tlp->cnt); /* adjuset inpos point */
|
||||
sem_post(&tlp->mutex); /* Unlock the buffer */
|
||||
sem_post(&tlp->ready); /* Announce available item */
|
||||
}
|
||||
|
||||
|
||||
/* Remove and return the first item from task_pool */
|
||||
task_t task_remove(task_line_t *tlp)
|
||||
{
|
||||
task_t item;
|
||||
sem_wait(&tlp->ready); /* Wait for available item */
|
||||
sem_wait(&tlp->mutex); /* Lock the shared pointer variable tp->outpos */
|
||||
item = tlp->taskp[tlp->outpos]; /* Remove the item */
|
||||
tlp->outpos=(tlp->outpos+1)%(tlp->cnt); /* adjuset outpos point */
|
||||
sem_post(&tlp->avail); /* Announce available slot */
|
||||
sem_post(&tlp->mutex); /* Unlock the shared pointer variable tp->outpos */
|
||||
return item;
|
||||
}
|
||||
|
||||
20
server-exp2/taskline.h
Normal file
20
server-exp2/taskline.h
Normal file
@@ -0,0 +1,20 @@
|
||||
typedef struct _task_t {
|
||||
int conn_sock; //客户连接socket
|
||||
int hit; //第几个客户
|
||||
} task_t;
|
||||
|
||||
typedef struct {
|
||||
task_t *taskp; /* Buffer array */
|
||||
int cnt; /* Maximum number of cell */
|
||||
int inpos; /* buf[inpos] is first available cell */
|
||||
int outpos; /* buf[outpos] is fist item */
|
||||
sem_t mutex; /* Protects accesses to socks */
|
||||
sem_t avail; /* Counts available cells */
|
||||
sem_t ready; /* Counts ready items */
|
||||
} task_line_t;
|
||||
|
||||
/* task line wrapper functions */
|
||||
void task_line_init(task_line_t *tlp, int n);
|
||||
void task_line_deinit(task_line_t *tlp);
|
||||
void task_insert(task_line_t *tlp, task_t item);
|
||||
task_t task_remove(task_line_t *tlp);
|
||||
8
server-exp2/test.html
Normal file
8
server-exp2/test.html
Normal file
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>a simple page for testing tiny</title>
|
||||
<head>
|
||||
<body>
|
||||
Hello World
|
||||
</body>
|
||||
</html>
|
||||
BIN
server-exp2/togglec
Executable file
BIN
server-exp2/togglec
Executable file
Binary file not shown.
30
server-exp2/togglec.c
Normal file
30
server-exp2/togglec.c
Normal file
@@ -0,0 +1,30 @@
|
||||
#include "common.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int client_sock, port;
|
||||
char *host, buf[MAXLINE];
|
||||
rio_t rio;
|
||||
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "usage: %s <host><port>\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
host = argv[1];
|
||||
port = atoi(argv[2]);
|
||||
|
||||
client_sock = open_client_sock(host, port);
|
||||
if(client_sock==-1) {
|
||||
fputs("Error to connect the Server\n",stdout);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while (fgets(buf, MAXLINE, stdin) != NULL) {
|
||||
//sleep(1);
|
||||
send(client_sock, buf, strlen(buf),0);
|
||||
recv(client_sock, buf, MAXLINE,0);
|
||||
fputs(buf, stdout);
|
||||
}
|
||||
close(client_sock);
|
||||
exit(0);
|
||||
}
|
||||
6
server-exp2/togglecm
Normal file
6
server-exp2/togglecm
Normal file
@@ -0,0 +1,6 @@
|
||||
for i in {1..20}
|
||||
do
|
||||
./togglec localhost 12345 < $1
|
||||
sleep 1
|
||||
done
|
||||
|
||||
BIN
server-exp2/togglesp
Executable file
BIN
server-exp2/togglesp
Executable file
Binary file not shown.
82
server-exp2/togglesp.c
Normal file
82
server-exp2/togglesp.c
Normal file
@@ -0,0 +1,82 @@
|
||||
#include "common.h"
|
||||
|
||||
void sigchld_handler(int sig)
|
||||
{
|
||||
while (waitpid(-1, 0, WNOHANG) > 0);
|
||||
return;
|
||||
}
|
||||
|
||||
typedef void (*sighandler_t) (int sig) ;
|
||||
|
||||
void Signal(int sig, sighandler_t handler){
|
||||
struct sigaction sa;
|
||||
sa.sa_handler = sigchld_handler;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_RESTART; // 确保被信号中断的系统调用自动重启
|
||||
sigaction(SIGCHLD, &sa, NULL);
|
||||
}
|
||||
|
||||
void toggle(int conn_sock,int hit)
|
||||
{
|
||||
size_t n; int i,no=0;
|
||||
char buf[MAXLINE];
|
||||
|
||||
printf("第%d个客户通信开始\n",hit);
|
||||
while((n =recv(conn_sock, buf, MAXLINE,0))> 0) {
|
||||
printf("toggle服务器收到第%d个客户第%d个消息,长度为%d字节\n", hit,++no,(int)n);
|
||||
|
||||
for(i=0; i<n; i++)
|
||||
if(isupper(buf[i]))
|
||||
buf[i]=tolower(buf[i]);
|
||||
else if(islower(buf[i]))
|
||||
buf[i]=toupper(buf[i]);
|
||||
|
||||
send (conn_sock, buf, n, 0);
|
||||
}
|
||||
printf("第%d个客户通信结束\n",hit);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int listen_sock, conn_sock, port;
|
||||
struct sockaddr_in clientaddr;
|
||||
struct hostent *hp;
|
||||
char *haddrp;
|
||||
int hit;
|
||||
|
||||
socklen_t clientlen=sizeof(struct sockaddr_in);
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "usage: %s <port>\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
port = atoi(argv[1]);
|
||||
|
||||
//设置SIGHLD的信号处理函数,用于收割结束的子进程
|
||||
Signal(SIGCHLD, sigchld_handler);
|
||||
|
||||
listen_sock = open_listen_sock(port);
|
||||
|
||||
if( listen_sock==-1) {
|
||||
printf("端口号%d繁忙\n",port);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for(hit=1; ; hit++) {
|
||||
conn_sock = accept(listen_sock, (SA *) &clientaddr, &clientlen);
|
||||
|
||||
/* determine the domain name and IP address of the client */
|
||||
hp = gethostbyaddr((const char *)&clientaddr.sin_addr.s_addr,
|
||||
sizeof(clientaddr.sin_addr.s_addr), AF_INET);
|
||||
haddrp = inet_ntoa(clientaddr.sin_addr);
|
||||
printf("server connected to %s (%s)\n", hp->h_name, haddrp);
|
||||
|
||||
if (fork() == 0) {
|
||||
close(listen_sock); /* Child process closes its listening socket */
|
||||
toggle(conn_sock,hit); /* Child process services client */
|
||||
close(conn_sock); /* Child process closes connection with client */
|
||||
exit(0); /* Child process exits */
|
||||
}
|
||||
close(conn_sock); /* Parent closes connected socket (important!) */
|
||||
}
|
||||
}
|
||||
BIN
server-exp2/togglest
Executable file
BIN
server-exp2/togglest
Executable file
Binary file not shown.
85
server-exp2/togglest.c
Normal file
85
server-exp2/togglest.c
Normal file
@@ -0,0 +1,85 @@
|
||||
#include "common.h"
|
||||
|
||||
void toggle(int conn_sock, int hit);
|
||||
void *serve_client(void *vargp);
|
||||
|
||||
typedef struct _client_data_t {
|
||||
int conn_sock; //客户连接socket
|
||||
int hit; //第几个客户
|
||||
} client_data_t;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int listen_sock, conn_sock, port,*conn_sock_p ;
|
||||
struct sockaddr_in clientaddr;
|
||||
struct hostent *hp;
|
||||
char *haddrp;
|
||||
client_data_t *cdp; //连接客户信息
|
||||
int hit; //连接客户计数
|
||||
|
||||
socklen_t clientlen=sizeof(struct sockaddr_in);
|
||||
|
||||
pthread_t tid;
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "usage: %s <port>\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
port = atoi(argv[1]);
|
||||
|
||||
listen_sock = open_listen_sock(port);
|
||||
if( listen_sock==-1) {
|
||||
printf("端口号%d繁忙\n",port);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (hit=1; ; hit++) {
|
||||
cdp = malloc(sizeof(client_data_t));
|
||||
cdp->conn_sock = accept(listen_sock, (SA *) &clientaddr, &clientlen);
|
||||
cdp->hit=hit;
|
||||
|
||||
/* determine the domain name and IP address of the client */
|
||||
hp = gethostbyaddr((const char *)&clientaddr.sin_addr.s_addr,
|
||||
sizeof(clientaddr.sin_addr.s_addr), AF_INET);
|
||||
haddrp = inet_ntoa(clientaddr.sin_addr);
|
||||
printf("server connected to %s (%s)\n", hp->h_name, haddrp);
|
||||
|
||||
pthread_create(&tid, NULL, serve_client, (void *)cdp);
|
||||
}
|
||||
}
|
||||
|
||||
/* thread routine */
|
||||
void * serve_client (void *vargp)
|
||||
{
|
||||
int hit,conn_sock;
|
||||
client_data_t cd;
|
||||
cd = *(client_data_t *)vargp;
|
||||
|
||||
pthread_detach(pthread_self());
|
||||
free(vargp);
|
||||
toggle(cd.conn_sock,cd.hit);
|
||||
|
||||
close(conn_sock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void toggle(int conn_sock,int hit)
|
||||
{
|
||||
size_t n; int i,no=0;
|
||||
char buf[MAXLINE];
|
||||
|
||||
printf("第%d个客户通信开始\n",hit);
|
||||
while((n =recv(conn_sock, buf, MAXLINE,0))> 0) {
|
||||
printf("toggle服务器收到第%d个客户第%d个消息,长度为%d字节\n", hit,++no,(int)n);
|
||||
|
||||
for(i=0; i<n; i++)
|
||||
if(isupper(buf[i]))
|
||||
buf[i]=tolower(buf[i]);
|
||||
else if(islower(buf[i]))
|
||||
buf[i]=toupper(buf[i]);
|
||||
|
||||
send (conn_sock, buf, n, 0);
|
||||
}
|
||||
printf("第%d个客户通信结束\n",hit);
|
||||
}
|
||||
|
||||
104
server-exp2/togglest_pool.c
Normal file
104
server-exp2/togglest_pool.c
Normal file
@@ -0,0 +1,104 @@
|
||||
#include "common.h"
|
||||
#include "pool.h"
|
||||
|
||||
#define NTHREADS 4
|
||||
#define SBUFSIZE 16
|
||||
|
||||
void toggle(int conn_sock,int hit);
|
||||
void *serve_client(void *vargp);
|
||||
|
||||
void toggle(int conn_sock,int hit)
|
||||
{
|
||||
size_t n; int i,no=0;
|
||||
char buf[MAXLINE];
|
||||
|
||||
//printf("线程%d服务第%d个客户请求通信开始\n",tid,hit);
|
||||
while((n =recv(conn_sock, buf, MAXLINE,0))> 0) {
|
||||
printf("toggle服务器收到第%d个客户第%d个消息,长度为%d字节\n", hit,++no,(int)n);
|
||||
|
||||
for(i=0; i<n; i++)
|
||||
if(isupper(buf[i]))
|
||||
buf[i]=tolower(buf[i]);
|
||||
else if(islower(buf[i]))
|
||||
buf[i]=toupper(buf[i]);
|
||||
sleep(1);
|
||||
send (conn_sock, buf, n, 0);
|
||||
}
|
||||
//printf("线程%d服务第%d个客户请求通信结束\n",tid,hit);
|
||||
}
|
||||
|
||||
//示例任务
|
||||
void handle_request(int sock, int taskid, int tid) {
|
||||
|
||||
printf("线程%d服务第%d个客户通信开始\n",tid,taskid);
|
||||
//usleep(1);
|
||||
toggle(sock,taskid);
|
||||
printf("线程%d服务第%d个客户通信结束\n",tid,taskid);
|
||||
close(sock);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
int listen_sock, conn_sock, port,i;
|
||||
struct sockaddr_in clientaddr;
|
||||
struct hostent *hp;
|
||||
char *haddrp;
|
||||
int hit;
|
||||
|
||||
int nth[NTHREADS];
|
||||
|
||||
socklen_t clientlen=sizeof(struct sockaddr_in);
|
||||
|
||||
pthread_t tid;
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "usage: %s <port>\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
listen_sock = open_listen_sock(port);
|
||||
if( listen_sock==-1) {
|
||||
printf("端口号%d繁忙\n",port);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
port = atoi(argv[1]);
|
||||
|
||||
listen_sock = open_listen_sock(port);
|
||||
if( listen_sock==-1) {
|
||||
printf("端口号%d繁忙\n",port);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("start main\n");
|
||||
// 初始化线程池
|
||||
threadpool* pool = initThreadPool(NTHREADS);
|
||||
|
||||
// 创建示例任务并将其添加到线程池
|
||||
for (hit=1; ; hit++) {
|
||||
conn_sock = accept(listen_sock, (SA *) &clientaddr, &clientlen);
|
||||
|
||||
/* determine the domain name and IP address of the client */
|
||||
hp = gethostbyaddr((const char *)&clientaddr.sin_addr.s_addr,
|
||||
sizeof(clientaddr.sin_addr.s_addr), AF_INET);
|
||||
haddrp = inet_ntoa(clientaddr.sin_addr);
|
||||
//printf("server connected to %s (%s)\n", hp->h_name, haddrp);
|
||||
|
||||
task* new_task = (task*)malloc(sizeof(task));
|
||||
new_task->function = handle_request; // 假设任务函数为 toggle
|
||||
new_task->taskid = hit; // 任务参数,假设为 socket fd 或其他参数
|
||||
new_task->sock=conn_sock;
|
||||
|
||||
addTaskToThreadPool(pool, new_task); /* Insert conn_sock in task pool */
|
||||
}
|
||||
|
||||
// 等待线程池中的所有任务执行完毕
|
||||
waitThreadPool(pool);
|
||||
|
||||
// 销毁线程池
|
||||
destroyThreadPool(pool);
|
||||
|
||||
printf("stop main\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
BIN
server-exp2/togglest_pre
Executable file
BIN
server-exp2/togglest_pre
Executable file
Binary file not shown.
100
server-exp2/togglest_pre.c
Normal file
100
server-exp2/togglest_pre.c
Normal file
@@ -0,0 +1,100 @@
|
||||
#include "common.h"
|
||||
#include "taskline.h"
|
||||
|
||||
#define NTHREADS 4
|
||||
#define SBUFSIZE 16
|
||||
|
||||
void toggle(int conn_sock,int hit);
|
||||
void *handle_request(void *vargp);
|
||||
|
||||
task_line_t tlp; /* task pool: shared buffer of connected descriptors */
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int listen_sock, conn_sock, port,i;
|
||||
struct sockaddr_in clientaddr;
|
||||
struct hostent *hp;
|
||||
char *haddrp;
|
||||
int hit;
|
||||
task_t item; //连接客户信息:socket和客户编号
|
||||
int nth[NTHREADS];
|
||||
|
||||
socklen_t clientlen=sizeof(struct sockaddr_in);
|
||||
|
||||
pthread_t tid;
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "usage: %s <port>\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
listen_sock = open_listen_sock(port);
|
||||
if( listen_sock==-1) {
|
||||
printf("端口号%d繁忙\n",port);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
port = atoi(argv[1]);
|
||||
task_line_init(&tlp, SBUFSIZE);
|
||||
|
||||
listen_sock = open_listen_sock(port);
|
||||
if( listen_sock==-1) {
|
||||
printf("端口号%d繁忙\n",port);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (i = 0; i < NTHREADS; i++) { /* Create worker threads */
|
||||
nth[i]=i;
|
||||
pthread_create(&tid, NULL, handle_request, (void *)&nth[i]);
|
||||
}
|
||||
|
||||
for (hit=1; ; hit++) {
|
||||
item.conn_sock = accept(listen_sock, (SA *) &clientaddr, &clientlen);
|
||||
item.hit=hit;
|
||||
|
||||
/* determine the domain name and IP address of the client */
|
||||
hp = gethostbyaddr((const char *)&clientaddr.sin_addr.s_addr,
|
||||
sizeof(clientaddr.sin_addr.s_addr), AF_INET);
|
||||
haddrp = inet_ntoa(clientaddr.sin_addr);
|
||||
printf("server connected to %s (%s)\n", hp->h_name, haddrp);
|
||||
|
||||
task_insert(&tlp, item); /* Insert conn_sock in task pool */
|
||||
}
|
||||
}
|
||||
|
||||
void *handle_request(void *vargp)
|
||||
{
|
||||
int tid=*(int*) vargp;
|
||||
task_t item;
|
||||
pthread_detach(pthread_self());
|
||||
|
||||
while (1) {
|
||||
item=task_remove(&tlp); /* Remove a task from task line */
|
||||
|
||||
printf("线程%d服务第%d个客户通信开始\n",tid,item.hit);
|
||||
|
||||
toggle(item.conn_sock,item.hit); /* Serve client */
|
||||
close(item.conn_sock);
|
||||
|
||||
printf("线程%d服务第%d个客户通信结束\n",tid,item.hit);
|
||||
}
|
||||
}
|
||||
|
||||
void toggle(int conn_sock,int hit)
|
||||
{
|
||||
size_t n; int i,no=0;
|
||||
char buf[MAXLINE];
|
||||
|
||||
while((n =recv(conn_sock, buf, MAXLINE,0))> 0) {
|
||||
printf("toggle服务器收到第%d个客户第%d个消息,长度为%d字节\n", hit,++no,(int)n);
|
||||
|
||||
for(i=0; i<n; i++)
|
||||
if(isupper(buf[i]))
|
||||
buf[i]=tolower(buf[i]);
|
||||
else if(islower(buf[i]))
|
||||
buf[i]=toupper(buf[i]);
|
||||
|
||||
send (conn_sock, buf, n, 0);
|
||||
}
|
||||
}
|
||||
2
server-exp2/urls
Normal file
2
server-exp2/urls
Normal file
@@ -0,0 +1,2 @@
|
||||
http://127.0.0.1:8088/index.html
|
||||
http://127.0.0.1:8088/test.html
|
||||
BIN
server-exp2/webclient
Executable file
BIN
server-exp2/webclient
Executable file
Binary file not shown.
55
server-exp2/webclient.c
Normal file
55
server-exp2/webclient.c
Normal file
@@ -0,0 +1,55 @@
|
||||
#include <arpa/inet.h> // 提供IP地址转换函数
|
||||
#include <netinet/in.h> // 提供套接字地址结构定义
|
||||
#include <stdio.h> // 标准输入输出
|
||||
#include <stdlib.h> // 标准库函数,如exit()
|
||||
#include <string.h> // 字符串操作函数
|
||||
#include <sys/socket.h> // 套接字相关函数
|
||||
#include <sys/types.h> // 数据类型定义
|
||||
#include <unistd.h> // POSIX API,如read()和write()
|
||||
|
||||
//#define PORT 8181 /* 目标服务器的端口号 */
|
||||
//#define IP_ADDRESS "192.168.0.8" /* 目标服务器的IP地址 */
|
||||
#define BUFSIZE 8196 /* 缓冲区大小 */
|
||||
|
||||
char *command = "GET /index.html HTTP/1.0 \r\n\r\n"; /* HTTP GET 请求命令 */
|
||||
|
||||
// 错误处理函数,打印错误信息并退出程序
|
||||
void pexit(char *msg) {
|
||||
perror(msg); // 打印错误信息
|
||||
exit(1); // 退出程序
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {//客户端启动命令为"./client 127.0.0.1 8088",argv[1]是IP地址,argv[2]是端口号8088
|
||||
int i, sockfd; // sockfd是套接字文件描述符
|
||||
char buffer[BUFSIZE]; // 用于存储从服务器接收的数据
|
||||
struct sockaddr_in serv_addr; // 定义服务器地址结构
|
||||
|
||||
// 打印尝试连接服务器的信息
|
||||
printf("客户端尝试连接到 %s 和端口 %s\n", argv[1], argv[2]);
|
||||
|
||||
// 创建套接字,使用IPv4和TCP协议
|
||||
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) pexit("socket() 创建失败");
|
||||
|
||||
// 配置服务器地址
|
||||
serv_addr.sin_family = AF_INET; // 地址族为IPv4
|
||||
serv_addr.sin_addr.s_addr = inet_addr(argv[1]); // 设置服务器IP地址,如"127.0.0.1"
|
||||
serv_addr.sin_port = htons(atoi(argv[2])); // 设置服务器端口号,如"8088"
|
||||
|
||||
// 尝试连接到服务器
|
||||
if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
|
||||
pexit("connect() 连接失败");
|
||||
|
||||
// 发送HTTP GET请求到服务器
|
||||
printf("发送字节数=%ld %s\n", strlen(command), command);
|
||||
if (write(sockfd, command, strlen(command)) < 0) pexit("write() 发送请求失败");
|
||||
|
||||
// 循环读取服务器返回的数据,并输出到标准输出
|
||||
while ((i = read(sockfd, buffer, BUFSIZE)) > 0) {
|
||||
if (write(1, buffer, i) < 0) // 1表示标准输出
|
||||
pexit("write() 输出到标准输出失败");
|
||||
}
|
||||
|
||||
// 关闭套接字,释放资源
|
||||
close(sockfd);
|
||||
return 0; // 程序正常退出
|
||||
}
|
||||
BIN
server-exp2/weblet
Executable file
BIN
server-exp2/weblet
Executable file
Binary file not shown.
265
server-exp2/weblet.c
Normal file
265
server-exp2/weblet.c
Normal file
@@ -0,0 +1,265 @@
|
||||
#include "common.h"
|
||||
|
||||
void process_trans(int fd,int hit);
|
||||
void read_requesthdrs(rio_t *rp,int hit,int nrh);
|
||||
int is_static(char *uri);
|
||||
void parse_static_uri(char *uri, char *filename);
|
||||
void parse_dynamic_uri(char *uri, char *filename, char *cgiargs);
|
||||
void feed_static(int fd, char *filename, int filesize);
|
||||
void get_filetype(char *filename, char *filetype);
|
||||
void feed_dynamic(int fd, char *filename, char *cgiargs);
|
||||
void error_request(int fd, char *cause, char *errnum,
|
||||
char *shortmsg, char *description);
|
||||
|
||||
/* 支持的文件扩展名及其对应的MIME类型 */
|
||||
struct {
|
||||
char *ext; // 文件扩展名
|
||||
char *filetype; // MIME类型
|
||||
} extensions[] = {
|
||||
{".gif", "image/gif"},
|
||||
{".jpg", "image/jpg"},
|
||||
{".jpeg", "image/jpeg"},
|
||||
{".png", "image/png"},
|
||||
{".ico", "image/ico"},
|
||||
{".zip", "image/zip"},
|
||||
{".gz", "image/gz"},
|
||||
{".tar", "image/tar"},
|
||||
{".htm", "text/html"},
|
||||
{".html", "text/html"},
|
||||
{0, 0} // 结束标志
|
||||
};
|
||||
|
||||
/* 调试模式宏定义 */
|
||||
#ifdef DEBUG
|
||||
#define printf2(format, var) printf(format,var)
|
||||
#define printf3(format,var1,var2) printf(format,var1,var2)
|
||||
#else
|
||||
#define printf2(format, var)
|
||||
#define printf3(format,var1,var2)
|
||||
#endif
|
||||
|
||||
/* 全局变量说明 */
|
||||
|
||||
|
||||
/* Ctrl+C信号处理函数 */
|
||||
void ctrlc_handler(int sig)
|
||||
{
|
||||
printf("您按下了Ctrl+C终止了Web服务器\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* 主函数:监听端口并处理客户端连接 */
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int listen_sock, conn_sock, port;
|
||||
int hit; // 请求计数器
|
||||
socklen_t clientlen;
|
||||
struct sockaddr_in clientaddr;
|
||||
|
||||
/* 检查命令行参数 */
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "用法: %s <端口号>\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
port = atoi(argv[1]);
|
||||
|
||||
listen_sock = open_listen_sock(port);
|
||||
for (hit=1; ; hit++) { //hit为第几次请求,或第几次http事务
|
||||
clientlen = sizeof(clientaddr);
|
||||
conn_sock = accept(listen_sock, (SA *)&clientaddr, &clientlen);
|
||||
process_trans(conn_sock,hit); // 处理HTTP事务
|
||||
close(conn_sock);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* 处理HTTP事务的核心函数 */
|
||||
void process_trans(int fd,int hit)
|
||||
{
|
||||
int static_flag; // 是否为静态资源标志
|
||||
struct stat sbuf; // 文件状态信息
|
||||
char buf[MAXLINE], method[MAXLINE], uri[MAXLINE], version[MAXLINE];
|
||||
char filename[MAXLINE], cgiargs[MAXLINE];
|
||||
rio_t rio;
|
||||
int rhn=0; // 请求头计数器
|
||||
|
||||
/* 设置Ctrl+C信号处理 */
|
||||
if(signal(SIGINT,ctrlc_handler)==SIG_ERR)
|
||||
(void)printf("错误: 无法设置SIGINT信号处理\n");
|
||||
|
||||
printf2("第%d次请求开始\n",hit);
|
||||
|
||||
/* 读取请求行和请求头 */
|
||||
rio_readinitb(&rio, fd);
|
||||
rio_readlineb(&rio, buf, MAXLINE);
|
||||
printf3("请求头%d:%s", ++rhn, buf);
|
||||
|
||||
sscanf(buf, "%s %s %s", method, uri, version);
|
||||
if (strcasecmp(method, "GET")) { // 仅支持GET方法
|
||||
error_request(fd, method, "501", "未实现",
|
||||
"本服务器不支持该请求方法");
|
||||
return;
|
||||
}
|
||||
read_requesthdrs(&rio,hit,rhn); // 读取剩余请求头
|
||||
|
||||
static_flag = is_static(uri); // 判断资源类型
|
||||
if(static_flag)
|
||||
parse_static_uri(uri, filename); // 解析静态资源路径
|
||||
else
|
||||
parse_dynamic_uri(uri, filename, cgiargs); // 解析动态资源路径和参数
|
||||
|
||||
/* 检查文件是否存在及权限 */
|
||||
if (stat(filename, &sbuf) < 0) {
|
||||
error_request(fd, filename, "404", "未找到",
|
||||
"服务器无法找到该文件");
|
||||
return;
|
||||
}
|
||||
|
||||
/* 根据资源类型发送响应 */
|
||||
if (static_flag) { // 静态资源处理
|
||||
if (!(S_ISREG(sbuf.st_mode)) || !(S_IRUSR & sbuf.st_mode)) {
|
||||
error_request(fd, filename, "403", "禁止访问",
|
||||
"服务器无权读取该文件");
|
||||
return;
|
||||
}
|
||||
feed_static(fd, filename, sbuf.st_size); // 发送静态文件内容
|
||||
}
|
||||
else { // 动态资源处理
|
||||
if (!(S_ISREG(sbuf.st_mode)) || !(S_IXUSR & sbuf.st_mode)) {
|
||||
error_request(fd, filename, "403", "禁止访问",
|
||||
"服务器无法执行该CGI程序");
|
||||
return;
|
||||
}
|
||||
feed_dynamic(fd, filename, cgiargs); // 执行CGI程序并发送输出
|
||||
}
|
||||
}
|
||||
|
||||
/* 判断URI是否对应静态资源 */
|
||||
int is_static(char *uri)
|
||||
{
|
||||
return strstr(uri, "cgi-bin") == NULL; // 不含cgi-bin则为静态资源
|
||||
}
|
||||
|
||||
/* 构造HTTP错误响应 */
|
||||
void error_request(int fd, char *cause, char *errnum,
|
||||
char *shortmsg, char *description)
|
||||
{
|
||||
char buf[MAXLINE], body[MAXBUF];
|
||||
|
||||
/* 构建错误页面内容 */
|
||||
sprintf(body, "<html><title>错误请求</title>");
|
||||
sprintf(body, "%s<body bgcolor=\"#ffffff\">\r\n", body);
|
||||
sprintf(body, "%s<h1>%s %s</h1>\r\n", body, errnum, shortmsg);
|
||||
sprintf(body, "%s<p>%s: %s</p>\r\n", body, description, cause);
|
||||
sprintf(body, "%s<hr><em>weblet Web服务器</em>\r\n", body);
|
||||
|
||||
/* 发送HTTP响应头 */
|
||||
sprintf(buf, "HTTP/1.0 %s %s\r\n", errnum, shortmsg);
|
||||
rio_writen(fd, buf, strlen(buf));
|
||||
sprintf(buf, "Content-type: text/html\r\n");
|
||||
rio_writen(fd, buf, strlen(buf));
|
||||
sprintf(buf, "Content-length: %d\r\n\r\n", (int)strlen(body));
|
||||
rio_writen(fd, buf, strlen(buf));
|
||||
|
||||
/* 发送错误页面内容 */
|
||||
rio_writen(fd, body, strlen(body));
|
||||
}
|
||||
|
||||
/* 读取请求头直到空行 */
|
||||
void read_requesthdrs(rio_t *rp,int hit, int rhn)
|
||||
{
|
||||
char buf[MAXLINE];
|
||||
rio_readlineb(rp, buf, MAXLINE);
|
||||
while(strcmp(buf, "\r\n")) {
|
||||
printf3("请求头%d:%s", ++rhn, buf);
|
||||
rio_readlineb(rp, buf, MAXLINE);
|
||||
}
|
||||
printf2("第%d次请求结束\n\n",hit);
|
||||
}
|
||||
|
||||
/* 解析静态资源URI到文件路径 */
|
||||
void parse_static_uri(char *uri, char *filename)
|
||||
{
|
||||
strcpy(filename, ".");
|
||||
strcat(filename, uri);
|
||||
if (uri[strlen(uri)-1] == '/')
|
||||
strcat(filename, "index.html"); // 默认返回index.html
|
||||
}
|
||||
|
||||
/* 解析动态资源URI到文件路径和参数 */
|
||||
void parse_dynamic_uri(char *uri, char *filename, char *cgiargs)
|
||||
{
|
||||
char *ptr = index(uri, '?');
|
||||
if (ptr) {
|
||||
strcpy(cgiargs, ptr+1); // 提取参数部分请求头
|
||||
*ptr = '\0'; // 截断URI
|
||||
} else {
|
||||
strcpy(cgiargs, "");
|
||||
}
|
||||
strcpy(filename, ".");
|
||||
strcat(filename, uri);
|
||||
}
|
||||
|
||||
/* 发送静态文件内容 */
|
||||
void feed_static(int fd, char *filename, int filesize)
|
||||
{
|
||||
int srcfd;
|
||||
char *srcp, filetype[MAXLINE], buf[MAXBUF];
|
||||
|
||||
/* 发送HTTP响应头 */
|
||||
get_filetype(filename, filetype);
|
||||
sprintf(buf, "HTTP/1.0 200 OK\r\n");
|
||||
sprintf(buf, "%sServer: weblet Web Server\r\n", buf);
|
||||
sprintf(buf, "%sContent-length: %d\r\n", buf, filesize);
|
||||
sprintf(buf, "%sContent-type: %s\r\n\r\n", buf, filetype);
|
||||
rio_writen(fd, buf, strlen(buf));
|
||||
|
||||
/* 发送文件内容 */
|
||||
srcfd = open(filename, O_RDONLY, 0);
|
||||
srcp = mmap(0, filesize, PROT_READ, MAP_PRIVATE, srcfd, 0);
|
||||
close(srcfd);
|
||||
rio_writen(fd, srcp, filesize);
|
||||
munmap(srcp, filesize);
|
||||
}
|
||||
|
||||
/* 根据文件扩展名获取MIME类型 */
|
||||
void get_filetype(char *filename, char *filetype)
|
||||
{
|
||||
int i, len;
|
||||
strcpy(filetype, "text/html"); // 默认类型
|
||||
for (i = 0; extensions[i].ext != 0; i++) {
|
||||
len = strlen(extensions[i].ext);
|
||||
if (!strcmp(&filename[strlen(filename)-len], extensions[i].ext)) {
|
||||
strcpy(filetype, extensions[i].filetype);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 启动子进程执行CGI程序 */
|
||||
void feed_dynamic(int fd, char *filename, char *cgiargs)
|
||||
{
|
||||
char buf[MAXLINE], *emptylist[] = { NULL };
|
||||
int pfd[2];
|
||||
|
||||
/* 构造HTTP响应头 */
|
||||
sprintf(buf, "HTTP/1.0 200 OK\r\n");
|
||||
rio_writen(fd, buf, strlen(buf));
|
||||
sprintf(buf, "Server: weblet Web Server\r\n");
|
||||
rio_writen(fd, buf, strlen(buf));
|
||||
|
||||
/* 创建管道并启动子进程 */
|
||||
(void)pipe(pfd);
|
||||
if (fork() == 0) { // 子进程
|
||||
close(pfd[1]); // 关闭写端
|
||||
dup2(pfd[0], STDIN_FILENO); // 重定向标准输入
|
||||
dup2(fd, STDOUT_FILENO); // 重定向标准输出到客户端
|
||||
execve(filename, emptylist, environ); // 执行CGI程序
|
||||
}
|
||||
|
||||
close(pfd[0]); // 父进程关闭读端
|
||||
(void)write(pfd[1], cgiargs, strlen(cgiargs)+1); // 传递参数
|
||||
wait(NULL); // 等待子进程结束
|
||||
close(pfd[1]); // 关闭写端
|
||||
}
|
||||
19
server-exp2/实验二文件清单.txt
Normal file
19
server-exp2/实验二文件清单.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
common.h : 公共头文件、函数声明、常量定义等(由教材wrapper.h简化而来)
|
||||
common.c : RIO函数库和打开网络连接函数源代码(教材中libwrapper.c简化而来)
|
||||
webclient.c: web客户端源代码(《操作系统实验教程》第1章的client.c)
|
||||
webserver.c: web服务器源代码(即教材《Linux编程》第8章的weblet.c)
|
||||
togglec.c : toggle客户端源代码(教材第8章源代码)
|
||||
togglesi.c : 迭代式toggle服务器源代码(教材《Linux编程》第8章源代码)
|
||||
togglesp.c : 多进程toggle服务器源代码(教材《Linux编程》第9章源代码)
|
||||
togglest.c : 多线程toggle服务器源代码(教材《Linux编程》第9章源代码)
|
||||
togglest_pre.c : 预线程toggle服务器源代码(教材《Linux编程》第9章源代码)
|
||||
togglest_pool.c : 线程池toggle服务器源代码
|
||||
./cgi-bin/add.c: 生成动态网页的cgi程序(教材《Linux编程》第8章)
|
||||
Makefile: 目标和源代码间相互依赖关系文件(参考教材《Linux编程》第3章)
|
||||
index.html: 缺省网页文件
|
||||
example.jpg: 网页文件index.html中内嵌的图片
|
||||
favicon.ico: index.html中内嵌的图标
|
||||
test.html: 第2个测试用网页
|
||||
urls: 记录运行http_load执行时,访问哪些网址
|
||||
|
||||
|
||||
Reference in New Issue
Block a user