学习爬虫顺便学习一下

网络请求的过程

image-20200214224200793

IP地址和url

动态ip和静态ip的问题

动态ip,对外是不固定的,定时收回更换,同时在家中布置服务器也不现实

静态ip,花钱买呗

url协议

url即资源地址

模板:http://www.example.com:80/path/to/xxx.html?key1=www&key2=333#chap

常用协议:http https file ftp

TCP/IP协议

TCP

是一种面向连接的、可靠的、基于字节流的传输层通信协议。

在协议族中位于IP层之上,应用层之下,负责处理数据流,处理丢包等情况。相当于一个中间者

TCP的三次握手连接(three-way handshake)

Connection_TCP

ps:SYN(建立连接), ACK(响应) == 数据包 (SYN攻击也是DDoS的一种, 消耗CPU和内存)

流程:Client 向 Server 发送一个 SYN 来创建一个主动打开,Client 把这段连接的序号设为随机数 A ,然后 Server 为合法的 SYN 传回一个 SYN/ACK ,其中 ACK 的确认码为 A+1, SYN/ACK 包序号为随机数 B , 最后 Client 发送 ACK , 序号为 A+1 ,确认码为 B+1 ,Server 收到后就建立连接了,这两发一回就被称为三次握手

TCP的四次握(抛)手断开(four-way handshake)

Deconnection_TCP

ps:FIN(关闭连接)

在这个过程中连接的每一侧都独立地被终止。当一个端点要停止它这一侧的连接,就向对侧发送FIN,对侧回复ACK表示确认。因此,拆掉一侧的连接过程需要一对FIN和ACK,分别由两侧端点发出。

首先发出FIN的一侧,如果给对侧的FIN响应了ACK,那么就会超时等待2*MSL时间,然后关闭连接。在这段超时等待时间内,本地的端口不能被新连接使用;避免延时的包的到达与随后的新连接相混淆。RFC793定义了MSL为2分钟,Linux设置成了30s。参数tcp_max_tw_buckets控制并发的TIME_WAIT的数量,默认值是180000,如果超限,那么,系统会把多的TIME_WAIT状态的连接给destory掉,然后在日志里打一个警告(如:time wait bucket table overflow)

Socket

套接字,把复杂的TCP/IP协议藏在接口之后

image-20200214233500573

介绍:socket_client 和 socket_server

socket_server

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import socket
import threading

# server = socket.socket()
# server.bind(('0.0.0.0', 8000))
# server.listen()

# sock, addr = server.accept()
# data = ""
# while True:
# sock.send("welcome!".encode('utf8'))
# tmp_data = sock.recv(1024)
# print(tmp_data.decode('utf8'))
# input_data = input()
# sock.send(input_data.encode('utf8'))
# if tmp_data:
# data += tmp_data.decode("utf8")
# if tmp_data.decode('utf8').endswith('#'):
# break
# else:
# break

# print(data)
# socket.close()

def handle_sock(sock, addr):
tmp_data = sock.recv(1024)
print(tmp_data.decode('utf8'))
input_data = input()
sock.send(input_data.encode('utf8'))


server = socket.socket()
server.bind(('0.0.0.0', 8000))
server.listen()

while True:
sock, addr = server.accept()# 返回的是一个tuple
# 多线程语法
client_thread = threading.Thread(target=handle_sock, args=(sock, addr))
client_thread.start()

socket_client

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import socket
import threading

# client = socket.socket()
# client.connect(('127.0.0.1', 8000))
# # client.send("aaa")
# client.send("boddy".encode("utf8"))
# client.close()

client = socket.socket()
client.connect(('127.0.0.1', 8000))
while True:
input_data = input()
client.send(input_data.encode('utf8'))
server_data = client.recv(1024)
print("server response: {}".format(server_data.decode('utf8')))

client.close()

应用: qq_client 和 qq_server

qq_server

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# 转发消息
# 处理登录
# 处理退出
# 维护历史消息, 维护在线用户和维护用户的连接

import socket
from collections import defaultdict
import threading
import json
# defaultdic 和 dict 的区别, 前者在为值空时会新建

# 1. 维护用户连接
online_users = defaultdict(dict)

# 2. 维护历史消息
user_msgs = defaultdict(list)
server = socket.socket()

# 绑定ip
server.bind(('0.0.0.0', 8000))
server.listen()


def handle_sock(sock, addr):
while True:
data = sock.recv(1024)
json_data = json.loads(data.decode('utf8'))
action = json_data.get('action', '')
if action == "login":
online_users[json_data['user']] = sock
sock.send("登录成功".encode('utf8'))
elif action == "list_user":
# 获取当前用户
all_users = [user for user, sock in online_users.items()]
sock.send(json.dumps(all_users).encode('utf8'))
elif action == 'history_msg':
sock.send(json.dumps(user_msgs.get(json_data['user'], [])).encode('utf8'))
elif action == 'send_msg':
if json_data["to"] in online_users:
online_users[json_data["to"]].send(json.dumps(json_data).encode('utf8'))
user_msgs[json_data["to"]].append(json_data)
elif action == "exit":
del online_users[json_data['user']]
sock.send("退出成功".encode("utf8"))



while True:
# 阻塞等待连接
sock, addr = server.accept()
client_thread = threading.Thread(target=handle_sock, args=(sock, addr))
client_thread.start()

qq_client

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import socket
import json
import threading

client = socket.socket()
client.connect(('192.168.101.15', 8000))

def client_send(msg):
client.send(json.dumps(msg).encode("utf8"))


user = "zrzz"

# 1. 登录
login_template = {
"action": "login",
"user": user,
}

client_send(login_template)
res = client.recv(1024)
print(res.decode('utf8'))

# 2. 获取在线用户
get_user_template = {
"action": "list_user"
}

client_send(get_user_template)
res = client.recv(1024)
print("当前在线用户: {}".format(res.decode('utf8')))

# 3.获取历史消息
offline_msg_template = {
"action": "history_msg",
"user": user
}

client_send(offline_msg_template)
res = client.recv(1024)
print("历史消息: {}".format(res.decode('utf8')))

tuichu = False


def handle_receive():
# 处理接收请求
while True:
if not tuichu:
try:
res = client.recv(1024)
except:
break
res = res.decode("utf8")
try:
res_json = json.loads(res)
if type(res_json) != list:
msg = res_json["data"]
from_user = res_json["from"]
print("受到来自({})的消息: {}".format(from_user, msg))
else:
print(res_json)
except:
print("res")
else:
break


def handle_send():
while True:
# 随时能够收发消息
op_type = input("请输入你要进行的操作: 1. 发送消息, 2. 退出, 3. 获取在线用户\n")
if op_type not in ["1", "2", "3"]:
print("不支持该操作")
elif op_type == "1":
to_user = input("请输入你要发送的用户: ")
msg = input("请输入你要发送的消息: ")
send_data_template = {
"action": "send_msg",
"to": to_user,
"from": user,
"data": msg
}
client_send(send_data_template)
elif op_type == "2":
exit_template = {
"action": "exit",
"user": user
}
client_send(exit_template)
client.close()
tuichu = True
break
elif op_type == "3":
get_user_template = {
"action": "list_user"
}
client_send(get_user_template)


if __name__ == "__main__":
send_thread = threading.Thread(target=handle_send)
receive_thread = threading.Thread(target=handle_receive)
send_thread.start()
receive_thread.start()

HTTP协议

image-20200214234443783