UNP 学习笔记2

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);
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值