1.最基础版本的socket编程:

import socket
#socket服务端:
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)  #买手机
phone.bind(('127.0.0.1',8080))                  #插入手机卡
phone.listen(5)         #开机     等待连接的连接数(5)     半连接池
conn,addr=phone.accept()     #接电话   conn连接的线路  addr 对方ip
print('tcp的连接: ',conn)
print('客户端的地址:',addr)
data=conn.recv(1024)         #接收的大小 1024
print('from client msg: %s' %data)
conn.send(data.upper()) #发消息
conn.close()    #挂电话
phone.close()   #关手机
import socket
timeout=2
#这里对整个socket层设置超时时间。后续文件中如果再使用到socket,不必再设置
socket.setdefaulttimeout(timeout)
#socket 客户端
client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect(('127.0.0.1',8080))
client.send('hello'.encode('utf-8'))
data=client.recv(1024)
print(data)
client.close()

 

简单的循环实现-socketserver和socketclient一直进行数据交互

import socket
#服务端
#创建socket对象,指定家族簇,指定协议TCP=SOCK_STREAM
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)  
#设置断开连接时不出错
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
#绑定ip和port,注意传入一个参数元组类型
phone.bind(('127.0.0.1',8080))                  
phone.listen(5)         #开机     等待连接的连接数(5)     半连接池
while True: #链接循环
    conn,addr=phone.accept()     #conn是client连接成功创建的对象,之后的数据交互都是通过conn
    print('tcp的连接: ',conn)
    print('客户端的地址:',addr)
    while True: #通讯循环
        try:
            data=conn.recv(1024)         #接收的大小 1024        #不能收空,空默认为没有收到
            if not data:break           #解决客户端断开,一直打印空。
            print('from client msg: %s' %data)
            conn.send(data.upper()) #发消息    将client传入的数据转化为大写发送回去
        except Exception:       #
            break
    conn.close()    #挂电话
phone.close()   #关手机
import socket
#客户端
#创建一个socket对象
client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#利用socket对象进行连接server
client.connect(('127.0.0.1',8080))
while True:
    msg=input('>>:')
    if not msg:continue #如果输入的数据是空,返回
    client.send(msg.encode('utf-8'))    #进行发送数据,socket之间数据交互必须是bytes类型的
    data=client.recv(1024)              #进行接收数据
    print(data)
client.close()

利用socket,远程执行命令并将命令执行的结果返回

服务端:

#远程执行命令server端
import socket,subprocess,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',8080))
phone.listen(5)         #开机     等待连接的连接数(5)     半连接池
while True: #链接循环
    print('等待连接....')
    conn,addr=phone.accept()     #接电话   conn连接的线路  addr 对方ip
    print('tcp的连接: ',conn)
    print('客户端的地址:',addr)
    while True: #通讯循环
        try:
            cmd=conn.recv(1024)         #接收的大小 1024        #不能收空,空默认为没有收到
            if not cmd:break           #解决客户端断开,一直打印空。
            print('from client msg: %s' %cmd)
            res=subprocess.Popen(cmd.decode('utf-8'),   #通过subprocess获取命令的执行结果
                                        shell=True,
                                        stdout=subprocess.PIPE,
                                        stderr=subprocess.PIPE)
            err=res.stderr.read()   #获取错误信息
            if err: #如果错误信息存在
                back_msg=err    #返回信息为错误信息
            else:
                back_msg=res.stdout.read()  #否则返回信息为标准输出
        except Exception:       #
            break

        #解决服务端粘包问题
        conn.send(struct.pack('i',len(back_msg)))       #'i':指定struct 返回的为4个字节
        conn.sendall(back_msg)                          #sendall 。循环将所有的数据全部发送完
    conn.close()    #挂电话
phone.close()   #关手机

客户端

import socket,struct
#创建一个socket对象
client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#进行连接服务器
client.connect(('127.0.0.1',8080))
#进入循环开始和服务器进行交互
while True:
    cmd=input('>>:').strip()
    if not cmd:continue #如果输入的是空,返回
    client.send(cmd.encode('utf-8'))
    data_head=client.recv(4)        #接收服务端用struct封装以后的数据,定长的为 4个字节
    data_size=struct.unpack('i',data_head)[0]   #利用struct获取到数据包的头部,获取到源数据的大小
    recv_size=0             #用来保存接收到的数据大小
    recv_bytes=b''          #用来保存接收到的数据
    while recv_size <data_size: #判断有没有收完数据
        res=client.recv(1024)   #接收数据
        recv_bytes+=res          #拼接bytes字符
        recv_size+=len(res)     #计算接收到的数据的大小
    print(res.decode('gbk'))    #打印接收到的数据
client.close()

解决粘包问题: 发送json数据

import socket,subprocess,struct,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',8080))                  #插入手机卡
phone.listen(5)         #开机     等待连接的连接数(5)     半连接池
while True: #链接循环
    print('等待连接....')
    conn,addr=phone.accept()     #接电话   conn连接的线路  addr 对方ip
    print('tcp的连接: ',conn)
    print('客户端的地址:',addr)
    while True: #通讯循环
        try:
            cmd=conn.recv(1024)         #接收的大小 1024        #不能收空,空默认为没有收到
            if not cmd:break           #解决客户端断开,一直打印空。
            print('from client msg: %s' %cmd)
            res=subprocess.Popen(cmd.decode('utf-8'),
                                        shell=True,
                                        stdout=subprocess.PIPE,
                                        stderr=subprocess.PIPE)
            err=res.stderr.read()
            if err:
                back_msg=err
            else:
                back_msg=res.stdout.read()
        except Exception:       #
            break
        # conn.send(back_msg)
#解决服务端粘包问题
        #conn.send(struct.pack('i',json.dumps(len(back_msg))))
        #第一阶段,制作报头
        head_dict={
            'data_size':len(back_msg)
        }
        head_json=json.dumps(head_dict)
        head_bytes=head_json.encode('utf-8')
        #第二阶段:发送报头的长度
        conn.send(struct.pack('i',len(head_bytes)))
        #第三阶段:发送报头
        conn.send(head_bytes)
        #第四阶段:发送真实数据
        conn.sendall(back_msg)
    conn.close()    #挂电话
phone.close()   #关手机

客户端:

import socket,struct,json
client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect(('127.0.0.1',8080))
while True:
    cmd=input('>>:').strip()
    if not cmd:continue
    client.send(cmd.encode('utf-8'))
    #收报头的长度
    data_head=client.recv(4)
   # data_size=json.load(struct.unpack('i',data_head)[0])
    head_size=struct.unpack('i',data_head)[0]
    #收报头(根据报头长度)
    head_json=client.recv(head_size)
    head_dict=json.loads(head_json.decode('utf-8'))
    #获取真实数据长度
    data_size=head_dict['data_size']

    recv_size=0
    recv_bytes=b''
    while recv_size <data_size:
        res=client.recv(1024)
        recv_bytes+=res
        recv_size+=len(res)
    print(res.decode('gbk'))
client.close()

socketserver解决只能一个客户端连接到server上的问题

服务端:

import socketserver
#BaseRequestHandler 处理通讯
class FtpServer(socketserver.BaseRequestHandler):
    def handle(self):   #必须实现handle方法,负责与客户端通讯
        print(self.request)
        print(self.client_address)
        while True:
            try:
                data=self.request.recv(1024)
                self.request.send(data.upper())
            except Exception:
                break
if __name__ == '__main__':
    #ThreadingTCPServer 处理链接
    s=socketserver.ThreadingTCPServer(('127.0.0.1',8080),FtpServer)
    s.serve_forever()       #链接循环--有了

客户端

from socket import *
client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8080))
while True:
    msg=input('>>:')
    client.send(msg.encode('utf-8'))
    data=client.recv(1024)
    print(data)

异常处理

try:
    names=['alex','liuhao']
    names[sasa]
except IndexError as e:
    print(e)
except Exception as e:
    print(e)
    exit()
else:
    print('什么错都没有')
finally:
    print('无论有没有错都执行')

print('keep going')

自定义异常处理

class WupeiqiException(Exception):

    def __init__(self, msg):
        self.message = msg
try:
    raise WupeiqiException('我的异常')
except WupeiqiException as e:
    print (e)

 

作业:开发一个支持多用户在线的FTP程序

要求:

  1. 用户加密认证
  2. 允许同时多用户登录
  3. 每个用户有自己的家目录 ,且只能访问自己的家目录
  4. 对用户进行磁盘配额,每个用户的可用空间不同
  5. 允许用户在ftp server上随意切换目录
  6. 允许用户查看当前目录下文件
  7. 允许上传和下载文件,保证文件一致性
  8. 文件传输过程中显示进度条
  9. 附加功能:支持文件的断点续传

FTPManager

import json,os,sys,hashlib
def run():
    #user_database = os.path.dirname(__file__)+'/'+'users'+'/'
    user_database=os.path.dirname(os.path.abspath(sys.argv[0]))+'/'+'users'+'/'
    print(user_database)
    while True:
        md5=hashlib.md5()
        name=input('create your acount:')
        if len(name)==0:continue
        elif os.path.isfile(user_database+name):
            print('用户已经存在')
            continue
        passwd=input('create your passwd:')
        if len(passwd)==0:continue
        passwd=passwd.encode(encoding='utf-8')
        md5.update(passwd)
        quota_size=input('enter your quota_size[b]:')
        if len(quota_size)==0:continue
        user_dir = os.path.dirname(os.path.abspath(sys.argv[0]))+'/'+'user_file/'+name
        os.mkdir(user_dir)
        user_dict={
                   'name':name,
                   'passwd':md5.hexdigest(),
                   'quota_size':int(quota_size),
                   'use_quota':0
                   }

        with open(user_database+name,'w',encoding='utf-8') as f:
            f.write(json.dumps(user_dict))
        break


if __name__ == '__main__':
    run()
View Code

相关文章:

  • 2022-12-23
  • 2021-11-13
  • 2021-09-10
  • 2021-05-17
  • 2022-01-16
  • 2021-05-11
猜你喜欢
  • 2022-12-23
  • 2021-09-09
  • 2022-12-23
  • 2021-06-13
  • 2021-12-02
相关资源
相似解决方案