title: socket编程
copyright: true
top: 0
date: 2019-02-25 11:31:12
tags: socket编程
categories: Python高阶笔记
permalink:
password:
keywords:
description: socket不仅仅用来做端口扫描,他相当于系统提供的tcp-udp接口,可以用来做任何网络请求协议。
如果黑暗中的蛾子曾经体会过那么一点点光,它也不会不惜把整个世界都烧起来,只为了让自己暖和起来。
五层网络模型
应用层
功能:文件传输,电子邮件,文件服务,数据传输
TCP/IP协议:HTTP,FTP,SMTP,DNS,TELNET,SSH
传输层
功能:提供端口对端口的接口
TCP/IP协议:TCP-UDP
网络层
功能:为数据包选择路由
TCP/IP协议:IP,ICMP
数据链路层
功能:传输有地址的帧,错误检测功能
TCP/IP协议:ARP
物理层
功能:物理媒体,光纤
TCP/IP协议:1000BASE-SX
每次的网络传输请求都是通过 应用层–》传输层–》网络层–》数据链路层–》物理层传递。
除了应用层,其他的层都由操作系统,物理设备完成,所以通过操作系统提供的接口socket直接走传输层(通过TCP链接,socket不属于网络协议,属于自己定义的协议)可以完成大部分不同协议的网络请求。
c/s实现通信
使用socket实现客户端与服务端的通信,偷一张图(socket的固定编程模式)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kbuLsYZW-1614078528424)(/upload/TIM截图20190225114621.png)]
服务端代码:
import socket
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 指定网络类型,指定类型对应的协议(TCP协议)
# AF_INET = 2
# # IPV4
# AF_INET6 = 23
# # IPV6
# AF_IPX = 6
# # UNIX下的进程间通信
s.bind(('0.0.0.0',9999))
# 绑定IP与端口,传入元组类型,
s.listen()
# 开始监听绑定的IP与端口
sock,addr = s.accept()
# sock是传输对象,addr是传输对象的IP地址
data = sock.recv(1024)
# 获取客户端发来的1kb大小的始据
print(data.decode('utf-8'))
# 打印出客户端发来的数据,返回的是bytes类型,需要编码成utf-8
sock.send('总部收到总部收到'.encode('utf-8'))
# 然后向客户端发送一条数据
s.close()
sock.close()
# 关闭连接
客户端代码:
import socket
c = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
c.connect(('127.0.0.1',9999))
c.send('浪子呼叫总部浪子呼叫总部'.encode('utf-8'))
# 因为传递的是bytes类型的数据,需要编码
data = c.recv(1024)
# 客户端接收服务端发来的1kb数据
print(data.decode('utf-8'))
# 打印服务端返回的数据
c.close()
socket的编码模式基本上可以说是固定的,套用代码即可。
先运行服务端代码,再运行客户端代码:
服务端返回结果:
浪子呼叫总部浪子呼叫总部
客户端返回结果:
总部收到总部收到
这个就是固定的套路代码,如果想要让服务端一直接受客户端的请求的话,在这里修改代码即可:
s.bind(('0.0.0.0',9999))
# 绑定IP与端口,传入元组类型,
s.listen()
# 开始监听绑定的IP与端口
while 1:
sock,addr = s.accept()
# sock是传输对象,addr是传输对象的IP地址
data = sock.recv(1024)
# 获取客户端发来的1kb大小的始据
print(data.decode('utf-8'))
# 打印出客户端发来的数据,返回的是bytes类型,需要编码成utf-8
sock.send('总部收到总部收到'.encode('utf-8'))
# 然后向客户端发送一条数据
sock.close()
# 关闭连接
注意socket发送的内容必须要是bytes类型的(python3),这里说明一下:
'''
对于bytes编码的数据来说
只有decode方法
就是把bytes编码的数据转换成utf-8编码
对于utf-8编码的数据来说
只有encode方法
就是把utf-8编码的数据转换成bytes编码,如果要转成其他编码
.encdoe('gbk')即可
'''
C/S端相互发消息
服务端代码:
import socket
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.bind(('0.0.0.0',9999))
s.listen()
sock, addr = s.accept()
while 1:
inp = input('输入消息:')
sock.send(inp.encode('utf-8'))
data = sock.recv(1024)
print('接收消息:'+data.decode('utf-8'))
客户端代码:
import socket
c = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
c.connect(('127.0.0.1',9999))
while 1:
data = c.recv(1024)
print('接收消息:'+data.decode('utf-8'))
inp = input('输入消息:')
c.send(inp.encode('utf-8'))
服务端返回结果:
输入消息:我是你爸爸
接收消息:我是你爷爷
输入消息:
客户端返回结果:
接收消息:我是你爸爸
输入消息:我是你爷爷
多用户连接
从上面的代码中一个sock只能服务一个客户端,服务端只能服务一个对象,使用多线程即可完成一个服务端服务大量的客户端。
服务端代码:
import socket
import threading
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.bind(('0.0.0.0',9999))
s.listen()
def handle_sock(sock,addr):
while 1:
inp = input('输入消息:')
sock.send(inp.encode('utf-8'))
data = sock.recv(1024)
print('接收消息:' + data.decode('utf-8'))
while 1:
sock, addr = s.accept()
clinent_thread = threading.Thread(target=handle_sock,args=(sock,addr))
clinent_thread.start()
客户端代码:
import socket
c = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
c.connect(('127.0.0.1',9999))
while 1:
data = c.recv(1024)
print('接收消息:'+data.decode('utf-8'))
inp = input('输入消息:')
c.send(inp.encode('utf-8'))
这个时候运行两个客户端返送请求一样可以被服务端获取到。
模拟HTTP请求
requests本质上调用urllib发起网络请求,urllib通过调用socket发起网络请求。模拟socket对HTTP请求就是对本质上进行重写编程。
具体实现看代码,其实很简单的,不多描述
import socket
from urllib.parse import urlparse
# 对url做解析
def get_url(url):
url = urlparse(url)
# 对传入的网址进行解析,比如传入http://www.langzi.fun/admin.php
host,path = url.netloc,url.path
# 获取传入网址的主域名和后面的url路径
if path == '':
path = '/'
c = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
c.connect((host,80))
headers = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'
# 绑定ip与端口
c.send('GET {}\r\nHost:{}\r\nUser-Agent:{}\r\n'.format(path,host,headers).encode('utf-8'))
# 发送请求,请求方式为GET 内容是url的路径,然后分隔换行
# 发送请求,请求的HOST主机就是主域名
# 在这里可以把请求头,cookie加进来
data = b''
# 获取数据
while 1:
d = c.recv(1024)
if d:
data +=d
else:
break
print(data.decode('utf-8'))
get_url('http://www.lancygroup.com/')
欢迎关注公众号:【安全研发】获取更多相关工具,课程,资料分享哦~