python:网络编程

网络编程:使用编程语言实现多台计算机的通信。

网络编程三要素:

  • IP地址
  • 端口
  • 协议

一、socket通信案例

server端

import socket

# 1.创建socket对象:默认是ipv4的TCP协议
sock = socket.socket()
# 2.bind方法
sock.bind(('127.0.0.1', 8890))
# 3.建立最大监听数
sock.listen(5)

while 1:
    # 4.等待连接
    print('server is waiting...')
    client_sock, client_addr = sock.accept()
    print(client_sock)
    print(client_addr)

    # 正式通信
    while 1:
        # 5.接受消息
        data = client_sock.recv(1024)
        if data.decode() == 'q':
            break
        print('客户端发送的数据:', data.decode())

        # 6.回复消息
        msg = input('请输入要发送给client的消息')
        client_sock.send(msg.encode())

client端:

import socket

# 1.创建socket对象:默认是ipv4的TCP协议
sock = socket.socket()
# 2.连接服务端
sock.connect(('127.0.0.1', 8890))

# 正式通信
while 1:
    msg = input('请输入要发送给server的数据:')
    # 3.发送数据:发送的必须是字节数据
    sock.send(msg.encode())

    # 接收服务端的响应
    res = sock.recv(1024)
    print('服务端的响应数据:', res.decode())

sock.close()

二、 TCP的粘包

根据socket缓冲区和数据的传递过程,可以看到数据的接收和发送是无关的,read()/recv() 函数不管数据发送了多少次,都会尽可能多的接收数据。也就是说,read()/recv() 和 write()/send() 的执行次数可能不同。

数据的“粘包”问题,客户端发送的多个数据包被当做一个数据包接收。也称数据的无边界性,read()/recv() 函数不知道数据包的开始或结束标志(实际上也没有任何开始或结束标志),只把它们当做连续的数据流来处理。

server端

import socket
import time

sock = socket.socket()
sock.bind(('127.0.0.1', 8891))
sock.listen(5)

# 等待连接
print('server is waiting...')
client_sock, client_addr = sock.accept()
time.sleep(5)
data = client_sock.recv(1024)
print('client传来的数据:', data.decode())

client端

import socket

sock = socket.socket()
sock.connect(('127.0.0.1', 8891))

msg = input('请输入要给server发送的消息')
sock.send(msg.encode())
sock.send(msg.encode())
sock.send(msg.encode())

三、ssh案例

server端:

import socket
import subprocess
import struct
import time

sock = socket.socket()
sock.bind(('127.0.0.1', 8890))
sock.listen(5)

# 等待连接
print('server is waiting...')
while 1:
    client_sock, client_addr = sock.accept()
    while 1:
        msg = client_sock.recv(1024)
        ret = subprocess.getoutput(msg.decode('gbk'))
        print('server的响应是:', ret)

        ret_len = struct.pack('i', len(ret.encode('gbk')))       # struct.pack()解决粘包问题
        print('server响应的字节串大小是:', ret_len)
        # print(len(ret.encode('gbk')))

        client_sock.send(ret_len)                             # send只能发str字符串,不能发int
        client_sock.send(ret.encode('gbk'))

client端 

import socket
import math
import time
import struct

sock = socket.socket()
sock.connect(('127.0.0.1', 8890))

while 1:
    msg = input('请输入要发送给server端的消息')
    sock.send(msg.encode())

    time.sleep(5)            # 模拟粘包
    # 接收数据大小
    data = sock.recv(4)
    size = struct.unpack('i', data)[0]
    # size = data.decode('gbk')
    print('server发来的消息总大小:', size)    # 循环读取

    # 接收数据内容
    s = ''
    num = math.ceil(int(size)/1024)
    print('循环次数:', num)
    for i in range(0, math.ceil(int(size)/1024)):      # 解决内存问题
        print('i', i)
        data = sock.recv(1024)
        a = data.decode('gbk')
        s = s + a
    print('server发来的消息', s)

四、FTP案例

server端:

import os.path
import socket
import struct
import json


class FTP():
    addr = ('127.0.0.1', 8890)

    def __init__(self):
        self.sock = socket.socket()
        # bind方法
        self.sock.bind(self.addr)
        # listen
        self.sock.listen(5)
        # 等待连接
        print('server is waiting...')
        self.client_sock, self.client_addr = self.sock.accept()
        # print('客户端sock', self.client_sock)

    def run(self):
        data = self.client_sock.recv(1024)
        data_json = json.loads(data.decode('gbk'))
        cmd = data_json['cmd']
        file_data = data_json['file_data']
        print('接收的文件信息:', data_json, type(data_json))

        if hasattr(self, cmd):
            getattr(self, cmd)(data_json)
        else:
            print('请输入正确shell')

    def put(self, file_data):
        print('server端put函数...')
        file_name = file_data['file_data']['name']
        file_size = file_data['file_data']['size']
        size = 0
        with open(file_name, mode='wb') as f:
            while size < file_size:
                content = self.client_sock.recv(1024)
                f.write(content)
                size += len(content)

    def get(self, file_data):
        print('server端get函数...')
        # 发送文件信息
        file_size = os.path.getsize(file_data['file_data']['name'])
        file_data['file_data']['size'] = file_size
        self.client_sock.send(json.dumps(file_data).encode('gbk'))
        # 发送文件
        recv_size = 0
        with open(file_data['file_data']['name'], mode='rb') as f:
            while recv_size < file_size:
                content = f.readline()
                self.client_sock.send(content)
                recv_size += len(content)
        print('server端文件已发送...')


if __name__ == '__main__':
    FTP().run()

client端:

import os.path
import socket
import struct
import json


class FTP():
    server_addr = ('127.0.0.1', 8890)

    def __init__(self):
        # 创建socket对象
        self.sock = socket.socket()
        # 连接server
        self.sock.connect(self.server_addr)

    def run(self):
        print('上传:put 文件地址 ; 下载:get 文件地址')
        inputs = input('请输入命令')
        cmd, path = inputs.split()
        if hasattr(self, cmd):
            print('反射结果:', getattr(self, cmd), type(getattr(self, cmd)))
            getattr(self, cmd)(path)
        else:
            print('请输入正确的shell命令')

    def put(self, path):
        print('put函数...')
        # 获取文件信息
        file_size = os.path.getsize(path)
        file_name = os.path.basename(path)
        data = {'cmd': 'put', 'file_data': {'size': file_size,'name': file_name}}
        print('文件信息:', data)
        # 发送data
        self.sock.send(json.dumps(data).encode('gbk'))
        # 发送文件
        with open(path, mode='rb') as f:
            for line in f:
                self.sock.send(line)
        print('文件已发送')

    def get(self, path):
        print('get函数...')
        data = {'cmd': 'get', 'file_data': {'name': path}}
        print('get函数的文件信息类型', type(data))
        self.sock.send(json.dumps(data).encode('gbk'))
        # 接收文件大小
        data = self.sock.recv(1024)
        print('接收到的文件信息', data, type(data))
        data = json.loads(data.decode('gbk'))
        file_size = data['file_data']['size']
        # 写入文件
        recv_size = 0
        with open(path, mode='wb') as f:
            while recv_size < file_size:
                content = self.sock.recv(1024)
                f.write(content)
                recv_size += len(content)


if __name__ == '__main__':
    FTP().run()

如上ftp案例目前仅实现了文件的上传put和下载get;感兴趣的朋友可以在此基础上增加如下功能;

  • 断点续传
  • 上传/下载展示进度条
  • 解决粘包问题
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值