4.实现一个简单的httpserver,仅支持get
#include <sys/socket.h>
#include <unistd.h>
#include <errno.h>
#include <netinet/in.h>
#include <string.h>
#include <stdio.h>
#define BUF_LEN 1028
#define SERVER_PORT 8080
const static char http_error_hdr[] = "HTTP/1.1 404 Not Found\r\nContent-type: text/html\r\n\r\n";
const static char http_html_hdr[] = "HTTP/1.1 200 OK\r\nContent-type: text/html\r\n\r\n";
const static char http_html_index[] =
"<html><head><title>Congrats!</title></head>"
"<body><h1>Welcome to our HTTP server !</h1>"
"<p>This is a test page.</body></html>";
/* step to socket programming:
*
* 1. call socket(int family, int type, int protocol), set I/O protocol : IPv4TCP/IPv6UDP/..
* family: type: protocol:
* AF_INET: IPv4 SOCK_STREAM: byte stream IPPROTO_CP: TCP
* AF_INET6: IPv6 SOCK_DGREAM: data gram IPPROTO_UDP: UDP
* AF_LOCAL: unix ... IPPROTO_SCTP: SCTP
* return sockfd : socket descriptor
*
* 2. bind() assgin a local protocol address to an unamed socket
*
* 3. listen(int sockfd, int backlog) called by server
* backlog deciede the size of queue.
* it has two queue: incomplete connection queue/ completed connection queue
*
* 4. accept()
*/
int http_send_file(char* filename, int sockfd)
{
if (!strcmp(filename, "/")) {
write(sockfd, http_html_hdr, strlen(http_html_hdr));
write(sockfd, http_html_index, strlen(http_html_index));
}
else {
printf("%s: file not find!\n", filename);
write(sockfd, http_error_hdr, strlen(http_html_hdr));
}
return 0;
}
// HTTP analyse request
void analyse(int sockfd)
{
char buf[BUF_LEN];
read(sockfd, buf, BUF_LEN);
if (!strncmp(buf, "GET", 3)) {
char *file = buf + 4;
char *space = strchr(file, ' ');
*space = '\0';
http_send_file(file, sockfd);
}
else {
printf("unsupported request!\n");
}
}
int main()
{
int sockfd, err, newfd; // socket descripe
struct sockaddr_in addr;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("socket creation failed!\n");
return -1;
}
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
// host to net work long
addr.sin_port = htons(SERVER_PORT);
addr.sin_addr.s_addr = INADDR_ANY;
if (bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in))) {
perror("socket binding failed!\n");
return -1;
}
listen(sockfd,128);
for (;;) {
newfd = accept(sockfd, NULL, NULL);
analyse(newfd);
close(newfd);
}
}
5.用fork()实现并发的服务器
unistd.h提供的fork()函数可以简单地将原来的单线程单进程阻塞的server改为多进程的server
fork()函数的特点在于,调用一次,它会返回两次,在子进程返回0,父进程返回子进程id,出错返回-1
if (pid = fork() < 0) {
perror("error");
}
else if (pid == 0) {
//childprocess do;
}
else {
//parentprocess do;
}
这样的一个结构就可以帮助我们实现一个简单的多进程并发server
#include <sys/socket.h>
#include <unistd.h>
#include <errno.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define BUF_LEN 1024
#define Q_LEN 128
#define SERVER_PORT 8080
const static char http_error_hdr[] = "HTTP/1.1 404 Not Found\r\nContent-type: text/html\r\n\r\n";
const static char http_html_hdr[] = "HTTP/1.1 200 OK\r\nContent-type: text/html\r\n\r\n";
const static char http_html_index[] =
"<html><head><title>Congrats!</title></head>"
"<body><h1>Welcome to our HTTP server !</h1>"
"<p>This is a test page.</body></html>";
int http_send_file(char* filename, int sockfd)
{
if (!strcmp(filename, "/")) {
write(sockfd, http_html_hdr, strlen(http_html_hdr));
write(sockfd, http_html_index, strlen(http_html_index));
}
else {
printf("%s: file not find!\n", filename);
write(sockfd, http_error_hdr, strlen(http_html_hdr));
}
return 0;
}
// HTTP analyse request
void analyse(int sockfd)
{
char buf[BUF_LEN];
read(sockfd, buf, BUF_LEN);
if (!strncmp(buf, "GET", 3)) {
char *file = buf + 4;
char *space = strchr(file, ' ');
*space = '\0';
http_send_file(file, sockfd);
}
else {
printf("unsupported request!\n");
}
}
int main(int argc, char **argv)
{
int listenfd, connfd;
pid_t childpid;
socklen_t clilen;
struct sockaddr_in cliaddr, servaddr;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
if (listenfd < 0) {
perror("socket creation failed!\n");
return -1;
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_port = htons(SERVER_PORT);
if (bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr))) {
perror("socket bindinf failed!\n");
return -1;
}
listen(listenfd, Q_LEN);
for ( ; ; ) {
clilen = sizeof(cliaddr);
connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen);
if (connfd < 0) {
perror("scoket accept failed!\n");
}
if ( (childpid = fork()) == 0) {
close(listenfd);
analyse(connfd);
exit(0);
}
close(connfd);
}
}