1.网络编程基础
1.1OSI7层模型
物理层、数据链路层、网络层、传输层、会话层、表示层、应用层
1.2OSI5层模型
物理层、数据链路层、网络层、传输层、应用层
1.3传输层的协议
tcp协议:可靠的面向连接的全双工通信
udp协议:不可靠的无连接的通信
1.4网络层的协议
ipv4/ipv6协议
1.5数据链路层的协议
arp协议:地址解析协议,通过ip地址找mac地址。
1.6.三次握手和四次挥手(tcp协议)
三次握手
客户端向服务端发送syn信号
服务端接收syn信号并返回ack信号,同时发送syn信号
客户端接收syn信号并返回ack信号
四次挥手
客户端想服务端发送fin信号
服务端接收fin信号并返回ack信号
服务端发送完数据后向客户端发送fin信号
客户端接收fin信号并返回ack信号
2.socket模块
2.1最基础的客户端/服务端代码
服务端
import socket
sk = socket.socket() #类的实例化#创建一个sever端对象
sk.bind(('127.0.0.1',9000)) #元祖#给sever绑定一个地址和端口
sk.listen() #开始监听
conn,add = sk.accept() #建立连接
conn.send(b'hello')
msg = conn.recv(1024).decode('utf-8')
print(msg)
conn.close() #关闭连接
sk.close() #关闭服务
客户端
import socket
sk = socket.socket() #创建一个客户端对象
sk.connect(('127.0.0.1',9000)) #连接服务端
msg = sk.recv(1024).decode('utf-8')
print(msg)
sk.send(b'byebye')
sk.close() #关闭连接
2.2多人多次交互的服务端/客户端代码
服务端
import socket
sk = socket.socket()
sk.bind(('127.0.0.1',9000))
sk.listen()
while True:
conn,addr = sk.accept()
while True:
send_msg = input('>>>')
if send_msg.upper() == 'Q':
break
conn.send(send_msg.encode('utf-8'))
msg = conn.recv(1024).decode('utf-8')
if msg.upper() == 'Q':
break
print(msg)
conn.close()
print('服务端已断开连接')
sk.close()
客户端
import socket
sk = socket.socket()
sk.connect(('127.0.0.1',9000))
while True:
msg = sk.recv(1024).decode('utf-8')
if msg.upper() == 'Q':
break
print(msg)
send_msg = input('>>>')
sk.send(send_msg.encode('utf-8'))
if send_msg.upper() == 'Q':
break
print('客户端已断开连接')
sk.close()
3.tcp协议中的粘包问题
3.1什么是粘包?
一次发送多条数据时,如第一次发送hello,第二次发送world
在实际接收时,第一次收到helloworld,第二次收到为空。
3.2为什么会发生粘包?
tcp协议数据传输是没有边界的
3.3如何解决粘包
给数据设置一个边界,通过struct模块,发送一个数据来表示数据长度,该数据固定为4个字节
服务端
import socket
import struct
sk = socket.socket()
sk.bind(('127.0.0.1',9000))
sk.listen()
conn,addr = sk.accept()
send_msg = input('>>>')
blen = struct.pack('i',len(send_msg))
send_msg2 = input('>>>')
conn.send(blen)
conn.send(send_msg.encode('utf-8'))
conn.send(send_msg2.encode('utf-8'))
conn.close()
sk.close()
客户端
import socket
import struct
sk = socket.socket()
sk.connect(('127.0.0.1',9000))
blength = sk.recv(4)
length = struct.unpack('i',blength)[0]
msg = sk .recv(length).decode('utf-8')
msg2 = sk .recv(1024).decode('utf-8')
print(msg,msg2)
4.udp协议的代码
服务端
import socket
sk = socket.socket(type=socket.SOCK_DGRAM)
sk.bind(('127.0.0.1',9000))
while True:
msg,addr = sk.recvfrom(1024)
print(msg,addr)
send_msg = input('>>>')
sk.sendto(send_msg.encode('utf-8'),addr)
客户端
import socket
sk = socket.socket(type=socket.SOCK_DGRAM)
sever = ('127.0.0.1',9000)
while True:
send_msg = input(">>>")
sk.sendto(send_msg.encode('utf-8'),sever)
msg = sk.recvfrom(1024)[0].decode('utf-8')
print(msg)
5.基于tcp协议的小文件传输
服务端
import socket
import json
sk = socket.socket()
sk.bind(('127.0.0.1',9000))
sk.listen()
conn,addr = sk.accept()
jmsg = conn.recv(1024).decode('utf-8')
filename,filesize = json.loads(jmsg)
with open(filename,mode='wb') as f:
content = conn.recv(1024)
f.write(content)
conn.close()
sk.close()
客户端
import socket
import os
import json
sk = socket.socket()
sever = ('127.0.0.1',9000)
sk.connect(sever)
abs_path = r'C:\Users\Administrator\工作\账号密码.txt'
filename = os.path.basename(abs_path)
filesize = os.path.getsize(abs_path)
tup = (filename,filesize)
str_tup = json.dumps(tup)
sk.send(str_tup.encode('utf-8'))
with open(abs_path,mode='rb') as f:
content = f.read()
sk.send(content)
sk.close()
6.基于tcp协议的大文件传输(有粘包问题)
服务端
import socket
import struct
import json
sk = socket.socket()
sk.bind(('127.0.0.1',9000))
sk.listen()
conn,addr = sk.accept()
blen = conn.recv(4)
tuplen = struct.unpack('i',blen)[0]
str_tup = conn.recv(tuplen).decode('utf-8')
filename,filesize = json.loads(str_tup)
with open(filename,mode='wb')as f:
while filesize>0:
content = conn.recv(1024)
f.write(content)
filesize -= len(content)
conn.close()
sk.close()
客户端
import socket
import os
import json
import struct
sk = socket.socket()
sk.connect(('127.0.0.1',9000))
abs_path = r'C:\Users\Administrator\Desktop\测试大文件.zip'
filename = os.path.basename(abs_path)
filesize = os.path.getsize(abs_path)
tup =(filename,filesize)
str_tup = json.dumps(tup)
b_tup = str_tup.encode('utf-8')
blen = struct.pack('i',len(b_tup))
sk.send(blen)
sk.send(b_tup)
with open(abs_path,mode='rb') as f:
while filesize>0:
content = f.read(1024)
sk.send(content)
filesize -= len(content)
sk.close()
7.处理tcp协议并发客户端请求的服务端
服务端
import socketserver
import time
class Mysever(socketserver.BaseRequestHandler):
def handle(self):
conn = self.request
while True:
for i in range(100):
msg = conn.recv(1024).decode('utf-8')
conn.send(msg.upper().encode('utf-8'))
print(msg+str(i))
time.sleep(0.5)
server = socketserver.ThreadingTCPServer(('127.0.0.1',9000),Mysever)
server.serve_forever()
客户端
import socket
sk = socket.socket()
sk.connect(('127.0.0.1',9000))
while True:
for i in range(100):
sk.send(b'hello')
content = sk.recv(1024).decode('utf-8')
print(content+str(i))
8.未登陆情况下验证客户端的合法性
客户端生成一个随机字符串+密钥通过加密算法加密后,发送给服务端,服务端接收字符串,加上密钥加密后,产生的密文与收到的密文一致,则认为合法。
服务端
import socketserver
import hashlib
secret_key = b'123'
class Mysever(socketserver.BaseRequestHandler):
def handle(self):
conn = self.request
randstr = conn.recv(16)
msg = conn.recv(1024).decode('utf-8')
sha = hashlib.sha1(secret_key)
sha.update(randstr)
if sha.hexdigest() == msg:
print('是合法的用户')
else:
print('不是合法的用户')
conn.close()
sever = socketserver.ThreadingTCPServer(('127.0.0.1',9000),Mysever)
sever.serve_forever()
客户端
import socket
import os
import hashlib
secret_key = b'123'
randstr = os.urandom(16)
sha = hashlib.sha1(secret_key)
sha.update(randstr)
sk = socket.socket()
sk.connect(('127.0.0.1',9000))
sk.send(randstr)
sk.send(sha.hexdigest().encode('utf-8'))