python——网络编程

网络通信示意图

这里写图片描述

socket编程网络步骤图

这里写图片描述

客户端

import socket
client=socket.socket()#声明socket类型,同时生成socket连接对象
client.connect(("localhost",6969))#连接地址(IP地址和端口)

client.send(b"hello world")#python3只能发byte字节类型
data=client.recv(1024)
print("recv:",data)

client.close()

服务端

import  socket
server=socket.socket()#声明类型,使用的是默认类型
server.bind(("localhost",6969))#绑定要监听的端口
server.listen()#监听

print("我要开始等电话了")
#conn就是客户端连过来而在服务器端为其生成的一个连接实例
conn,addr=server.accept()#等电话打进来,conn就是客户端连过来而在服务器端为其生成的一个连接实例,addr链接的地址
print(conn,addr)             #('127.0.0.1', 3020)是地址

print("电话来了")
data=conn.recv(1024)
print("recv:",data)
conn.send(data.upper())#发送给客户端

server.close()

能连续发送命令给服务端,服务端给客户端返回执行的命令结果

服务端代码

import socket
import os
import time
server=socket.socket()
server.bind(("localhost",9999))
server.listen()
while True:
    coon,addr=server.accept()
    print("new conn:",addr)
    while True:
        print("等待新指令")
        data=coon.recv(1024)
        if not data:
            print("客户端已断开")
            break
        print("执行指令:",data.decode())
        cmd_res=os.popen(data.decode()).read()#接受字符串,执行结果也是字符串
        print("before send",len(cmd_res))
        if len(cmd_res)==0:
            cmd_res="cmd has no output"
        '''
        下面发送的两个包在一起,就有可能出现粘包的现象,因为缓冲区会把这两条语句当做一条语句发送
        '''
        coon.send(str(len(cmd_res.encode())).encode("utf-8"))#先发大小给客户端
        #time.sleep(0.5)#这样也能解决粘包的问题,但是会产生延时,不适合实时通信的
        client_ack=coon.recv(1024)#等待客户端确认,这样就不会粘包了
        print("ack from client:",client_ack.decode())
        coon.send(cmd_res.encode("utf-8"))
        print("send done")
server.close()

客户端

import socket
client=socket.socket()
client.connect(("localhost",9999))
while True:
    cmd=input(">>:").strip()
    if len(cmd)==0: continue
    client.send(cmd.encode("utf-8"))
    cmd_res_size=client.recv(1024)#接受命令结果的长度
    print("命令结果的大小:",cmd_res_size)
    client.send("可以开始接收了".encode("utf-8"))
    received_size=0
    received_data=b""
    while received_size<int(cmd_res_size.decode()):
        data=client.recv(1024)
        received_size+=len(data)#每次收到的可能小于1024(recv(1024)这个只是说每次最大能接受1024,而不是每次就接受1024,这个值一般最大为8792),所以必须用len判断
        print(data.decode())
        received_data+=data
    else:
        print("cmd res receive done...",received_size)
        print(received_data.decode())

client.close()

单用户使用get下载文件,并能验证md5值

下载文件步骤

这里写图片描述

服务端代码

import socket
import os
import hashlib
import time
server=socket.socket()
server.bind(("localhost",9999))
server.listen()
while True:
    coon,addr=server.accept()
    print("new conn:",addr)
    while True:
        print("等待新指令")
        data=coon.recv(1024)
        if not data:
            print("客户端已断开")
            break
        cmd,filename=data.decode().split()
        print(filename)
        if os.path.isfile(filename):#判断是否为文件
            f=open(filename,"rb")
            m=hashlib.md5()
            file_size=os.stat(filename).st_size#获取文件的大小
            coon.send(str(file_size).encode())#发送文件长度
            coon.recv(1024)#等待确认
            for line in f:
                m.update(line)
                coon.send(line)
            print("file md5",m.hexdigest())
            f.close()
            coon.send(m.hexdigest().encode())#给客户端发送md5值
        print("send done")
server.close()

客户端代码

import socket
import hashlib
client=socket.socket()
client.connect(("localhost",9999))
while True:
    cmd=input(">>:").strip()
    if len(cmd)==0: continue
    if cmd.startswith("get"):
        client.send(cmd.encode())
        server_response=client.recv(1024)
        print("server response:",server_response)
        client.send(b"ready to recv file")
        file_total_size=int(server_response.decode())
        received_size=0
        filename=cmd.split()[1]
        f=open(filename+".new","wb")
        m=hashlib.md5()
        while received_size<file_total_size:
            '''
            通过下面的这个对size的控制可以防止位置1和位置2处发生粘包的发生,因为在接收文件最后不足1024的时候剩多少,我收多少
            (粘包发生的原因就是文件收到最后不足1024的时候,可能将md5和文件不足1024的部分一起接收了,但是也有可能不发生粘包,因为每次发送接收的不一定就是1024)
            '''
            if file_total_size-received_size>1024:#要收不止一次
                size=1024
            else:
                size=file_total_size-received_size

            data=client.recv(size)#位置1
            received_size+=len(data)
            m.update(data)
            f.write(data)
            print(file_total_size,received_size)
        else:
            new_file_md5=m.hexdigest()
            print("file recv done")
            f.close()
        server_file_md5=client.recv(1024)#位置2
        print("server file md5:",server_file_md5)
        print("client file md5:",new_file_md5)
client.close()

* 支持多用户同时上传下载(并发)——socketServer,简例*

创建一个sockerServer的步骤

这里写图片描述

服务端

import socketserver
class MyTCPHandler(socketserver.BaseRequestHandler):
    def handle(self):
        while True:
            try:
                self.data=self.request.recv(1024).strip()
                print("{} wrote".format(self.client_address[0]))
                print(self.data)
                # if not self.data:#客户端断了
                #     print(self.client_address,"断开了")
                #     break
                self.request.send(self.data.upper())
            except ConnectionResetError as e:
                print("err",e)
                break
if __name__== "__main__":
    HOST,PORT="localhost",9999
    #创建服务端,绑定主机端口9999
    server=socketserver.ThreadingTCPServer((HOST,PORT),MyTCPHandler)#多线程并发
    #server=socketserver.ForkingTCPServer((HOST,PORT),MyTCPHandler)#多进程并发,在windows上不好使,在Linux上可以,因为windows上的进程不能通过fork实现
    server.serve_forever()

客户端

import socket
client=socket.socket()#声明socket类型,同时生成socket连接对象
client.connect(("localhost",9999))#连接地址(IP地址和端口)

while True:
    msg=input(">>:").strip()
    client.send(msg.encode("utf-8"))#python3只能发byte字节类型
    data=client.recv(1024)
    print("recv:",data.decode())

client.close()

简易版的ftp并发上传

客户端代码

import socket
import os
import json
client=socket.socket()
client.connect(("localhost",9999))
class FtpClient(object):
    def __init__(self):
        self.client=socket.socket()
    def help(self):
        msg='''
        ls
        pwd
        cd ../..
        get filename
        put filename
        '''
        print(msg)
    def connect(self,ip,port):
        self.client.connect((ip,port))

    def interactive(self):
        #self.authenticate()
        while True:
            cmd=input(">>").strip()
            if len(cmd)==0: continue
            cmd_str=cmd.split()[0]
            if hasattr(self,"cmd_%s"%cmd_str):#反射
                func=getattr(self,"cmd_%s"%cmd_str)
                func(cmd)
            else:
                self.help()
    def cmd_put(self,*args):
        cmd_split=args[0].split()
        if len(cmd_split)>1:
            filename=cmd_split[1]
            if os.path.isfile(filename):
                filesize=os.stat(filename).st_size
                msg_dic={
                    "action":"put",
                    "filename":filename,
                    "size":filesize,
                    "overridden":True
                }
                self.client.send(json.dumps(msg_dic).encode("utf-8"))
                print("send",json.dumps(msg_dic).encode("utf-8"))
                #防止粘包,等服务器确认
                server_response=self.client.recv(1024)
                f=open(filename,"rb")
                for line in f:
                    self.client.send(line)
                else:
                    print("file upload success...")
                    f.close()
            else:
                print(filename,"is not exist")
    def cmd_get(self):
        pass
ftp=FtpClient()
ftp.connect("localhost",9999)
ftp.interactive()

服务端代码

import socketserver
import json
import os
class MyTCPHandler(socketserver.BaseRequestHandler):#括号里面的是固定的
    def put(self,*args):
        '''接收客户端文件'''
        cmd_dic=args[0]
        filename=cmd_dic["filename"]
        filesize=cmd_dic["size"]
        if os.path.isfile(filename):
            f=open(filename+".new","wb")
        else:
            f=open(filename,"wb")
        self.request.send(b"200 ok")
        received_size=0
        while received_size<filesize:
            data=self.request.recv(1024)
            f.write(data)
            received_size+=len(data)
        else:
            print("file [%s] has uploaded..."%filename)
    def handle(self):#这里面的才是跟客户端交互的
        while True:
            try:
                self.data=self.request.recv(1024).strip()
                print("{} wrote".format(self.client_address[0]))
                print(self.data)
                cmd_dic=json.loads(self.data.decode())
                action=cmd_dic["action"]
                if hasattr(self,action):#判断是否有action所对应的字符串的函数
                    func=getattr(self,action)#获取action对应的函数
                    func(cmd_dic)#执行其对应的函数
            except ConnectionResetError as e:#捕获异常的
                print("err",e)
                break

'''
下面是固定的写法
'''
if __name__== "__main__":
    HOST,PORT="localhost",9999
    #创建服务端,绑定主机端口9999
    server=socketserver.ThreadingTCPServer((HOST,PORT),MyTCPHandler)
    server.serve_forever()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值