下面是一个简单的例子,来模拟HTTP服务器
这里只是简单的按照 HTTP 协议来构造数据
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
#include <arpa/inet.h>
//处理连接的请求响应
void connect_process(sockaddr_in addr , int new_socket)
{
(void)addr;
char read_buf[1024 * 10] = {0};
char buf[1024 * 10] = {0};
while(1)
{
//读取客户端请求
if((read(new_socket ,read_buf ,sizeof(read_buf)-1))<0)
{
perror("read");
}
else
{
printf("%s",read_buf);
printf("###################################\n");
//将客户端的请求报文打印出来
}
//此处不用关心对方发来的是什么请求
//只要要按照http响应报文格式回复过去
const char * body = "<html>\n<h1>love and peace</h1>\n</html>";
const char * first_line = "HTTP/1.1 200 OK";
const char * header_content_type = "Content-Type: text.html;charset=UTF-8";
//构造http响应报文
sprintf(buf,"%s\n%s\nContent-Length: %lu\n\n%s",first_line,header_content_type,strlen(body),body);
write(new_socket,buf,strlen(buf));
}
}
int main(int argc,char * argv[])
{
//判断命令行参数是否合法
if(argc != 3)
{
printf("Usage: ./server [IP] [Port]\n");
return 1;
}
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(argv[1]);
addr.sin_port = htons(atoi(argv[2]));
socklen_t addr_len = sizeof(addr);
//创建套接字
int fd = socket(AF_INET,SOCK_STREAM,0);
//绑定IP和端口号
int bind_ret = bind(fd,(sockaddr *)&addr,addr_len);
if(bind_ret < 0)
{
perror("bind");
return 2;
}
//使服务器处于监听状态
if(listen(fd,5) < 0 )
{
perror("listen");
return 3;
}
//服务器开始时间循环
while(1)
{
//服务器接收连接请求
int new_socket = accept(fd ,(sockaddr *)&addr,&addr_len);
if(new_socket < 0)
{
perror("accept");
continue;
}
pid_t pid = fork();
if(pid < 0)
{
perror("fork");
return 4;
}
if(pid == 0)
{
//在子进程的执行逻辑中,不用监听socket ,可以直接将其文件关闭
close(fd);
pid_t id = fork();
if(id < 0)
{
perror("fork");
return 5;
}
if(id > 0)
{//二代子进程
//为一个已经建立连接的用户提供服务
connect_process(addr , new_socket);
close(new_socket);
exit(0);
}
else
{ //一代子进程
//一代子进程直接退出,使二代子进程成为孤儿进程
//被一号进程收养,避免成为僵尸进程,造成内存泄漏
//并且直接退出,此处可以不用手动关闭文件
exit(0);
}
}
else
{//父进程
//在父进程的执行逻辑中,不用new_socket 必须要将其关闭
//因为父进程是一直在执行中,为了防止文件描述符泄漏
close(new_socket);
waitpid(pid,NULL,0);
}
}
close(fd);
}