天天看点

PYTHON socket编程五层网络模型c/s实现通信C/S端相互发消息多用户连接模拟HTTP请求

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/')
           

欢迎关注公众号:【安全研发】获取更多相关工具,课程,资料分享哦~

PYTHON socket编程五层网络模型c/s实现通信C/S端相互发消息多用户连接模拟HTTP请求