HTTP协议

项目要用到通信协议,强行学习了一波HTTP协议

报文格式

请求格式

HTTP请求由状态行、请求头、请求正文三部分组成:

  • 状态行:包括请求方式Method、资源路径URL、协议版本Version;
  • 请求头:包括一些访问的域名、用户代理、Cookie等信息;
  • 请求正文:就是HTTP请求的数据。

请求方式Method一般有GET、POST、PUT、DELETE,含义分别是获取、修改、上传、删除,其中GET方式仅仅为获取服务器资源,方式较为简单,因此在请求方式为GET的HTTP请求数据中,请求正文部分可以省略,直接将想要获取的资源添加到URL中。


图片.png
图片.png

上面这张图是Fiddle捕获的一个实际请求报文,它清晰的展示了HTTP 消息的结构。详情如下:

  • 请求行:即第一排用空格分割成的三个小块,分别对应请求方法、请求URL、HTTP协议版本三个部分。
  • 请求头:从第二行开始到倒数第二行都是我们的请求头(headers)。
  • 消息主体:截图的最后一行是请求体,也就是我们要发送的数据的主体,消息主体(entity-body)。
  • 也就是说一个正常的post请求主要由请求行,请求头,消息主体组成。接下来我们来了解一下什么是Content-Type。

Content-Type的格式种类

四种最常用的编码方式,基本上形成了相应的规范,即基本固定的Content-Type取值application/x-www-form-urlencoded(默认格式)、application/json、text/xml、multipart/form-data,与默认传递的urlencoded、json格式、xml格式、文件格式一 一对应。

应答格式

HTTP响应由三部分组成:状态行、响应头、响应正文;

  • 状态行:包括协议版本Version、状态码Status Code、回应短语;
  • 响应头:包括搭建服务器的软件,发送响应的时间,回应数据的格式等信息;
  • 响应正文:就是响应的具体数据


    图片.png

使用轮子

Python Requests 快速上手
https://2.python-requests.org//zh_CN/latest/user/quickstart.html
Python实现简单HTTP服务器
https://www.cnblogs.com/xinyangsdut/p/9099623.html
Python Http Post请求四种请求体的Python实现
https://www.cnblogs.com/Detector/p/9404391.html

使用socket创建简单的客户端和服务端

客户端

client.py

# -*- coding: utf-8 -*-
"""
Created on Fri Jul  5 17:00:36 2019

@author: Administrator
"""

import socket 

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 连接服务端
s.connect(('127.0.0.1', 9999))

# 请求 | 发送数据到服务端
s.sendall(b'hello')

# 响应 | 接受服务端返回到数据
data = s.recv(1024)

print(data) # hello

# 关闭 socket
s.close()

服务端

# -*- coding: utf-8 -*-
"""
Spyder Editor

This is a temporary script file.
"""

import socket 

# socket.AF_INET (IPV4)
# socket.SOCK_STREAM (TCP)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 监听 IP:port
s.bind(('127.0.0.1', 9999))

# 最大允许连接数量
s.listen(3)

# 死循环,重复的处理着每个客户端的请求
while True:

# 阻塞 每当有客户端的请求过来开始执行
# 连接处理 (已完成三次握手)并获取资源对象 | conn 请求对象 | addr 客户端地址 ip: port
conn, addr = s.accept() 

# 请求处理 | 读取客户端发送过来的数据 | recv(1024) 指定每次读取 1024 字节,当数据较长时可以通过 while 循环读取
data = conn.recv(1024).decode('utf-8')

# 响应处理 | 把客服端发送过来的数据又转发回去
conn.sendall(data.encode('utf-8'))

# 关闭客户端连接
conn.close()

HTTP服务端

# -*- coding: utf-8 -*-
"""
Created on Mon Jul  8 09:02:54 2019

@author: Administrator
"""

# coding:utf-8

import socket
import json

from multiprocessing import Process

def handle_client(client_socket):
    """
    处理客户端请求
    """
    request_data = client_socket.recv(1024)
    print("request data:", request_data)
    # 构造响应数据
    response_start_line = "HTTP/1.1 200 OK\r\n"
    response_headers = "Server: My server\r\n"
    response_body = "<h1>Python HTTP Test</h1>"
    datas={"param1": "Detector", "param2": "cnblogs"}
    response = response_start_line + response_headers + "\r\n" + datas

    # 向客户端返回响应数据
    client_socket.send(bytes(response, "utf-8"))

    # 关闭客户端连接
    client_socket.close()


if __name__ == "__main__":
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.bind(("", 8000))
    server_socket.listen(128)
    

    while True:
        client_socket, client_address = server_socket.accept()
        
        print("[%s, %s]用户连接上了" % client_address)
        handle_client_process = Process(target=handle_client, args=(client_socket,))
        handle_client_process.start()
        client_socket.close()

C端TCP/IP 服务器

#include<iostream>
#include<winsock.h>
#pragma comment(lib,"ws2_32.lib")
using namespace std;
void initialization();
int server() {
    //定义长度变量
    int send_len = 0;
    int recv_len = 0;
    int len = 0;
    //定义发送缓冲区和接受缓冲区
    char send_buf[100];
    char recv_buf[100];
    memset(send_buf, 0, sizeof(send_buf));
    memset(recv_buf, 0, sizeof(recv_buf));
    //定义服务端套接字,接受请求套接字
    SOCKET s_server;
    SOCKET s_accept;
    //服务端地址客户端地址
    SOCKADDR_IN server_addr;
    SOCKADDR_IN accept_addr;
    initialization();
    //填充服务端信息
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(8001);
    //创建套接字
    s_server = socket(AF_INET, SOCK_STREAM, 0);
    if (bind(s_server, (SOCKADDR *)&server_addr, sizeof(SOCKADDR)) == SOCKET_ERROR) {
        cout << "bing faild!" << endl;
        WSACleanup();
    }
    else {
        cout << "bing success!" << endl;
    }
    //设置套接字为监听状态
    if (listen(s_server, SOMAXCONN) < 0) {
        cout << "listen faild!" << endl;
        WSACleanup();
    }
    else {
        cout << "listen success!" << endl;
    }
    cout << "listening...." << endl;
    //接受连接请求
    len = sizeof(SOCKADDR);
    s_accept = accept(s_server, (SOCKADDR *)&accept_addr, &len);
    if (s_accept == SOCKET_ERROR) {
        cout << "listen faild!" << endl;
        WSACleanup();
        return 0;
    }
    cout << "connect..." << endl;
    //接收数据
    while (1) {
        recv_len = recv(s_accept, recv_buf, 1, 0);
        if (recv_len <= 0) {
            cout << "rec failed!" << endl;
            break;
        }
        else {
            cout << "client:" << recv_buf << endl;
        }
        /*cout << "please cin:";
        cin >> send_buf;*/
        //send_len = send(s_accept, send_buf, 100, 0);
        //if (send_len < 0) {
        //  cout << "send failed!" << endl;
        //  break;
        //}
    }
    //关闭套接字
    closesocket(s_server);
    closesocket(s_accept);
    //释放DLL资源
    WSACleanup();
    return 0;
}

void initialization() {
    //初始化套接字库
    WORD w_req = MAKEWORD(2, 2);//版本号
    WSADATA wsadata;
    int err;
    err = WSAStartup(w_req, &wsadata);
    if (err != 0) {
        cout << "init faied!" << endl;
    }
    else {
        cout << "init success!" << endl;
    }
    //检测版本号
    if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wHighVersion) != 2) {
        cout << "version error!" << endl;
        WSACleanup();
    }
    else {
        cout << "version right!" << endl;
    }
    //填充服务端地址信息

}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 161,326评论 4 369
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,228评论 1 304
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,979评论 0 252
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,489评论 0 217
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,894评论 3 294
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,900评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,075评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,803评论 0 205
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,565评论 1 249
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,778评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,255评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,582评论 3 261
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,254评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,151评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,952评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,035评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,839评论 2 277

推荐阅读更多精彩内容