【python进阶 笔记ing】网络编程

目录

1.UDP

1.1. UDP发送数据

1.2. UDP循环接收

1.3. UDP收发 :

1.4. UDP聊天(非多线程)

1.5 UDP聊天(多线程)

2. TCP

2.1. TCP client

2.2. TCP server (单线程)

2.3. TCP多线程(待续)

2.4. TCP简单文件下载


函数 socket.socket 创建一个 socket,该函数带有两个参数:

  • Address Family:可以选择 AF_INET(用于 Internet 进程间通信) 或者 AF_UNIX(用于同一台机器进程间通信),实际工作中常用AF_INET
  • Type:套接字类型,可以是 SOCK_STREAM(流式套接字,主要用于 TCP 协议)或者 SOCK_DGRAM(数据报套接字,主要用于 UDP 协议)

1.UDP

1.1. UDP发送数据

import socket

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

    # 绑定本地信息
    localaddr = ("", 7890)
    udp_socket.bind(localaddr)  # 绑定后用固定端口发送,不然每次会随机分配端口

    while True:

        # 从键盘获取数据
        send_data = input("请输入要发送的数据:")

        # 可以使用套接字收发数据
        # udp_socket.sendto("hahahah", 对方的ip以及port)
        # udp_socket.sendto(b"hahahah------1----", ("192.168.33.53", 8080))
        udp_socket.sendto(send_data.encode("utf-8"), ("192.168.33.42", 8080))


    # 关闭套接字
    udp_socket.close()
	

if __name__ == "__main__":
    main()

1.2. UDP循环接收

import socket

def main():
    # 1. 创建套接字
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    # 2. 绑定一个本地信息
    localaddr = ("", 7788)
    udp_socket.bind(localaddr)  # 必须绑定自己电脑的ip以及port,其他的不行

    # 3. 接收数据
    while True:
        recv_data = udp_socket.recvfrom(1024)
        # recv_data这个变量中存储的是一个元组(接收到的数据,(发送方的ip, port))
        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")))  # win中文时要用gbk不能用utf-8
    # 5. 关闭套接字
    udp_socket.close()

if __name__ == "__main__":
    main()

1.3. UDP收发 :

    socket是全双工的通信方式,是可以同时收发的。

import socket


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

    # 获取对方的ip/port
    dest_ip = input("请输入对方的ip:")
    dest_port = int(input("请输入对方的port:"))  # 真正使用时用try捕获异常更严谨

    # 从键盘获取数据
    send_data = input("请输入要发送的数据:")

    # 可以使用套接字收发数据
    # udp_socket.sendto("hahahah", 对方的ip以及port)
    udp_socket.sendto(send_data.encode("utf-8"), (dest_ip, dest_port))

    # 接收回送过来的数据
    recv_data = udp_socket.recvfrom(1024)
    # 套接字是一个可以同时 收发数据
    print(recv_data)

    # 关闭套接字
    udp_socket.close()


if __name__ == "__main__":
    main()

1.4. UDP聊天(非多线程)

import socket


def send_msg(udp_socket):
    """send message"""
    dest_ip = input("please input ip:")
    dest_port = int(input("please input port:")) 
    send_data = input("please input data what you would send:")
    udp_socket.sendto(send_data.encode("utf-8"), (dest_ip, dest_port))


def recv_msg(udp_socket):
    recv_data = udp_socket.recvfrom(1024)
    print("%s:%s" % (str(recv_data[1]), recv_data[0].decode("gbk"))) # 如果是win用kgb


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

    # 绑定信息
    udp_socket.bind(("", 7788))

    #循环处理
    while  True:
        print("-----xxx聊天器-----")
        print("1:send message")
        print("2:receive message")
        print("0:quit")
        op = input("please input function:")

        if op == "1":
            # 发送
            send_msg(udp_socket)
        elif op == "2":
            # 接收并显示
            recv_msg(udp_socket)
        elif op == "0":
            break
        else:
            print("输入有误请重新输入...")


if __name__ == "__main__":
    main()

1.5 UDP聊天(多线程)

https://blog.csdn.net/qq_23996069/article/details/104050575

2. TCP

2.1. TCP client

import socket


def main():
    # 1. 创建tcp的套接字
    tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # 2. 链接服务器
    # tcp_socket.connect(("192.168.33.11", 7788))
    server_ip = input("请输入要链接的服务器的ip:")
    server_port = int(input("请输入要链接的服务器的port:"))
    server_addr = (server_ip, server_port)
    tcp_socket.connect(server_addr)

    # 3. 发送数据/接收数据
    send_data = input("请输入要发送的数据:")
    tcp_socket.send(send_data.encode("utf-8"))

    # 4. 关闭套接字
    tcp_socket.close()


if __name__ == "__main__":
    main()

2.2. TCP server (单线程)

如果想要完成一个tcp服务器的功能,需要的流程如下:

  1. socket创建一个套接字
  2. bind绑定ip和port
  3. listen使套接字变为可以被动链接
  4. accept等待客户端的链接
  5. recv/send接收发送数据

本例无法多线程,一次只能为一个客户端服务。一个客户端关闭后为下一个客户端服务。

import socket


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

    # 2绑定本地信息 bind
    tcp_server_socket.bind(("", 7890))
    
    # 3让默认的套接字由主动变为被动 listen
    tcp_server_socket.listen(128)

    # 循环目的:调用多次accept,从而为多个客户端服务
    while True:
        # 4等待客户端的链接 accept
        print("waiting a new client...")
        new_client_socket, client_addr =  tcp_server_socket.accept()
        print("new clinet %s is come" % str(client_addr))
        
        # 循环目的: 为同一个客户端 服务多次
        while True:
            
            # 接收客户端发送过来的请求
            recv_data = new_client_socket.recv(1024)
            print("客户端发送过来的请求是: %s." % recv_data.decode("utf-8"))

            # 如果recv解堵塞,那么有2种方式:
            # 1. 客户端发送过来数据
            # 2. 客户端调用close导致而了 这里 recv解堵塞
            if recv_data:
                # 回送一部分数据给客户端
                new_client_socket.send("hahahghai-----ok-----".encode("utf-8"))
            else:
                break

        # 关闭套接字
        # 关闭accept返回的套接字 意味着 不会在为这个客户端服务
        new_client_socket.close()
        print("本次服务完毕")
        
    # 关闭监听套接字,则不能再等待新的客户端到来
    tcp_server_socket.close()


if __name__ == "__main__":
    main()

tcp注意点

  1. tcp服务器一般情况下都需要绑定,否则客户端找不到这个服务器
  2. tcp客户端一般不绑定,因为是主动链接服务器,所以只要确定好服务器的ip、port等信息就好,本地客户端可以随机
  3. tcp服务器中通过listen可以将socket创建出来的主动套接字变为被动的,这是做tcp服务器时必须要做的
  4. 当客户端需要链接服务器时,就需要使用connect进行链接,udp是不需要链接的而是直接发送,但是tcp必须先链接,只有链接成功才能通信
  5. 当一个tcp客户端连接服务器时,服务器端会有1个新的套接字,这个套接字用来标记这个客户端,单独为这个客户端服务
  6. listen后的套接字是被动套接字,用来接收新的客户端的链接请求的,而accept返回的新套接字是标记这个新客户端的
  7. 关闭listen后的套接字意味着被动套接字关闭了,会导致新的客户端不能够链接服务器,但是之前已经链接成功的客户端正常通信。
  8. 关闭accept返回的套接字意味着这个客户端已经服务完毕
  9. 当客户端的套接字调用close后,服务器端会recv解堵塞,并且返回的长度为0,因此服务器可以通过返回数据的长度来区别客户端是否已经下线

2.3. TCP多线程(待续)

2.4. TCP简单文件下载

简单下载实例,只能小文件,单线程。

客户端:

import socket


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

    # 2. 获取服务器的ip port
    dest_ip = input("请输入下载服务器的ip:")
    dest_port = int(input("请输入下载服务器的port:"))

    # 3. 链接服务器
    tcp_socket.connect((dest_ip, dest_port))

    # 4. 获取下载的文件名字
    download_file_name = input("请输入要下载的文件名字:")

    # 5. 将文件名字发送到服务器
    tcp_socket.send(download_file_name.encode("utf-8"))

    # 6. 接收文件中的数据
    recv_data = tcp_socket.recv(1024)  # 1024--->1K  1024*1024--->1k*1024=1M 1024*1024*124--->1G

    if recv_data:
        # 7. 保存接收到的数据到一个文件中
        with open("[新]" + download_file_name, "wb") as f:
            f.write(recv_data)

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


if __name__ == "__main__":
    main()

服务端:

import socket


def send_file_2_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))

    file_content = None
    # 2. 打开这个文件,读取数据
    try:
        f = open(file_name, "rb")
        file_content = f.read()
        f.close()
    except Exception as ret:
        print("没有要下载的文件(%s)" % file_name)


    # 3. 发送文件的数据给客户端
    if file_content:
        new_client_socket.send(file_content)



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

    # 2. 绑定本地信息 bind
    tcp_server_socket.bind(("", 7890))

    # 3. 让默认的套接字由主动变为被动 listen
    tcp_server_socket.listen(128)

    while True:
        # 4. 等待客户端的链接 accept
        new_client_socket, client_addr = tcp_server_socket.accept()

        # 5. 调用发送文件函数,完成为客户端服务
        send_file_2_client(new_client_socket, client_addr)

        # 6. 关闭套接字
        new_client_socket.close()
    tcp_server_socket.close()


if __name__ == "__main__":
    main()
发布了50 篇原创文章 · 获赞 10 · 访问量 6620

猜你喜欢

转载自blog.csdn.net/qq_23996069/article/details/104040985
今日推荐