网络编程--模拟HTTP服务器

下面是一个简单的例子,来模拟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);
}

结果截图

获取数据

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值