第三模块:面向对象&网络编程基础-第2章 网络编程

文章目录

网络编程



前言

计算机网络编程


一、计算机网络基础

1.计算机基础

应用软件
操作系统
计算机硬件

2.什么是网络

互联网协议
osi七层:






3.五层协议详解

应用层
传输层 tcp/udbc
网络层 ip
数据链路层 Ethernet head(18个字节)|data
物理层

4.传输层详解

tcp协议
三次握手,四次断开

二、什么是socket

1.基于socket实现简单的套接字通信

服务端

# -*- coding: utf-8 -*-
import socket

#1.买手机
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# print(phone)
#2.绑定手机卡
phone.bind(('127.0.0.1',8081))#0-1024操作系统用
#3.开机
phone.listen(5)
#4.等电话链接
print("starting")
conn,client_addr = phone.accept()
#5.收发消息

data = conn.recv(1024) #1.单位:bytes 2.最大接收1024个bytes
print(f"客户端数据:{data}")

conn.send(data.upper())
#6.挂电话
conn.close()
#7.关机
phone.close()

客户端

# -*- coding: utf-8 -*-
import socket

#1.买手机
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# print(phone)
#2.拨号
phone.connect(('127.0.0.1',8081))#0-1024操作系统用

#3.发收消息
phone.send("hello".encode("utf-8"))
data = phone.recv(1024)
print(data)
#4.关闭
phone.close()

2.在简单的套接字通信基础上加上通信循环

服务端

# -*- coding: utf-8 -*-
import socket

phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.bind(('127.0.0.1',8081))#0-1024操作系统用
phone.listen(5)
print("starting")
conn,client_addr = phone.accept()
print(client_addr)
while True: #通信循环
    data = conn.recv(1024) #1.单位:bytes 2.最大接收1024个bytes
    print(f"客户端数据:{data}")
    conn.send(data.upper())

conn.close()
phone.close()

客户端

# -*- coding: utf-8 -*-
import socket

phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect(('127.0.0.1',8081))#0-1024操作系统用
while True:
    msg = input(">>:").strip()
    phone.send(msg.encode("utf-8"))
    data = phone.recv(1024)
    print(data)

phone.close()

3.客户端与服务端bug修复

服务端

# -*- coding: utf-8 -*-
import socket

phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phone.bind(('127.0.0.1',8081))#0-1024操作系统用
phone.listen(5)
print("starting")
conn,client_addr = phone.accept()
print(client_addr)
while True: #通信循环
    try:
        data = conn.recv(1024) #1.单位:bytes 2.最大接收1024个bytes
        if not data:break #适用于linux操作系统
        print(f"客户端数据:{data}")
        conn.send(data.upper())
    except ConnectionResetError: #适用于windows操作系统
        break

conn.close()
phone.close()

客户端

# -*- coding: utf-8 -*-
import socket

phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect(('127.0.0.1',8081))#0-1024操作系统用
while True:
    msg = input(">>:").strip()
    phone.send(msg.encode("utf-8"))
    if not msg:
        continue
    print("has send")
    data = phone.recv(1024)
    print("has recv")
    print(data.decode("utf-8"))

phone.close()

4.实现服务端可以对多个客户端提供服务

服务端

# -*- coding: utf-8 -*-
import socket

phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phone.bind(('127.0.0.1',8081))#0-1024操作系统用
phone.listen(5)
print("starting")
while True: #链接循环
    conn,client_addr = phone.accept()
    print(client_addr)
    while True: #通信循环
        try:
            data = conn.recv(1024) #1.单位:bytes 2.最大接收1024个bytes
            if not data:break #适用于linux操作系统
            print(f"客户端数据:{data}")
            conn.send(data.upper())
        except ConnectionResetError: #适用于windows操作系统
            break
    conn.close()
phone.close()

5.模拟ssh远程执行命令-项目

服务端

# -*- coding: utf-8 -*-
import socket
import subprocess

phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phone.bind(('127.0.0.1',8081))#0-1024操作系统用
phone.listen(5)
print("starting")
while True: #链接循环
    conn,client_addr = phone.accept()
    print(client_addr)
    while True: #通信循环
        try:
            #1.收命令
            cmd = conn.recv(1024) #1.单位:bytes 2.最大接收1024个bytes
            if not cmd:break #适用于linux操作系统

            #2.执行命令,拿到结果
            obj = subprocess.Popen(cmd.decode("utf-8"), shell=True,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE)
            stdout = obj.stdout.read()
            stderr = obj.stderr.read()
            #3.把命令的结果返回给客户端
            conn.send(stdout+stderr) #+是一个可以优化的点
        except ConnectionResetError: #适用于windows操作系统
            break
    conn.close()
phone.close()

客户端

# -*- coding: utf-8 -*-
import socket

phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect(('127.0.0.1',8081))#0-1024操作系统用
while True:
    #1.发命令
    cmd = input(">>:").strip()
    phone.send(cmd.encode("utf-8"))
    if not cmd:
        continue

    #2.拿到命令的结果并打印
    data = phone.recv(1024) #1024是一个坑
    print(data.decode("gbk"))

phone.close()

补充

#windows
#dir:查看某个文件夹下的子文件名与子文件夹
#ipconfig:查看本地网卡的ip信息
#tacklist:查看运行的进程

#linux
#ls
#config
#ps aux

#执行系统命令,并且拿到命令的结果
# import os
# res = os.system("dir c:")
# print(res)

import subprocess
obj = subprocess.Popen("dir c:",shell=True,
                 stdout=subprocess.PIPE,
                 stderr=subprocess.PIPE)
print(obj)
print("stdout:",obj.stdout.read().decode("gbk"))

print("stderr:",obj.stderr.read().decode("gbk"))

三、粘包现象

1.send与receive对比

1.不管是receive还是send都不是直接接收对方的数据,而是操作自己的操作系统内存——》不是一个send对应一个receive
2.recv:
wait data 耗时长
copy data
send:
copy data

2.底层原理分析

服务端

# -*- coding: utf-8 -*-
import socket
import time
import subprocess

sever = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
sever.bind(('127.0.0.1',8081))#0-1024操作系统用
sever.listen(5)

conn,addr = sever.accept()

#第一次接收
res1 = conn.recv(1)
res2 = conn.recv(3)
print("first time:",res1+res2)

#第二次接收
res3 = conn.recv(1024)
print("first time:",res3)

客户端

# -*- coding: utf-8 -*-
import socket
import time

client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect(('127.0.0.1',8081))#0-1024操作系统用

client.send("hello".encode("utf-8"))
time.sleep(5)
client.send("world".encode("utf-8"))

3.解决粘包问题伪代码实现

服务端

# -*- coding: utf-8 -*-
import socket
import subprocess

phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phone.bind(('127.0.0.1',8081))#0-1024操作系统用
phone.listen(5)
print("starting")
while True: #链接循环
    conn,client_addr = phone.accept()
    print(client_addr)
    while True: #通信循环
        try:
            #1.收命令
            cmd = conn.recv(8096) #1.单位:bytes 2.最大接收1024个bytes
            if not cmd:break #适用于linux操作系统

            #2.执行命令,拿到结果
            obj = subprocess.Popen(cmd.decode("utf-8"), shell=True,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE)
            stdout = obj.stdout.read()
            stderr = obj.stderr.read()
            #3.把命令的结果返回给客户端

            #第一步把报头(固定长度)发送给客户端
            total_size = len(stdout)+len(stderr)
            conn.send(str(total_size).encode("utf-8"))

            #第二步再发送真实的数据
            conn.send(stdout)
            conn.send(stderr)
        except ConnectionResetError: #适用于windows操作系统
            break
    conn.close()
phone.close()

客户端

# -*- coding: utf-8 -*-
import socket

phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect(('127.0.0.1',8081))#0-1024操作系统用
while True:
    #1.发命令
    cmd = input(">>:").strip()
    phone.send(cmd.encode("utf-8"))
    if not cmd:
        continue

    #2.拿到命令的结果并打印

    #第一步:先收报头
    total_size =
    #第二步:接收真实的数据
    receive_size = 0
    receive_data = b""

    while receive_size < total_size:
        res = phone.recv(1024) #1024是一个坑
        receive_data += res
        receive_size += len(res)
    print(receive_data.decode("gbk"))

phone.close()

2.解决粘包问题-简单版本

服务端

# -*- coding: utf-8 -*-
import socket
import subprocess
import struct
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phone.bind(('127.0.0.1',8081))#0-1024操作系统用
phone.listen(5)
print("starting")
while True: #链接循环
    conn,client_addr = phone.accept()
    print(client_addr)
    while True: #通信循环
        try:
            #1.收命令
            cmd = conn.recv(8096) #1.单位:bytes 2.最大接收1024个bytes
            if not cmd:break #适用于linux操作系统

            #2.执行命令,拿到结果
            obj = subprocess.Popen(cmd.decode("utf-8"), shell=True,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE)
            stdout = obj.stdout.read()
            stderr = obj.stderr.read()
            #3.把命令的结果返回给客户端
            #第一步:制作固定长度的报头
            total_size = len(stdout)+len(stderr)
            header = struct.pack("i",total_size)

            #第二步把报头(固定长度)发送给客户端
            conn.send(header)

            #第三步再发送真实的数据
            conn.send(stdout)
            conn.send(stderr)
        except ConnectionResetError: #适用于windows操作系统
            break
    conn.close()
phone.close()

客户端

# -*- coding: utf-8 -*-
import socket
import struct

phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect(('127.0.0.1',8081))#0-1024操作系统用
while True:
    #1.发命令
    cmd = input(">>:").strip()
    phone.send(cmd.encode("utf-8"))
    if not cmd:
        continue

    #2.拿到命令的结果并打印

    #第一步:先收报头
    header = phone.recv(4)

    #第二步:从报头中解析出对真实数据的描述信息(数据的长度)
    total_size = struct.unpack("i", header)[0]
    #第三步:接收真实的数据
    receive_size = 0
    receive_data = b""

    while receive_size < total_size:
        res = phone.recv(1024) #1024是一个坑
        receive_data += res
        receive_size += len(res)
    print(receive_data.decode("gbk"))

phone.close()

3.解决粘包问题-最终版本

服务端

# -*- coding: utf-8 -*-
import socket
import subprocess
import struct
import json
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phone.bind(('127.0.0.1',8081))#0-1024操作系统用
phone.listen(5)
print("starting")
while True: #链接循环
    conn,client_addr = phone.accept()
    print(client_addr)
    while True: #通信循环
        try:
            #1.收命令
            cmd = conn.recv(8096) #1.单位:bytes 2.最大接收1024个bytes
            if not cmd:break #适用于linux操作系统

            #2.执行命令,拿到结果
            obj = subprocess.Popen(cmd.decode("utf-8"), shell=True,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE)
            stdout = obj.stdout.read()
            stderr = obj.stderr.read()
            #3.把命令的结果返回给客户端
            #第一步:制作固定长度的报头
            header_dict = {
                "filename":"a.txt",
                "md5":"xxx",
                "total_size":len(stdout)+len(stderr)
            }
            header_json = json.dumps(header_dict)
            # total_size = len(stdout)+len(stderr)
            header_bytes=header_json.encode("utf-8")
            #第二步:先发送报头的长度
            conn.send(struct.pack("i",len(header_bytes)))

            #第三步:再发报头
            conn.send(header_bytes)

            #第四步:再发送真实的数据
            conn.send(stdout)
            conn.send(stderr)
        except ConnectionResetError: #适用于windows操作系统
            break
    conn.close()
phone.close()

客户端

# -*- coding: utf-8 -*-
import socket
import struct
import json

phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect(('127.0.0.1',8081))#0-1024操作系统用
while True:
    #1.发命令
    cmd = input(">>:").strip()
    phone.send(cmd.encode("utf-8"))
    if not cmd:
        continue

    #2.拿到命令的结果并打印

    #第一步:先收报头的长度
    obj = phone.recv(4)
    header_size = struct.unpack("i",obj)[0]

    #第二步:再收报头
    header_bytes = phone.recv(header_size)

    #第三步:从报头中解析出对真实数据的描述信息(数据的长度)
    header_json = header_bytes.decode("utf-8")
    header_dict = json.loads(header_json)
    print(header_dict)
    total_size = header_dict["total_size"]

    #第四步:接收真实的数据
    receive_size = 0
    receive_data = b""

    while receive_size < total_size:
        res = phone.recv(1024) 
        receive_data += res
        receive_size += len(res)
    print(receive_data.decode("gbk"))

phone.close()

四、文件传输功能

1.文件传输功能实现

服务端

# -*- coding: utf-8 -*-
import socket
import subprocess
import struct
import json
import os

share_dir = r"D:\pyfile\路飞学城就业课程\第三模块-面向对象&网络编程基础\第二章-网络编程\课堂练习\05文件传输\sever\share"
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phone.bind(('127.0.0.1',8081))#0-1024操作系统用
phone.listen(5)
print("starting")
while True: #链接循环
    conn,client_addr = phone.accept()
    print(client_addr)
    while True: #通信循环
        try:
            #1.收命令
            res = conn.recv(8096) #1.单位:bytes 2.最大接收1024个bytes
            if not res:break #适用于linux操作系统

            #2.解析命令,提取相应命令参数
            cmds = res.decode("utf-8").split()
            filename = cmds[1]
            #3.以读的方式打开文件,读取文件内容发送给客户端
            #第一步:制作固定长度的报头
            header_dict = {
                "filename":filename,
                "md5":"xxx",
                "file_size":os.path.getsize(r"%s/%s" %(share_dir,filename))
            }
            header_json = json.dumps(header_dict)
            # total_size = len(stdout)+len(stderr)
            header_bytes=header_json.encode("utf-8")
            #第二步:先发送报头的长度
            conn.send(struct.pack("i",len(header_bytes)))

            #第三步:再发报头
            conn.send(header_bytes)

            #第四步:再发送真实的数据
            with open("%s/%s" %(share_dir,filename),"rb") as f:
                for line in f:
                    conn.send(line)
        except ConnectionResetError: #适用于windows操作系统
            break
    conn.close()
phone.close()

客户端

# -*- coding: utf-8 -*-
import socket
import struct
import json

download_dir = r"D:\pyfile\路飞学城就业课程\第三模块-面向对象&网络编程基础\第二章-网络编程\课堂练习\05文件传输\client\download"
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect(('127.0.0.1',8081))#0-1024操作系统用
while True:
    #1.发命令
    cmd = input(">>:").strip()
    phone.send(cmd.encode("utf-8"))
    if not cmd:
        continue

    #2.以写的方式打开新文件,接收服务端发来的文件内容写入客户端的新文件
    #第一步:先收报头的长度
    obj = phone.recv(4)
    header_size = struct.unpack("i",obj)[0]

    #第二步:再收报头
    header_bytes = phone.recv(header_size)

    #第三步:从报头中解析出对真实数据的描述信息(数据的长度)
    header_json = header_bytes.decode("utf-8")
    header_dict = json.loads(header_json)
    print(header_dict)
    total_size = header_dict["file_size"]
    filename = header_dict["filename"]

    #第四步:接收真实的数据

    with open("%s/%s" %(download_dir,filename),"wb") as f:
        receive_size = 0
        while receive_size < total_size:
            line = phone.recv(1024)
            f.write(line)
            receive_size += len(line)
            print(f"总大小:{total_size},已下载大小:{receive_size}")


phone.close()

2.文件传输功能-函数版

服务端

# -*- coding: utf-8 -*-
import socket
import subprocess
import struct
import json
import os

share_dir = r"D:\pyfile\路飞学城就业课程\第三模块-面向对象&网络编程基础\第二章-网络编程\课堂练习\05文件传输\优化版本\sever\share"

def get(conn,cmds):
    filename = cmds[1]
    # 3.以读的方式打开文件,读取文件内容发送给客户端
    # 第一步:制作固定长度的报头
    header_dict = {
        "filename": filename,
        "md5": "xxx",
        "file_size": os.path.getsize(r"%s/%s" % (share_dir, filename))
    }
    header_json = json.dumps(header_dict)
    # total_size = len(stdout)+len(stderr)
    header_bytes = header_json.encode("utf-8")
    # 第二步:先发送报头的长度
    conn.send(struct.pack("i", len(header_bytes)))

    # 第三步:再发报头
    conn.send(header_bytes)

    # 第四步:再发送真实的数据
    with open("%s/%s" % (share_dir, filename), "rb") as f:
        for line in f:
            conn.send(line)

def put(conn,cmds):
    pass

def run():
    phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    # phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
    phone.bind(('127.0.0.1',8081))#0-1024操作系统用
    phone.listen(5)
    print("starting")
    while True: #链接循环
        conn,client_addr = phone.accept()
        print(client_addr)
        while True: #通信循环
            try:
                #1.收命令
                res = conn.recv(8096) #1.单位:bytes 2.最大接收1024个bytes
                if not res:break #适用于linux操作系统

                #2.解析命令,提取相应命令参数
                cmds = res.decode("utf-8").split()
                if cmds[0] == "get":
                    get(conn,cmds)
                elif cmds[0] == "put":
                    put(conn,cmds)

            except ConnectionResetError: #适用于windows操作系统
                break
        conn.close()
    phone.close()

if __name__ == '__main__':
    run()

客户端

# -*- coding: utf-8 -*-
import socket
import struct
import json

download_dir = r"D:\pyfile\路飞学城就业课程\第三模块-面向对象&网络编程基础\第二章-网络编程\课堂练习\05文件传输\优化版本\client\download"

def get(phone,cmds):
    # 2.以写的方式打开新文件,接收服务端发来的文件内容写入客户端的新文件
    # 第一步:先收报头的长度
    obj = phone.recv(4)
    header_size = struct.unpack("i", obj)[0]

    # 第二步:再收报头
    header_bytes = phone.recv(header_size)

    # 第三步:从报头中解析出对真实数据的描述信息(数据的长度)
    header_json = header_bytes.decode("utf-8")
    header_dict = json.loads(header_json)
    print(header_dict)
    total_size = header_dict["file_size"]
    filename = header_dict["filename"]

    # 第四步:接收真实的数据

    with open("%s/%s" % (download_dir, filename), "wb") as f:
        receive_size = 0
        while receive_size < total_size:
            line = phone.recv(1024)
            f.write(line)
            receive_size += len(line)
            print(f"总大小:{total_size},已下载大小:{receive_size}")

def put(phone,cmds):
    pass
def run():
    phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    phone.connect(('127.0.0.1',8081))#0-1024操作系统用
    while True:
        #1.发命令
        inp = input(">>:").strip()
        if not inp:continue
        phone.send(inp.encode("utf-8"))
        cmds = inp.split()
        if cmds[0] == "get":
            get(phone,cmds)
        elif cmds[0] == "put":
            put(phone,cmds)
    phone.close()

if __name__ == '__main__':
    run()

3.文件传输功能-面向对象版

五、基于udp协议套接字介绍

1.基本功能

服务端

# -*- coding: utf-8 -*-
from socket import *
sever = socket(AF_INET,SOCK_DGRAM)
sever.bind(("127.0.0.1",8881))

while True:
    data,client_addr = sever.recvfrom(1024)
    print(data)

    sever.sendto(data.upper(),client_addr)

sever.close()

客户端

# -*- coding: utf-8 -*-
from socket import *
client = socket(AF_INET,SOCK_DGRAM)

while True:
    msg = input(">>:").strip()
    client.sendto(msg.encode("utf-8"),("127.0.0.1",8881))

    data,sever_addr = client.recvfrom(1024)
    print(data,sever_addr)

client.close()

2.udp协议不会粘包

服务端

from socket import *

sever = socket(AF_INET,SOCK_DGRAM)
sever.bind(("127.0.0.1",8881))

res1 = sever.recvfrom(1024)
print(f"第一次:{res1}")
res2 = sever.recvfrom(1024)
print(f"第二次:{res2}")

sever.close()

客户端

from socket import *
client = socket(AF_INET,SOCK_DGRAM)

client.sendto(b"hello",("127.0.0.1",8881))
client.sendto(b"world",("127.0.0.1",8881))

client.close()

总结

网络编程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值