python-网络编程 (个人学习笔记1.0)--socket模块,以及客户端利用服务端,进行信息交互,文件传输,系统命令执行的代码的简单编写

提要

网络编程简单提要:

IP:

1.用于识别网络上一台独立的计算机(主机)
2.IP地址 = 网络地址 + 主机地址
3.特殊IP地址:127.0.0.1(表示本机)

端口号:

1.用于识别程序进程,每个进程都有自己的端口号

传输协议:
1.UDP:用户数据报协议(UDP,User Datagram Protocol)

1.传输速率快,效率高
2.传输数据时,传输端不必和目的端产生连接,即:传出数据不一定会被接收
3.限制传输数据大小8字节(64K)

2.TCP:传输控制协议(TCP,Transmission Control Protocol)

1.传输速率慢,效率低
2.传输数据前,传输端需要与目的端产生连接
3.可传输大量数据

4.遵循三握手协议:
传输端:我要给你发信息了
目的端:我知道你要给我发信息了
传输端:我知道你知道我要给你发信息了

一、socket模块

1.socket简述

socket:通过IP等进程,在网络上识别某个独立计算机后,可以利用socket模块使双方建立通讯

1.socket内常用方法:

sk = socket.socket()   #建立一个socket对象

address=('127.0.0.1',9999)
sk.bind(address)		#向socket对象导入IP地址以及端口号

sk.listen(3)		#限制连接对象与排队人数为3

conn,address = sk.accept()			#接收客户端配置信息,此时由conn与address分别接收
#conn:接收客户端应用配置信息,是在服务端内的客户端的套接字对象,用于与客户端连接以及传输数据
#address:接收客户端地址

服务端:
# conn:客户端的端口信息
conn.recv(1024)		#接收客户端传来的信息,限制一次性传来大小为1024字节,可更改大小
conn.send(<信息>)		#向客户端传输指定信息,可能未将指定内容全部发送
conn.sendall()		#向客户端传输指定信息,尝试传输所有内容,传输失败返回False

客户端:
# sk:客户端的端口信息
sk.recv(1024)	
sk.send(<信息>)
sk.sendall()	

!!!
注意:send以及recv只能传输或接收bytes类型数据
!!!

2.代码实例(以下皆以本机作为客户端以及服务端,模拟两台主机间的交互):

1.字符交互(代码案例):

服务端:

import socket

sk = socket.socket()

address = ('127.0.0.1',9999)

sk.bind(address)

sk.listen(3)

print('waiting.....')

while True:
    conn, ret = sk.accept()	
    print(ret,end='')	#标识连接的客户端IP
    print('已连接....')
    
    while True:
        try:					#捕捉客户端的异常断开
            message = conn.recv(1024)		#接收客户端信息
        except Exception as e:
            print('客户端异常退出...\n')
            break
            
        if not message:			#通过判断客户端传输信息是否存在,决定是否关闭连接端口
            print('客户端已退出...')
            print('等待连接...')
            conn.close()
            break
        else:
            print(str(message, 'utf8'))
        conn.send(bytes(input('>>>'), 'utf8'))	#向客户端传递信息

客户端:

import socket

sk = socket.socket()

address = ('127.0.0.1',9999)

sk.connect(address)

while True:
    data = input('>>>')
    if data == 'exit':
        break
    sk.send(bytes(data, 'utf8'))
    message = sk.recv(1024)
    print(str(message, 'utf8'))

sk.close()

输出举例:

服务端:

waiting.....
('127.0.0.1', 51570)已连接....
HI
>>>HI
客户端已退出...
等待连接...

客户端:

>>>HI
HI
>>>exit

2.客户端通过服务端执行系统操作指令(代码案例)

服务端:

import socket
import subprocess

sk = socket.socket()

address = ('127.0.0.1',9999)

sk.bind(address)

sk.listen(3)

print('waiting.....')
while True:
    conn, ret = sk.accept()
    print(ret,end='')
    print('已连接....')
    while True:
        message = conn.recv(1024)
        cmd_set = subprocess.Popen(str(message,'utf8'),shell=True,stdout=subprocess.PIPE)
        #str(message,'utf8'):指定操作命令
        #shell=True参数会让subprocess接受字符串类型的变量作为命令
        #stout = subprocess.PIPE -> 将Popen调入主进程,否则将会在其额外进程将其打印在当前屏幕
        
        cmd_result = cmd_set.stdout.read()      #接收命令结果,cmd_set.stdout.read()返回值为:bytes类型
        
        cmd_len = len(cmd_result)			#传回命令结果长度,方便客户端操作,使其能够完整接收传出结果
        conn.sendall(bytes(str(cmd_len),'utf8'))  #bytes不能转换int

        conn.recv(1024)     #解决粘包问题,有时因为前一个sendall传出数据太短,将和后一个sendall同时传出,此时recv起到一个暂停作用

        conn.sendall(cmd_result)	#传出结果

客户端:

import socket

sk = socket.socket()

address = ('127.0.0.1',9999)

sk.connect(address)

while True:
    data = input('>>>')
    
    sk.send(bytes(data, 'utf8'))	#发送想要执行的命令
    
    cmd_lens = int(str(sk.recv(1024),'utf8'))	#接收命令结果的长度
    
    sk.sendall('')      #解决粘包问题
    
    print(cmd_lens)		#显示命令结果长度
    
    message = bytes()	#建立一个空的buytes类型对象,方便下方统计长度,及时退出循环
    
    while len(message) != cmd_lens:		#因为一次只能接收1024字节,所以此时需要使用循环来帮助接收完整的结果
        result_cmd = sk.recv(1024)		
        message+=result_cmd

    print(str(message,'GBK'))		

sk.close()

输出案例:

服务端:

waiting.....
('127.0.0.1', 52364)已连接....

客户端:

>>>cd	
44
D:\compileby\python fullstack\net_function

3.传输一个文件的代码案例(将一个文件从当前脚本目录传输到当前脚本目录下的phtone_home文件夹下)

服务端:

import os
import socket

root_path = os.path.dirname(os.path.abspath(__file__))	#查找脚本文件夹路径

sk = socket.socket()

address = ('127.0.0.1',9999)

sk.bind(address)

sk.listen(3)

while True:
    conn, ret = sk.accept()
    while True:
        data = conn.recv(1024)
        cmd_name,file_name,file_size = str(data,'utf8').split('|')
        #客户端传来的三个信息:命令,图片名称,图片大小
        path = os.path.join(root_path,'phtone_home',file_name)
        #图片传输目的地目录
        
        file_size = int(file_size)

        f = open(path,'wb')

        recv_size = 0
        while recv_size != file_size:
            file_recv = conn.recv(1024)
            f.write(file_recv)
            recv_size += len(file_recv)

        f.close()

客户端:

import socket
import os

sk = socket.socket()

address = ('127.0.0.1',9999)

sk.connect(address)

root_path = os.path.dirname(os.path.abspath(__file__))

while True:
    data = input('请输入命令以及文件名称以‘|’分隔:').strip()	#删除结尾换行符
    
    cmd_name,data_name = data.split('|')	#将一次性输入的命令与文件名分开

    file_path = os.path.join(root_path,data_name)	#文件路径

    file_name = os.path.basename(file_path)	#文件名

    file_size = os.stat(file_path).st_size	#查找文件大小

    file_info = "post|%s|%s"%(file_name,file_size)	#将上述得到的命令信息打包
    sk.sendall(bytes(file_info,'utf8'))

    f = open(file_path,'rb')	#rb:将数据以bytes类型读出

    num_size = 0

    while num_size != file_size:
        datas = f.read(1024)
        sk.sendall(datas)
        num_size+=len(datas)

    f.close()
    print('上传成功...')

服务端输出:


客户端输出:

请输入命令以及文件名称以‘|’分隔:post|11.jpg
上传成功...

运行前:
在这里插入图片描述
运行后:
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值