Python学习之路--网络编程

由于不同机器上的程序要通信,才产生了网络

C/S Client/Server 客户端/服务端

服务端 一直运行 等待服务别人

客户端 寻求服务的时候 才请求服务

B/S Browser/Server 浏览器/服务器

b/s架构是c/s架构的一种

实现通信上有全球唯一的MAC地址

网卡和网线

网卡

通过ip地址就能找到对应的MAC地址  ARP协议

交换机 ---- 多台机器之间的通信问题

广播风暴

网关  局域网中的机器想要访问局域网外的机器,需要通过网关访问

IP地址 和 子网掩码 按位与  得到网段地址

端口 找到的程序

在计算机上 每一个需要网络通信的程序 都会开一个端口

在同一实际只会有一个程序占用一个端口

不可能在同一时间 在同一个计算机有两个端口占用同一个端口

端口的范围: 0--65535

127.0.0.1 本地的回环地址

ip地址  确定唯一一台机器

端口  确定唯一的一个程序

ip+端口  找到唯一的一台机器上的唯一的一个程序

基于tcp协议的socket

import socket
sk = socket.socket()
sk.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #避免服务重启的时候,报address already is in use
sk.bind((‘127.0.0.1‘, 8080))
sk.listen()     # 监听
conn, addr = sk.accept()   # 接收到客户端  连接 地址
print(addr)
ret = conn.recv(1024)  # 听
print(ret)
conn.send(b‘hi‘)  # 发送信息 必须传一个bytes类型

conn.close()  # 关闭连接
sk.close()             #  关闭
import socket
sk = socket.socket()
sk.connect((‘127.0.0.1‘, 8080))  #拨号

sk.send(b‘hello‘)  # 发送
ret =sk.recv(1024)
print(ret)

sk.close()

tcp中的长连接

import socket
sk = socket.socket()
sk.bind((‘127.0.0.1‘,8080))
sk.listen()
while True:
    conn,addr = sk.accept()
    while True:
        msg = conn.recv(1024).decode(‘utf-8‘)
        if msg == ‘bye‘:
            break
        print(msg)
        info = input(‘>>>‘)
        if info == ‘bye‘:
            conn.send(b‘bye‘)
            break
        conn.send(info.encode(‘utf-8‘))

    conn.close()
sk.close()

server

import socket
sk = socket.socket()
sk.connect((‘127.0.0.1‘,8080))
while True:
    msg = input(‘>>>>>‘)
    if msg == ‘bye‘:
        sk.send(b‘bye‘)
        break
    sk.send(msg.encode(‘utf-8‘))
    ret = sk.recv(1024).decode(‘utf-8‘)
    if ret == ‘bye‘:
        break
    print(ret)
sk.close()

client1

import socket
sk = socket.socket()
sk.connect((‘127.0.0.1‘,8080))
while True:
    msg = input(‘client2:>>>>>‘)
    if msg == ‘bye‘:
        sk.send(b‘bye‘)
        break
    sk.send((‘client2:‘+msg).encode(‘utf-8‘))
    ret = sk.recv(1024).decode(‘utf-8‘)
    if ret == ‘bye‘:
        break
    print(ret)
sk.close()

client2

 

UDP

udp的server 不需要进行监听也不需要建立连接

在启动服务之后只能被动得等待客户端发送消息过来

客户端发送消息的同时还会自带地址消息

消息回复的时候不仅需要发送消息,还需要把对方的地址填写上

单个服务端

import socket
sk = socket.socket(type=socket.SOCK_DGRAM)
sk.bind((‘127.0.0.1‘,8080))
msg,addr = sk.recvfrom(1024)
print(msg.decode(‘utf-8‘))
sk.sendto(b‘bye‘,addr)
sk.close()

server

import socket
sk = socket.socket(type=socket.SOCK_DGRAM)
ip_port = (‘127.0.0.1‘,8080)
sk.sendto(b‘hello‘,ip_port)
ret,addr = sk.recvfrom(1024)
print(ret.decode(‘utf-8‘))
sk.close()

client

多个客户端

import socket
sk = socket.socket(type=socket.SOCK_DGRAM)
sk.bind((‘127.0.0.1‘,8080))
while True:
    msg,addr = sk.recvfrom(1024)
    print(addr)
    print(msg.decode(‘utf-8‘))
    info = input(‘>>‘).encode(‘utf-8‘)
    sk.sendto(info,addr)

sk.close()

server

import socket
sk = socket.socket(type=socket.SOCK_DGRAM)
ip_port = (‘127.0.0.1‘,8080)
while True:
    info = input(‘二哥:‘)
    info = (‘\033[32m来自二哥的消息:%s\033[0m‘%info).encode(‘utf-8‘)
    sk.sendto(info,ip_port)
    msg,addr = sk.recvfrom(1024)
    print(msg.decode(‘utf-8‘))
sk.close()

client1

import socket
sk = socket.socket(type=socket.SOCK_DGRAM)
ip_port = (‘127.0.0.1‘,8080)
while True:
    info = input(‘tiger:‘)
    info = (‘\033[34m来自tiger的消息:%s\033[0m‘ % info).encode(‘utf-8‘)
    sk.sendto(info, ip_port)
    msg,addr = sk.recvfrom(1024)
    print(msg.decode(‘utf-8‘))
sk.close()

client2

黏包

同时接受的一条消息没有接收完,下一次执行的时候又多出来;

tcp 会出现黏包现象 不丢包

一,不知道长度

import socket
sk = socket.socket()
sk.bind((‘127.0.0.1‘,8090))
sk.listen()
conn,addr = sk.accept()
ret = conn.recv(2)
ret2 = conn.recv(10)
print(ret)
print(ret2)
conn.close()
sk.close()
# b‘he‘
# b‘llo‘

server

import socket
sk = socket.socket()
sk.connect((‘127.0.0.1‘,8090))
sk.send(b‘hello‘)

sk.close()

client

二、优化算法

import socket
sk = socket.socket()
sk.bind((‘127.0.0.1‘,8090))
sk.listen()
conn,addr = sk.accept()
ret = conn.recv(12)
print(ret)
conn.close()
sk.close()

# b‘helloegg‘

server

import socket
sk = socket.socket()
sk.connect((‘127.0.0.1‘,8090))
sk.send(b‘hello‘)
sk.send(b‘egg‘)
sk.close()

client

多个send小的数据黏在一起 会发生黏包现象,tcp协议内部的优化算法造成的

# 基于tcp实现远程执行命令
# 在server端下发命令
import socket
sk = socket.socket()
sk.bind((‘127.0.0.1‘,8090))
sk.listen()
conn, addr = sk.accept()
while True:
    cmd = input(‘>>>‘)
    conn.send(cmd.encode(‘utf-8‘))
    ret = conn.recv(1024).decode(‘utf-8‘)
    print(ret)

conn.close()
sk.close()

server

#  在client端接收消息并执行
import socket
import subprocess
sk = socket.socket()
sk.connect((‘127.0.0.1‘,8090))
while True:
    cmd = sk.recv(1024).decode(‘gbk‘)
    ret = subprocess.Popen(cmd,shell=True,
                           stdout=subprocess.PIPE,
                           stderr=subprocess.PIPE)
    std_out = ‘stdout:‘+(ret.stdout.read()).decode(‘gbk‘)
    std_err = ‘stderr‘+(ret.stderr.read()).decode(‘gbk‘)
    print(std_out)
    print(std_err)
    sk.send(std_out.encode(‘utf-8‘))
    sk.send(std_err.encode(‘utf-8‘))

sk.close()

client

udp 不会出现黏包现象 丢包

import socket
sk = socket.socket(type=socket.SOCK_DGRAM)
sk.bind((‘127.0.0.1‘,8090))
msg,addr = sk.recvfrom(1024)
while True:
    cmd = input(‘>>>‘)
    if cmd == ‘q‘:
        break
    sk.sendto(cmd.encode(‘utf-8‘),addr)
    msg,addr = sk.recvfrom(1024)
    print(msg.decode(‘utf-8‘))
sk.close()

server

import socket
import subprocess
sk = socket.socket(type=socket.SOCK_DGRAM)
addr = (‘127.0.0.1‘,8090)
sk.sendto(‘吃了吗‘.encode(‘utf-8‘),addr)
while True:
    cmd, addr = sk.recvfrom(1024)
    ret = subprocess.Popen(cmd.decode(‘gbk‘),shell=True,
                               stdout=subprocess.PIPE,
                               stderr=subprocess.PIPE)
    std_out = ‘stdout:‘+(ret.stdout.read()).decode(‘gbk‘)
    std_err = ‘stderr‘+(ret.stderr.read()).decode(‘gbk‘)
    print(std_out)
    print(std_err)
    sk.sendto(std_out.encode(‘utf-8‘),addr)
    sk.sendto(std_err.encode(‘utf-8‘),addr)
sk.close()

client

黏包问题解决方法一

import socket
sk = socket.socket()
sk.bind((‘127.0.0.1‘,8080))
sk.listen()
conn,addr = sk.accept()
while True:
    cmd = input(‘>>>>>‘)
    if cmd == ‘q‘:
        conn.send(‘q‘)
        break
    conn.send(cmd.encode(‘gbk‘))
    num = conn.recv(1024).decode(‘utf-8‘)
    conn.send(b‘ok‘)
    res = conn.recv(int(num)).decode(‘gbk‘)
    print(res)
conn.close()
sk.close()

server

import socket
import subprocess
sk = socket.socket()
sk.connect((‘127.0.0.1‘,8080))
while True:
    cmd = sk.recv(1024).decode(‘gbk‘)
    if cmd == ‘q‘:
        break
    res = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    std_out = res.stdout.read()
    std_err = res.stderr.read()
    sk.send(str(len(std_out)+len(std_err)).encode(‘utf-8‘))
    sk.recv(1024)
    sk.send(std_out)
    sk.send(std_err)
sk.close()

client

send 和 sendto 在超过一定范围的时候会报错

当要发送大数据的时候,要明确告诉接收方要发送多大的数据,一遍接收方能够准确的接收到所有数据

多用于文件传输过程中

黏包问题解决方法二

struck模块

该模块能够把一个了下转换成固定长度的bytes

import struct
ret = struct.pack(‘i‘,4096) #‘i‘代表int,就是即将要把一个数字转换成固定长度的bytes类型
print(ret)
num = struct.unpack(‘i‘,ret)
print(num[0])
# b‘\x00\x10\x00\x00‘
# 4096

struck

import socket
sk = socket.socket()
sk.bind((‘127.0.0.1‘,8080))
sk.listen()
conn,addr = sk.accept()
while True:
    cmd = input(‘>>>>>‘)
    if cmd == ‘q‘:
        conn.send(‘q‘)
        break
    conn.send(cmd.encode(‘gbk‘))
    num = conn.recv(4)
    num = struct.unpack(‘i‘,num)[0]
    res = conn.recv(int(num)).decode(‘gbk‘)
    print(res)
conn.close()
sk.close()

server

import struct
import socket
import subprocess
sk = socket.socket()
sk.connect((‘127.0.0.1‘,8080))
while True:
    cmd = sk.recv(1024).decode(‘gbk‘)
    if cmd == ‘q‘:
        break
    res = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    std_out = res.stdout.read()
    std_err = res.stderr.read()
    len_num = len(std_out)+len(std_err)
    nub_byt = struct.pack(‘i‘,len_num)
    sk.send(nub_byt)
    sk.send(std_out)
    sk.send(std_err)
sk.close()

client

struck 模块定制报头理论

网络上传输的所有数据 都叫数据包

数据包的里的所有数据 都叫报文

报文里不止有数据 ip地址 端口号 mac地址

所有的报文都有报头

协议 报头 接收多少个字节

字节定制报文 在复杂的应用上会用到

传输文件的时候

文件的上传下载

# 实现文件的上传下载
import socket
import struct
import json
sk = socket.socket()
sk.bind((‘127.0.0.1‘,8090))
sk.listen()
buffer = 4096
conn,addr = sk.accept()

head_len = conn.recv(4)
head_len = struct.unpack(‘i‘,head_len)[0]
json_head = conn.recv(head_len).decode(‘utf-8‘)
head = json.loads(json_head)
filesize = head[‘filesize‘]
with open(head[‘filename‘],‘wb‘) as f:
    while filesize:
        print(filesize)
        if filesize >= buffer:
            content = conn.recv(buffer)
            f.write(content)
            filesize -= buffer
        else:
            content =conn.recv(filesize)
            f.write(content)
            break
conn.close()
sk.close()

server

import socket
import os
import json
import struct
sk = socket.socket()
sk.connect((‘127.0.0.1‘,8090))
buffer = 4096

head = {‘filepath‘:r‘C:\Users\kehu\Desktop‘,
        ‘filename‘:r‘162210409211 冉思思财务报表分析.docx‘,
        ‘filesize‘:None}
file_path = os.path.join(head[‘filepath‘],head[‘filename‘])
filesize = os.path.getsize(file_path)
head[‘filesize‘] = filesize
json_head = json.dumps(head)  # 字典转成了字符串
bytes_head = json_head.encode(‘utf-8‘)  # 字符串转bytes
print(json_head)
print(bytes_head)
head_len = len(bytes_head)
pack_len = struct.pack(‘i‘,head_len)
sk.send(pack_len) # 先发送报头长度
sk.send(bytes_head) # 再发bytes类型的报头
with open(file_path,‘rb‘) as f:
    while filesize:
        print(filesize)
        if filesize >= buffer:
            content = f.read(buffer)
            sk.send(content)
            filesize -= buffer
        else:
            content = f.read(filesize)
            sk.send(content)
            break
sk.close()

client

原文地址:https://www.cnblogs.com/rssblogs/p/10993638.html

时间: 2024-08-01 02:41:49

Python学习之路--网络编程的相关文章

《Python学习之路 -- 网络编程》

在前面已经提到过,互联网的本质就是一堆协议,协议就是标准,比如全世界人通信的标准是英语,所有的计算机都学会了互联网协议,那么所有的计算机就可以按照统一的标准去收发信息完成通信了. 作为普通开发人员的我们,写的软件/程序都是处于应用层上的,然而,想要让软件接入互联网,就必须得通过传输层,也就是必须遵循TCP协议或者UDP协议.这是两个非常复杂的协议,如果遵循原生的协议,那么必然会大大降低效率,所以就有了socket抽象层的概念.socket是应用层与TCP/IP协议族通信的软件抽象层,它是一组接口

python学习之路网络编程篇(第一篇)

新课程知识的引入:python作用域 #python中无块级别作用域 if 1 == 1 : name = 'alex' print(name) for i in range(10): name = i print(name) #python中以函数为作用域 def func(): name = 'alex' print(name) #程序执行结果 # Traceback (most recent call last): # File "D:/PythonS13/Day10/С????1_pyt

python学习之路网络编程篇(第五篇)

paramiko简介 paramiko 是基于Python实现的SSH2远程安装连接,支持认证及秘钥方式.可以实现远程命令执行.文件传输.中间SSH代理等功能. paramiko安装 #!/bin/bash #install indepence package cd /data/soft wget https://www.dlitz.net/pub/dlitz/crypto/pycrypto/pycrypto-2.6.tar.gz yum -y install gcc python-devel

python学习之路网络编程篇(第五篇)-续篇

Python堡垒机实现之基础知识 一般的堡垒机必须要具备以下5个基本功能: 1.权限控制 2.执行命令 3.上传下载文件 4.远程登录 5.记录操作 权限控制 说明:根据不同的登录用户分配不同的可管理的主机组.(再细分的权限就是根据不同的用户控制可在主机上执行的命令,一般不会限制的这么严格) 思路:使用数据库创建用户表,表字段有ID.用户名.密码.所属组,再创建主机表,表字段有ID,主机IP,所属组.其中用户表中的所属组和主机表中的所属组相对应,这样就能把两张表关联起来.当用户登录的时候就可以根

python学习笔记11 ----网络编程

网络编程 网络编程需要知道的概念 1.网络体系结构就是使用这些用不同媒介连接起来的不同设备和网络系统在不同的应用环境下实现互操作性,并满足各种业务需求的一种粘合剂.网络体系结构解决互质性问题彩是分层方法. 网络(OSI)的7层模型: 应用层--->为应用程序提供网络通信服务 表示层--->数据表示 会话层--->主机间通信(两个应用进程间) 传输层--->端到端的连接,隔离网络的上下层协议,使得网络应用与下层协议无关 网络层--->寻找最优路径,转发数据包 数据链路层---&

Python学习之==>Socket网络编程

一.计算机网络 多台独立的计算机通过网络通信设备连接起来的网络.实现资源共享和数据传递.在同一台电脑上可以将D盘上的一个文件传到C盘,但如果想从一台电脑传一个文件到另外一台电脑上就要通过计算机网络 二.网络编程 所谓网络编程就是通过某种计算机语言来实现不同设备间的资源共享和信息传递.计算机网络的创造比计算机本身的意义更大,否则我们现在还玩着单机游戏,也没有现在蒸蒸日上的互联网行业. 1.OSI模型 OSI模型定义了不同计算机互联的标准,是设计和描述计算机网络通信的基本框架.OSI模型把网络通信的

Python学习笔记之网络编程

操作MySQL # 断言 assert(1==1) ############################################################################# ******************************************************************** # 创建Connection * ------------------------------------------------------------

Python学习之路3?编程风格

语句和语法 #   表示注释掉的内容 \    续行 1 print("yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy2 yyyyyyyyyyyyyyyyyyyyyyy") ;    分号:同一行放置多个语句以分号作为分割符 1 print('cyy');print('zzl') 2 3 输出结果: 4 cyy 5 zzl 语句(代码块)用缩进方式体现不同的代码级别,建议用4个空格(不要用tab) python文件以模块的方式组织,编写一个.py结尾的文件实际上

Python学习之路并发编程--信号量、事件、队列及生产消费模型

1. 信号量 对于多进程来说,多个进程同时修改数据,就可能出现安全隐患,所以引入了锁,这一机制,但锁只能有一把来控制一个的开关,当你需要几把锁的时候,就可能用到信号量的概念.他是用了锁的原理,内置了一个计数器,在同一时内,只能有指定数量的进程来执行某一段被控制的代码. import time,random from multiprocessing import Process,Semaphore def singing(i,sem): ''' :param i: 随机生成20个数的值 :para