京东秒杀
国美-超级5
索尼Xperia旗舰
限时优惠页 - 京东
自营热卖

协议(初识HTTP协议)

山川唱晚 27天前   阅读数 34 0

1协议

1.1结构化数据

协议是一种 “约定”. socket api的接口, 在读写数据时, 都是按 “字符串” 的方式来发送接收的. 如果我们要传输一些"结构化的数据" 怎么办呢?

结构化的数据:比如发送微信消息,消息的组合由时间,发送人等信息

序列化:发送信息的时候、需要将信息多变一
反序列化:接收信息、将信息一变多

2网络版计算器

例如, 我们需要实现一个服务器版的加法器. 我们需要客户端把要计算的两个加数发过去, 然后由服务器进行计算, 最后再把结果返回给客户端。

约定方案:

  • 定义结构体来表示我们需要交互的信息;
  • 发送数据时将这个结构体按照一个规则转换成字符串, 接收到数据的时候再按照相同的规则把字符串转化回结构体;
  • 这个过程叫做 “序列化” 和 "反序列化

这种约定, 就是 应用层协议

//Protocol.hpp:
#ifndef __PROTOCOL_HPP_ 
#define __PROTOCOL_HPP_ 

#include <iostream>
//用结构体定的协议
typedef struct request
{
     
  int x;
  int y;
  char op;
}request_t;

typedef struct response
{
     
  int result;
  int code;
}response_t;

#endif 

#ifndef _SERVER_HPP_
#define _SERVER_HPP_ 

#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cstdlib>
#include <sys/wait.h>
#include "Protocol.hpp"

class server 
{
     
  private:
    int port;
    int lsock;
  public:
    server(int _port):port(_port),lsock(-1)
    {
     }

    void initServer()
    {
     
      //创建套接字
      lsock = socket(AF_INET, SOCK_STREAM, 0);
      if(lsock < 0)
      {
     
        std::cerr << "socket error" << std::endl;
        exit(2);
      }
      
      //服务器绑定,填充服务器信息
      struct sockaddr_in local;
      local.sin_family = AF_INET;
      local.sin_port = htons(port);
      local.sin_addr.s_addr = htonl(INADDR_ANY);

      if(bind(lsock, (struct sockaddr*)&local, sizeof(local)) < 0)//传到inet_sock
      {
     
        std::cerr << "bind error! " << std::endl;
        exit(3);
      }
      
	  //监听套接字
      if(listen(lsock, 5) < 0)
      {
     
        std::cerr << "listen error!" << std::endl;
        //exit(4); 
      }
    }
      
    void cal(int sock)
    {
     
      //短链接来完成计算
      request_t rq;
      response_t rsp = {
     4, 0};
      ssize_t s = recv(sock, &rq, sizeof(rq), 0);//BUG
      if(s > 0)
      {
     
        switch(rq.op)
        {
     
          case '+':
            rsp.result = rq.x + rq.y;
            break;
          case '-':
            rsp.result = rq.x - rq.y;
            break;
          case '*':
            rsp.result = rq.x * rq.y;
            break;
          case '/':
            if(rq.y != 0)
            {
     
              rsp.result = rq.x / rq.y;
            }
            else 
            {
     
              rsp.code = 1;
            }
            break;
          case '%':
            if(rq.y != 0)
            {
     
              rsp.result = rq.x % rq.y;
            }
            else 
            {
     
              rsp.code = 2;
            }
            break;
          default:
            rsp.code = 3;
            break;
        }
      }
      
      send(sock, &rsp, sizeof(rsp), 0);
      close(sock);
    }

    void start()
    {
     
      struct sockaddr_in peer;
      for(;;)
      {
     
        socklen_t len = sizeof(len);
        int sock = accept(lsock, (struct sockaddr*)&peer, &len);
        if(sock < 0)
        {
     
          std::cerr << "accept error!" << std::endl;
          continue;
        }

        if(fork() == 0)
        {
     
          if(fork() > 0)//子进程
          {
     
            exit(0);
          }
          //孙子
          close(lsock);
          
          //具体服务
          cal(sock);
          
          exit(0);//短链接、调用完就退出
        }

        //父进程
        close(sock);
        waitpid(-1, nullptr, 0);//等待任意子进程
      }
    }

    ~server()
    {
     
      close(lsock);
    }
};

#endif 

#include "Server.hpp"

void Menu(std::string proc)
{
     
  std::cout << "Usage: \n\t";
  std::cout << proc << "svr_ip svr_port" << std::endl;
}

int main(int argc, char *argv[])
{
     
  if(argc != 2)
  {
     
    Menu(argv[0]);
    exit(1);
  }

  server *sp = new server(atoi(argv[1])); 
  sp->initServer();
  sp->start();
  
  delete sp;
  return 0;
}

#ifndef _CLIENT_HPP_
#define _CLIENT_HPP_ 

#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cstdlib>
#include <sys/wait.h>
#include "Protocol.hpp"

class client 
{
     
  private:
    int port;
    int sock;
    std::string ip;
  public:
    client(std::string _ip, int _port):ip(_ip),port(_port),sock(-1)
    {
     }

    void initClient()
    {
     
      sock = socket(AF_INET, SOCK_STREAM, 0);
      if(sock < 0)
      {
     
        std::cerr << "socket error" << std::endl;
        exit(2);
      }
      
    }
      

    void start()
    {
     
      struct sockaddr_in server;
      server.sin_family = AF_INET;
      server.sin_port = htons(port);
      server.sin_addr.s_addr = inet_addr(ip.c_str());//字符串转成网络整形

      if(connect(sock, (struct sockaddr*)&server, sizeof(server)) < 0)
      {
     
        std::cerr << "cennect error!" << std::endl;
        exit(2);
      }
      
      response_t rsp;
      request_t rq;
      std::cout << "datax# "; 
      std::cin >> rq.x;
      std::cout << "datay# ";
      std::cin >> rq.y;
      std::cout << "op# ";
      std::cin >> rq.op;

      send(sock, &rq, sizeof(rq), 0);
      recv(sock, &rsp, sizeof(rsp), 0);

      std::cout << "code:" << rsp.code << std::endl;
      std::cout << "result: " << rsp.result << std::endl;
    }

    ~client()
    {
     
      close(sock);
    }
};
#endif 

#include "Client.hpp"

void Menu(std::string proc)
{
     
  std::cout << "Usage: \n\t";
  std::cout << proc << "svr_ip svr_port" << std::endl;
}

int main(int argc, char *argv[])
{
     
  if(argc != 3)
  {
     
    Menu(argv[0]);
    exit(1);
  }

  client *cp = new client(argv[1], atoi(argv[2])); 
  cp->initClient();
  cp->start();
  
  delete cp;
  return 0;
}

代码运行效果展示:
在这里插入图片描述

3.抓包工具

tcpdump:
作用:抓包 (传输层的协议基本都可以抓

tcpdump -i 指定sniffer操作的侦听端口,比如:tcpdump -i eth0 ,

tcpdump -i any(发送至这台主机的都要抓) 。
-n:主机名这些能显示成数字就显示成数字
-nn:将更多的信息显示成数字

在这里插入图片描述
在这里插入图片描述

4. HTTP协议

虽然说应用层协议是由我们程序猿自己定的,但实际上已经有大佬们定义了一些现成的, 又非常好用的应用层协议, 供我们直接使用。比如 HTTP(超文本传输协议)

4.1URL

我们平时说的 “网址” 其实就是说的 URL。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210525152057447.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl81MDg0Mzg2OA==,size_16,color_FFFFFF,t_70

?:后面叫做参数
互联网行为:

  1. 把服务器数据拿下来
  2. 把自己的数据传上服务器
    3.一般在搜索引擎中将搜索关键字拿到?后面
    在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

http:端口80 https:端口443


注意:本文归作者所有,未经作者允许,不得转载

全部评论: 0

    我有话说: