01_socket的使用

01_socket.udp

01_socket的基本使用

import socket
"""
找到终端,ls一下,跳到桌面:cd Desktop/;跳到python就业班:cd python就业班/;

清空一下桌面:clear;ls一下;vim pd_01_socket的基本使用  打开查看内容,使用":q";关闭

python3 pd_01_socket的基本使用  运行.(必须严格执行上边的步骤打开)

用python2运行:python pd_01_socket的基本使用  打开;

技巧:ctrl + a  跳到行首
     ctrl + e  跳到行末
"""


def main():
    # 创建一个udp套接字
    udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

    # 可以使用套接字收发数据
    # udp_socket.sendto("发送内容",("对方的IP",端口port)元组类型别忘了加括号)
    udp_socket.sendto("ha ha ha",("169.254.4.219",8080))
    # 由于sendto()方法要求第一个参数为bytes(字节)类型,
    # 故在字符串"ha ha ha"前边加一个字母b使之变为bytes类型

    # 关闭套接字
    udp_socket.close()

# 导入模块后直接输入下方代码,再定义main函数进行书写代码主体
if __name__ == '__main__':
    main()
# 在终端如何运行?


02_从键盘上获取数据发送

import socket
"""
# 在终端如何运行?
找到终端,ls一下,跳到桌面:cd Desktop/;跳到python就业班:cd python就业班/;

清空一下桌面:clear;ls一下;vim pd_01_socket的基本使用  打开查看内容,使用":q";关闭

python3 pd_01_socket的基本使用  运行.(必须严格执行上边的步骤打开)

用python2运行:python pd_01_socket的基本使用  打开;

技巧:ctrl + a  跳到行首
     ctrl + e  跳到行末
"""


def main():
    # 创建一个udp套接字
    udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

    # 为实现从键盘获取数据,不再只传送固定的数据
    send_data = input("请输入要传送的数据:")

    # 可以使用套接字收发数据
    # udp_socket.sendto("发送内容",("对方的IP",端口port)元组类型别忘了加括号)
    # udp_socket.sendto(b"hahaha",("169.254.4.219",8080))
    # 由于内部发送内容变成了变量不在是一个字符串,无法使用在前边加一个字母b使之变为字节类型
    # 因此使用send_data.encode("utf-8")进行传输
    udp_socket.sendto(send_data.encode("utf-8"),("169.254.4.219",8080))
    
    # 关闭套接字
    udp_socket.close()
# 导入模块后直接输入下方代码,再定义main函数进行书写代码主体
if __name__ == '__main__':
    main()



03_循环发送

import socket
"""
# 在终端如何运行?
找到终端,ls一下,跳到桌面:cd Desktop/;跳到python就业班:cd python就业班/;

清空一下桌面:clear;ls一下;vim pd_01_socket的基本使用  打开查看内容,使用":q";关闭

python3 pd_01_socket的基本使用  运行.(必须严格执行上边的步骤打开)

用python2运行:python pd_01_socket的基本使用  打开;

技巧:ctrl + a  跳到行首
     ctrl + e  跳到行末
"""
# 实现循环输入
# 使用ctrl + c可以强制退出循环


def main():
    # 创建一个udp套接字
    udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

    while True:
        # 为实现从键盘获取数据,不再只传送固定的数据
        send_data = input("请输入要传送的数据:")

        # 可以使用套接字收发数据
        # udp_socket.sendto("发送内容",("对方的IP",端口port)元组类型别忘了加括号)
        # udp_socket.sendto(b"hahaha",("169.254.4.219",8080))
        # 由于内部发送内容变成了变量不在是一个字符串,无法使用在前边加一个字母b使之变为字节类型
        # 因此使用send_data.encode("utf-8")进行传输
        udp_socket.sendto(send_data.encode("utf-8"),("169.254.4.219",8080))
        
    # 关闭套接字
    # 全部传输完成后在关闭套接字,因此不要把关闭套接字放在循环中
    udp_socket.close()
# 导入模块后直接输入下方代码,再定义main函数进行书写代码主体
if __name__ == '__main__':
    main()



04_带有退出功能的循环发送

import socket
"""
# 在终端如何运行?
找到终端,ls一下,跳到桌面:cd Desktop/;跳到python就业班:cd python就业班/;

清空一下桌面:clear;ls一下;vim pd_01_socket的基本使用  打开查看内容,使用":q";关闭

python3 pd_01_socket的基本使用  运行.(必须严格执行上边的步骤打开)

用python2运行:python pd_01_socket的基本使用  打开;

技巧:ctrl + a  跳到行首
     ctrl + e  跳到行末
"""
# 实现循环输入
# 使用ctrl + c可以强制退出循环


def main():
    # 创建一个udp套接字
    udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

    while True:
        # 为实现从键盘获取数据,不再只传送固定的数据
        send_data = input("请输入要传送的数据:")
        
        # 若果输入exit,那么就退出程序
        if send_data == "exit":
            # 使用下方代码依旧是强退
            # udp_socket.close()
            # 使用continue?
            # 使用break退出整个while循环
            break

        # 可以使用套接字收发数据
        # udp_socket.sendto("发送内容",("对方的IP",端口port)元组类型别忘了加括号)
        # udp_socket.sendto(b"hahaha",("169.254.4.219",8080))
        # 由于内部发送内容变成了变量不在是一个字符串,无法使用在前边加一个字母b使之变为字节类型
        # 因此使用send_data.encode("utf-8")进行传输
        udp_socket.sendto(send_data.encode("utf-8"),("169.254.4.219",8080))
        # encode是编码的意思,将一个字符串类型编译成utf-8/gbk(windows用的形式)的格式
        
    # 关闭套接字
    # 全部传输完成后在关闭套接字,因此不要把关闭套接字放在循环中
    udp_socket.close()
# 导入模块后直接输入下方代码,再定义main函数进行书写代码主体
if __name__ == '__main__':
    main()



05_绑定端口用来接收数据

import socket


def main():
    # 1.创建套接字
    udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

    # 2.绑定一个本地信息,绑定的是一个元组类型
    localaddr = ("",41786) # 此处本地的IP如果唯一,就不用写了.端口的数值要求;大于1024
    udp_socket.bind(localaddr)  # 绑定,绑谁?绑上方变量内部的信息

    # 3.接收数据
    recv_data = udp_socket.recvfrom(1024)  # 1024表示本次接收的最大字节数
    # recv_data这个变量中存储的是一个元组(接收到的数据,(发送方的ip,端口))

    # 4.打印接收到的数据
    print(recv_data)
    # 5.关闭套接字
    udp_socket.close()

if __name__ == "__main__":
    main()

06_解析出接收的数据

import socket


def main():
    # 1.创建套接字
    udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

    # 2.绑定一个本地信息,绑定的是一个元组类型 必须绑定自己电脑的IP以及端口,其他的不行
    localaddr = ("",5566)  # 此处本地的IP如果唯一,就不用写了.端口的数值要求;大于1024
    udp_socket.bind(localaddr)  # 绑定,绑谁?绑上方变量内部的信息

    # 3.接收数据
    # 实现循环接收数据
    while True:
        recv_data = udp_socket.recvfrom(1024)  # 1024表示本次接收的最大字节数
        # recv_data这个变量中存储的是一个元组(接收到的数据,(发送方的ip,端口))

        recv_msg = recv_data[0]  # 存储接收的数据
        send_addr = recv_data[1]  # 存储发送方的地址信息

        # 4.打印接收到的数据
        # print(recv_data)
        # print("%s:%s"%(str(send_addr),recv_msg.decode("utf-8")))
        print("%s:%s" % (str(send_addr), recv_msg.decode("gbk")))
        # 由于要输出两个字符串类型,send_addr,recv_msg均不是字符串类型,用str()将send_addr
        # 强制转换成字符串类型,而recv_msg是由发送方发送过来已经编译成utf-8形式
        # (若是从windows发送过来的,则全是gbk形式,需要解码gbk),故此处要用decode进行解码

    # 5.关闭套接字
    udp_socket.close()

if __name__ == "__main__":
    main()

07_先绑定端口再循环发送

import socket
"""
# 在终端如何运行?
找到终端,ls一下,跳到桌面:cd Desktop/;跳到python就业班:cd python就业班/;

清空一下桌面:clear;ls一下;vim pd_01_socket的基本使用  打开查看内容,使用":q";关闭

python3 pd_01_socket的基本使用  运行.(必须严格执行上边的步骤打开)

用python2运行:python pd_01_socket的基本使用  打开;

技巧:ctrl + a  跳到行首
     ctrl + e  跳到行末
"""
# 实现循环输入
# 使用ctrl + c可以强制退出循环


def main():
    # 创建一个udp套接字
    udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    # 绑定本地信息
    # 如果不绑定就会系统随机分配端口,每次调用程序都会分配不同的端口,发送方可以不绑定,接收方绑定
    udp_socket.bind(("",7890))
    while True:
        # 为实现从键盘获取数据,不再只传送固定的数据
        send_data = input("请输入要传送的数据:")

        # 可以使用套接字收发数据
        # udp_socket.sendto("发送内容",("对方的IP",端口port)元组类型别忘了加括号)
        # udp_socket.sendto(b"hahaha",("169.254.4.219",8080))
        # 由于内部发送内容变成了变量不在是一个字符串,无法使用在前边加一个字母b使之变为字节类型
        # 因此使用send_data.encode("utf-8")进行传输
        udp_socket.sendto(send_data.encode("utf-8"),("169.254.4.219",8080))
        
    # 关闭套接字
    # 全部传输完成后在关闭套接字,因此不要把关闭套接字放在循环中
    udp_socket.close()
# 导入模块后直接输入下方代码,再定义main函数进行书写代码主体
if __name__ == '__main__':
    main()



08_使用同一个套接字进行收发数据

import socket
"""同一个套接字可以收数据也可以发数据即同时收发数据x"""


def main():
    # 创建一个udp套接字
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    # 获取对方的IP
    dest_addr = input("请输入对方的IP:")
    dest_port = int(input("请输入对方的端口:"))

    # 为实现从键盘获取数据,不再只传送固定的数据
    send_data = input("请输入要传送的数据:")

    # 可以使用套接字收发数据
    # udp_socket.sendto("发送内容",("对方的IP",端口port)元组类型别忘了加括号)
    # udp_socket.sendto(b"hahaha",("169.254.4.219",8080))
    # 由于内部发送内容变成了变量不在是一个字符串,无法使用在前边加一个字母b使之变为字节类型
    # 因此使用send_data.encode("utf-8")进行传输
    udp_socket.sendto(send_data.encode("utf-8"), (dest_addr, dest_port))

    # 关闭套接字
    udp_socket.close()


# 导入模块后直接输入下方代码,再定义main函数进行书写代码主体
if __name__ == '__main__':
    main()

09_案例:udp聊天

"""
import socket


def main():

    # 创建套接字
    udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    # 创建完套接字,要想成功的接收到发送过来的信息,首先要有一个固定的端口号-绑定一个端口

    # 绑定本地信息
    udp_socket.bind("",7788)
    # while循环处理收发信息
    while True:
        # 发送:
        # 获取要发送的内容
        dest_ip = input("请输入要发送目标的ip:")
        dest_port = input("请输入要发送目标的port:")
        send_massage = input("请输入要发送的信息:")
        udp_socket.sendto(send_massage.encode("utf-8"),(dest_ip,dest_port))  # 产生
        # dest_ip,dest_port的需求,即在下方定义,定义完成后发现应该在前边进行定义,复制粘贴即可

        # 接收数据并显示
        recv_data = udp_socket.recvfrom(1024)  # recvfrom()方法返回的是一个元组类型
        print("%s:%S" % (str(recv_data[1]),recv_data[0].encode("utf-8")))
        # 除了与windows进行通信以外都用utf-8进行转化,windows用gbk.[1]代表元组内部第2部分
        # 注意:一个具有独立功能的代码块要封装到一个函数之中



if __name__ == '__main__':
    main()

"""
    # 注意:一个具有独立功能的代码块要封装到一个函数之中,以上代码做如下修改:将与发送和接收相关的
    # 代码分别封装在发送,接收两个函数中

import socket


def send_data(udp_socket):  # 定义成函数后,是否需要传参,要具体看函数内容,新定义的变量不用考虑
    # 出现未知变量调用方法时,要考虑传递参数的问题
    """发送数据"""
    # 获取要发送的内容
    dest_ip = input("请输入要发送目标的ip:")
    dest_port = int(input("请输入要发送目标的port:"))
    send_massage = input("请输入要发送的信息:")
    udp_socket.sendto(send_massage.encode("utf-8"), (dest_ip, dest_port))  # 产生
    # dest_ip,dest_port的需求,即在下方定义,定义完成后发现应该在前边进行定义,复制粘贴即可


def recv_data(udp_socket):
    """接收数据并显示"""
    recv_data = udp_socket.recvfrom(1024)  # recvfrom()方法返回的是一个元组类型
    print("%s:%s" % (str(recv_data[1]), recv_data[0].decode("utf-8")))
    # 除了与windows进行通信以外都用utf-8进行转化,windows用gbk.[1]代表元组内部第2部分
    # 注意:一个具有独立功能的代码块要封装到一个函数之中


def main():
    """完成主要的主体流程"""
    # 创建套接字
    udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    # 创建完套接字,要想成功的接收到发送过来的信息,首先要有一个固定的端口号-绑定一个端口

    # 绑定本地信息
    udp_socket.bind(("",7788))
    # while循环处理收发信息
    while True:
        # 发送:
        send_data(udp_socket)

        # 接收数据并显示
        recv_data(udp_socket)



if __name__ == '__main__':
    main()

10_案例:可控制操作

import socket


def send_data(udp_socket):  # 定义成函数后,是否需要传参,要具体看函数内容,新定义的变量不用考虑
    # 出现未知变量调用方法时,要考虑传递参数的问题
    """发送数据"""
    # 获取要发送的内容
    dest_ip = input("请输入要发送目标的ip:")
    dest_port = int(input("请输入要发送目标的port:"))
    send_massage = input("请输入要发送的信息:")
    udp_socket.sendto(send_massage.encode("utf-8"), (dest_ip, dest_port))  # 产生
    # dest_ip,dest_port的需求,即在下方定义,定义完成后发现应该在前边进行定义,复制粘贴即可


def recv_data(udp_socket):
    """接收数据并显示"""
    recv_data = udp_socket.recvfrom(1024)  # recvfrom()方法返回的是一个元组类型
    print("%s:%s" % (str(recv_data[1]), recv_data[0].decode("utf-8")))
    # 除了与windows进行通信以外都用utf-8进行转化,windows用gbk.[1]代表元组内部第2部分
    # 注意:一个具有独立功能的代码块要封装到一个函数之中


def main():
    """完成主要的主体流程"""
    # 创建套接字
    udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    # 创建完套接字,要想成功的接收到发送过来的信息,首先要有一个固定的端口号-绑定一个端口

    # 绑定本地信息
    udp_socket.bind(("",7788))
    # 若是不绑定,发送数据时系统会随机分配端口,在当次程序运行过程中,使用系统分配的端口可以实现消息回发
    # while循环处理收发信息
    while True:
        """用这样的方法以实现连续的收/发消息"""
        print("*****洋仔聊天器*****")
        print("1.发送消息")
        print("2.接收消息")
        print("0.退出系统")
        it = input("请选择要使用的功能:")
        if it == "1":
            # 发送:
            send_data(udp_socket)
        elif it == "2":
            # 接收数据并显示
            recv_data(udp_socket)
        elif it == "0":
            break
        else:
            print("输入有误,请重新输入!")


if __name__ == '__main__':
    main()

02_socket.tcp

01_tcp.client

import socket


def main():
    
    # 1. 创建tcp套接字
    tcp_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    # 此处若在路径中含有名为socket的文件,程序会出错,找不到AF_INET,导入模块的查找顺序是,
    # 先从路径中寻找,没有再从系统中寻找.
    # 使用SOCK_DGRAM创建套接字是创建的udp套接字,使用SOCK_STREAM创建的套接字是tcp套接字
    
    # 2. 链接服务器
    sever_ip = input("请输入服务器ip:")
    sever_port = int(input("请输入服务器port:"))
    # 这里一定要注意转换!
    sever_addr = (sever_ip,sever_port)
    tcp_socket.connect(sever_addr)
    # tcp_socket.connect("192.168.146.130",8080)固定ip和port时,这一行代码等价于上边四行代码
    # connect()方法内部是一个元组类型

    # 3. 接收/发送数据
    send_msg = input("请输入发送数据:")
    tcp_socket.send(send_msg.encode("utf-8"))
    # 此处使用的发送的方法是send 与sendto 的不同之处在于,他它只需要发送编码的信息即可,不
    # 用再输入接收程序的端口信息,就像打电话一样,打过去之后说多少话都可以,不用再打一遍

    # 4. 关闭套接字
    tcp_socket.close()
if __name__ == "__main__":
    main()

02_tcp.sever

import socket


def main():
    # 1. 买个手机(创建一个套接字:socket)
    tcp_sever_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)  # 这个套接字是用来监听的

    # 2. 插上手机卡(绑定本地信息:bind)
    tcp_sever_socket.bind(("",7890))

    # 3. 设置手机为正常接听状态(使套接字由主动变成被动套接字listen)
    tcp_sever_socket.listen(128)

    print("****1****")
    # 4. 静待他人拨打电话(静待客户链接:accept)
    new_client_socket,client_addr = tcp_sever_socket.accept()  # 新的套接字标记着客户端
    # 监听套接字默认会堵塞,一直堵塞到有一个新的客户端链接了你,就可以解堵塞,
    # 并且解堵塞的时候会有一个元组类型的返回值,new_client_socket保存的是accept()
    # 产生的新的套接字,client_addr保存客户端的信息
    print(client_addr)
    print("****2******")

    # 服务器先收,客户端先发
    # 接收客户端发送过来的数据
    # 使用新的客户端调用接收和发送(就像拨打10086,是客服进行处理而不是总机)
    recv_data = new_client_socket.recv(1024)  # 和recvfeom很类似,返回值是表示接收数据的字节对象
    # (一组数字b'\xe7\xbb\x99\xe6\x9e\xaa')。因为,client_addr
    # 保存客户端的信息没有必要再一遍一遍的发送,而recvfrom内部还有谁发过来的信息
    # 因为new_client_socket标记着客户端,知道客户端信息(ip,port)所以返回的时候仅仅有数据
    print(recv_data)
    print("发送过来的信息是:%s" % recv_data.decode("utf-8"))

    # 回送一部分数据给客户端
    new_client_socket.send("hahahahahaha*****ok****".encode("utf-8"))

    # 关闭套接字
    tcp_sever_socket.close()
    new_client_socket.close()
    # 创建了几个套接字就要关闭几个套接字


if __name__ == "__main__":
    main()

03_循环为多个客户端服务的服务器

import socket


def main():
    # 如同到银行办业务,领号,一个一个客户(客户端)接受服务(服务器)

    # 1. 买个手机(创建一个套接字:socket)
    tcp_sever_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)  # 这个套接字是用来监听的

    # 2. 插上手机卡(绑定本地信息:bind)
    tcp_sever_socket.bind(("",7890))

    # 3. 设置手机为正常接听状态(使套接字由主动变成被动套接字listen)
    tcp_sever_socket.listen(128)

    while True:

        print("等待一个新的客户端的到来")
        # 4. 静待人拨打电话(静待客户链接:accept)
        new_client_socket,client_addr = tcp_sever_socket.accept()  # 新的套接字标记着客户端
        # 监听套接字默认会堵塞,一直堵塞到有一个新的客户端链接了你,就可以解堵塞,
        # 并且解堵塞的时候会有一个元组类型的返回值,new_client_socket保存的是accept()
        # 产生的新的套接字,client_addr保存客户端的信息
        print("新来的客户端信息是:%s" % str(client_addr))

        # 服务器先收,客户端先发
        # 接收客户端发送过来的数据
        # 使用新的客户端调用接收和发送(就像拨打10086,是客服进行处理而不是总机)
        recv_data = new_client_socket.recv(1024)  # 和recvfeom很类似,返回值是表示接收数据的字节对象
        # (一组数字b'\xe7\xbb\x99\xe6\x9e\xaa')。因为,client_addr
        # 保存客户端的信息没有必要再一遍一遍的发送,而recvfrom内部还有谁发过来的信息
        # 因为new_client_socket标记着客户端,知道客户端信息(ip,port)所以返回的时候仅仅有数据
        print(recv_data)
        print("客户端发送过来的请求:%s" % recv_data.decode("utf-8"))

        # 回送一部分数据给客户端
        new_client_socket.send("hahahahahaha*****ok****".encode("utf-8"))

        # 关闭套接字
        # 关闭的是客户端的套接字,关闭accept()返回的套接字,意味着不会再为这个客户端服务
        new_client_socket.close()
        print("服务结束,欢迎下次光临!")
    tcp_sever_socket.close()
    # 如果将监听套接字关闭l,那么会导致不能再次等待新客户端的到来,即socket.accept()会失败

    # 创建了几个套接字就要关闭几个套接字


if __name__ == "__main__":
    main()

04_循环为多个客户端服务的服务器并且多次服务一个客户端

import socket


def main():
    # 如同到银行办业务,领号,一个一个客户(客户端)接受服务(服务器)
    # 为一个客户提供多次服务,就像拨打10086,必须由客户(客户端)挂断,客户端挂断后程序继续执行,等待新的客户端

    # 1. 买个手机(创建一个套接字:socket)
    tcp_sever_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)  # 这个套接字是用来监听的

    # 2. 插上手机卡(绑定本地信息:bind)
    tcp_sever_socket.bind(("",7890))

    # 3. 设置手机为正常接听状态(使套接字由主动变成被动套接字listen)
    tcp_sever_socket.listen(128)

    while True:

        print("等待一个新的客户端的到来")
        # 4. 静待人拨打电话(静待客户链接:accept)
        new_client_socket,client_addr = tcp_sever_socket.accept()  # 新的套接字标记着客户端
        # 监听套接字默认会堵塞,一直堵塞到有一个新的客户端链接了你,就可以解堵塞,
        # 并且解堵塞的时候会有一个元组类型的返回值,new_client_socket保存的是accept()
        # 产生的新的套接字,client_addr保存客户端的信息
        print("新来的客户端信息是:%s" % str(client_addr))

        while True:
        
            # 服务器先收,客户端先发
            # 接收客户端发送过来的数据
            # 使用新的客户端调用接收和发送(就像拨打10086,是客服进行处理而不是总机)
            recv_data = new_client_socket.recv(1024)  # 和recvfeom很类似,返回值是表示接收数据的字节对象
            # (一组数字b'\xe7\xbb\x99\xe6\x9e\xaa')。因为,client_addr
            # 保存客户端的信息没有必要再一遍一遍的发送,而recvfrom内部还有谁发过来的信息
            # 因为new_client_socket标记着客户端,知道客户端信息(ip,port)所以返回的时候仅仅有数据
            print(recv_data)
            print("客户端发送过来的请求:%s" % recv_data.decode("utf-8"))
            # 如果recv()解堵塞,那么有两种方式:
            # 1.客户端发送过来数据
            # 2.客户端调用close()从而导致了recv()解堵塞并且recv()的返回值为空
            if recv_data:
                # if 后边跟字符串,列表,元组...只要不空即为真,空为假
                # 回送一部分数据给客户端
                new_client_socket.send("hahahahahaha*****ok****".encode("utf-8"))
            else:
                break
                # 程序内部有两个while True,一个break,break跳出的是离它最近的while True,与另一个一毛钱关系都没有

        # 关闭套接字
        # 关闭的是客户端的套接字,关闭accept()返回的套接字,意味着不会再为这个客户端服务
        new_client_socket.close()
        print("服务结束,欢迎下次光临!")
    tcp_sever_socket.close()
    # 如果将监听套接字关闭l,那么会导致不能再次等待新客户端的到来,即socket.accept()会失败

    # 创建了几个套接字就要关闭几个套接字


if __name__ == "__main__":
    main()

05_文件下载.client

import socket


def main():
    """客户端"""

    # 1.创建套接字
    tcp_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

    # 2.获取服务器的ip和port
    # 客户端可以不用绑定,一般也不绑定
    sever_ip = input("输入服务器的ip:")
    sever_port = int(input("请输入服务器的port:"))

    # 3.链接服务器
    # connect()方法内部是一个元组
    tcp_socket.connect((sever_ip,sever_port))

    # 4.获取下载的文件名字
    download_file_name = input("请输入要下载的文件的名字:")
    # 5.将文件名字发送给服务器
    tcp_socket.send(download_file_name.encode("utf-8"))
    # 6.接收文件中的数据
    recv_file_data = tcp_socket.recv(1024*1024)  # 1024--->1k  1024 * 1024--->1k * 1024 = 1M  1024 * 1024 * 1024 = 1g
    # 7.保存接收的数据到一个文件中
    if recv_file_data:
        with open("附件" + download_file_name,"wb") as f:
            # "+"表示字符串拼接;字符串+字符串:字符串拼接."w"表示以w(写)的方式打开;
            # "b"表示以二进制的模式 .(之前的bytes类型其实就是二进制)
            #  为什么要使用二进制的模式,因为recv()得到的数据就是二进制的数据,所以此处
            # 使用二进制的方式打开,直接省去了先encode()再decode()过程
            f.write(recv_file_data)

    # 8.关闭套接字
    tcp_socket.close()
    pass

if __name__ == '__main__':
    main()

06_文件下载.sever

import socket


def send_file_to_client(new_client_socket,client_addr):

    # 1.接收客户端发送过来的要下载的文件名
    file_name  = new_client_socket.recv(1024).decode("utf-8")
    print("客户端 %s 发送过来的要下载的文件名是:%s" % (str(client_addr),file_name))

    # 2.打开这个文件,读取数据
    # 此处不适合使用with因为with不仅是打开文件后发现异常会调用close()若打不开文件同样发现异常会调用close()
    # with的前提是open()能够打开,打不开就挂了,如果用open的打开模式中有w,意味着写,写就意味着新建文件,
    # 在有权限的前提下新建一个文件是不可能失败的
    # 所以:若是新建一个文件,二话不说直接用with,但是要是以read的方式打开一个文件去为了读数据,这个文件是有不存在的可能的
    # 故此处用try的方式
    file_content = None  # 给变量赋初始值
    try:
        f = open(file_name,"rb")
        file_content = f.read()
        # 打开以后定义一个变量将内容读取出来
        f.close()
        # 读完之后关闭文件
    except Exception as ret:
        # ret(result):是定义的变量,相当于定义了一个类Exception的对象
        # Exception是针对异常提出塞外类
        print("没有要下载的文件:%s " % file_name)

    if file_content:
        # 3.发送文件数据给客户端
        new_client_socket.send(file_content)
   # else:
   #     break  这样写为啥不对? 是因为上边exception已经进行错误监测了?



def main():
    # 1. 买个手机(创建一个套接字:socket)
    tcp_sever_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)  # 这个套接字是用来监听的

    # 2. 插上手机卡(绑定本地信息:bind)
    tcp_sever_socket.bind(("",7890))

    # 3. 设置手机为正常接听状态(使套接字由主动变成被动套接字listen)
    tcp_sever_socket.listen(128)

    while True:

        # 4. 静待他人拨打电话(静待客户链接:accept)
        new_client_socket,client_addr = tcp_sever_socket.accept()
        
        # 5.调用发送文件函数,完成为客户端服务(由于这一部分功能独立,所以单独定义函数)
        send_file_to_client(new_client_socket,client_addr)
        # 6.1关闭客户端套接字
        new_client_socket.close()

    # 6.2关闭监听套接字
    tcp_sever_socket.close()
        # 创建了几个套接字就要关闭几个套接字


if __name__ == "__main__":
    main()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值