1 Python高级

一. 网络通信

1. 网络---UDP

网络通信

使用网络能够把多方链接在一起,然后可以进行数据通信。

所谓的网络编程就是,让在不同的电脑上的软件能够进行数据传输,即进程之间的通信。

ip地址

地址就是标记地点的。网络中ip地址来标记,用来标记网络上的一台电脑。

socket简介(套接字)

TCP/IP协议簇的网络层的IP地址可以唯一标识网络中的主机,传输层的协议+端口可以唯一标识主机中的应用进程。

socket是进程通信的一种方式,他与其他进程通信的主要不同是:他能实现不同主机间的进程通信,我们网络中各种各样的服务大多数都是属于socket来完成通信的。如浏览网页,QQ 微信等。

创建socket

python中使用socket模块的函数socket就可以完成。

函数socket.socket创建一个socket,该函数有两个参数:socket.socket(AddressFamily,Type)

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

创建TCP套接字:

import socket
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#这里是使用套接字的功能
s.close()
#不用的时候 关闭套接字

b前缀表示:后面字符串是bytes类型

如果一台计算机上运行的虚拟机和我们的主机IP不同,改成桥接方式。ping 一个IP地址 确定能否和这个IP地址通信

UDP套接字发数据:

如果发送数据之前没有绑定端口,操作系统会自己给你分配一个

import socket
def demo():
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    # 这里是使用套接字收发数据
    while True:
        send_data = input('请输入发送的数据: ')
        if send_data=='exit':#循环退出
            break
        #udp_socket.sendto(发送的内容,对方IP以及port)
        #发送的数据用utf-8编码
        s.sendto(send_data.encode('utf-8'),('192.168.33.53',8080))
    s.close()  # 不用的时候 关闭套接字

if __name__=='__main__':
    demo()

接收数据:

bind绑定端口

import socket
def demo():
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    #绑定本地信息
    localaddr = ('',7878)#''绑定本机的一个ip和port
    s.bind(localaddr)
    #接收对方的数据
    recv_data = s.recvfrom(1024)#1024表示本次接收的最大字节数
    #recv_data变量中存储的是一个元组
    recv_mes = recv_data[0]
    id = recv_data[1]
    print('%s %s' % (recv_mes.decode('gbk'),id))#window默认编码是gbk
    s.close()  #不用的时候 关闭套接字

if __name__=='__main__':
    demo()

同一个电脑上,同一个ip不同程序也可以发送信息传输数据。

lo 本地环回127.0.0.1 可以完成自己电脑上的数据共享。

套接字可以收数据也可以发数据,不需要创建两个。

import socket
def demo():
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    #绑定端口 用于接收数据
    s.bind('',7878)
    # 获取对方ip和port
    dest_ip = input("请输入对方ip: ")
    dest_port = int(input("输入对方port: "))

    send_data = input('请输入发送的数据: ')
    #udp_socket.sendto(发送的内容,对方IP以及port)
    #发送的数据用utf-8编码
    s.sendto(send_data.encode('utf-8'),(dest_ip,dest_port))

    #接收对方回复的数据
    recv_data = s.recvfrom(1024)
    print("%s %s" % (str(recv_data[1]),recv_data[0].decode('gbk')))

    s.close()  # 不用的时候 关闭套接字

if __name__=='__main__':
    demo()

udp聊天室

import socket
def send_mes(s):
    # 获取对方ip和port
    dest_ip = input("请输入对方ip: ")
    dest_port = int(input("输入对方port: "))

    send_data = input('请输入发送的数据: ')
    #udp_socket.sendto(发送的内容,对方IP以及port)
    #发送的数据用utf-8编码
    s.sendto(send_data.encode('utf-8'),(dest_ip,dest_port))
def recv_mes(s):
    #接收对方回复的数据
    recv_data = s.recvfrom(1024)
    print("%s %s" % (str(recv_data[1]),recv_data[0].decode('gbk')))
    
def demo():
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    #绑定端口 用于接收数据
    s.bind('',7878)
    while True:
        print("1 发送数据")
        print("2 接收数据")
        print("0 退出")
        id = input("请输入功能: ")
        if id == "1":
            #发送
            send_mes(s)
        elif id == "2":
            #接收并显示
            recv_mes(s)
        elif id == "0":
            break
        else:
            print("输入有误")

    s.close()  # 不用的时候 关闭套接字

if __name__=='__main__':
    demo()

当对方发送数据给你时,操作系统会将数据缓存起来,应用程序调用recvfrom时,有需要的数据就给你,没有时就堵塞。

TCP

 TCP协议,传输控制协议,是一种面向连接的,可靠的,基于字节流的传输层的通信协议。

TCP通信需要创建连接,数据传送,终止连接三个步骤。不适合用于广播的应用程序,广播的应用程序用UDP。

TCP客户端


import socket

def main():
    #创建套接字
    tcp_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    #连接服务器
    server_ip = input("输入连接的服务器ip: ")
    server_port = int(input("输入端口: "))
    tcp_socket.connect((server_ip,server_port))

    #发送数据
    send_data = input("发送的数据:")
    tcp_socket.send(send_data.encode("utf-8"))
    
    #关闭套接字
    tcp_socket.close()

if __name__ == "__main__":
    main()

TCP服务器

服务器需要绑定端口和ip,服务器先运行

import socket
def main():
    #创建套接字
    #这个套接字相当于监听
    tcp_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    #绑定本地信息 bind
    tcp_socket.bind(('',7892))
   
    #让默认套接字有主动改为被动(因为默认的是主动) listen
    tcp_socket.listen(128)
    
    #等待客户端的连接 accept(会返回一个新的套接字为客户端服务,还返回客户端的ip和端口
    new_client_socket,client_addr = tcp_socket.accept()#元组拆包
    
    #接收客户端发送的请求
    recv_data = new_client_socket.recv(1024)
    print(recv_data)#recv_data就是一个数据,并不是像UDP一样是元组,因为已经知道了客户端的ip(提前建立连接了)
    
    #回送数据给客户端
    new_client_socket.send("----ok----".encode('utf-8'))

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

循环为多个客户端服务

import socket
def main():
    #创建套接字
    #这个套接字相当于监听
    tcp_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    #绑定本地信息 bind
    tcp_socket.bind(('',7892))

    #让默认套接字有主动改为被动(因为默认的是主动) listen
    tcp_socket.listen(128)
    while True:#来个客户端就为其服务,服务结束关闭此套接字
        #如果到来的客户端太多,就会排队,等待一个一个接收服务
        #等待客户端的连接 accept(会返回一个新的套接字为客户端服务,还返回客户端的ip和端口
        new_client_socket,client_addr = tcp_socket.accept()#元组拆包
        while True:#循环多次 为同一个客户端服务多次
            #接收客户端发送的请求
            recv_data = new_client_socket.recv(1024)
            print(recv_data)#recv_data就是一个数据,并不是像UDP一样是元组,因为已经知道了客户端的ip(提前建立连接了)
    
            if recv_data:
            #如果recv解堵塞 那么有两种可能 1客户端发送过来数据 2客户端调用close recv解堵塞  
            #回送数据给客户端
                new_client_socket.send("----ok----".encode('utf-8'))
            else:
                break
            new_client_socket.close()#关闭accept返回的套接字 意味着不会为此客户端服务
    #关闭套接字
    tcp_socket.close()

if __name__ == "__main__":
    main()

案例:文件下载器

客户端:

import socket

def main():
    tcp_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    dest_ip = input("输入服务器ip:")
    dest_port = int(input("输入服务器端口: "))
    #连接服务器
    tcp_socket.connect((dest_ip,dest_port))
    download_file = input("输入下载的文件:")
    #把文件名字发送到服务器
    tcp_socket.send(download_file.encode('utf-8'))

    #接收文件中的数据
    recv_data = tcp_socket.recv(1024)#1024 1K 1024*1024 1M
    if recv_data:
        #保存收到的数据到一个文件中
        with open(download_file,'wb') as f:#用with最后不需要close,而且如果没有该文件,也会自己创建一个
            f.write(recv_data)
    tcp_socket.close()

if __name__ == "__main__":
    main()

服务器:

import socket

def send_file(new_client_socket, client_addr):
    # 接收客户端发送的请求
    file_name = new_client_socket.recv(1024).decode('utf-8')
    print('客户端%s需要下载的文件是: %s' % (str(client_addr),file_name))  # recv_data就是一个数据,并不是像UDP一样是元组,因为已经知道了客户端的ip(提前建立连接了)
    file_content = None
    try:
        f = open(file_name,'rb')
        file_content = f.read()
        f.close()
    except Exception as ret:
        print('没有要下载的文件 %s '% file_name)
    if file_content:
        new_client_socket.send(file_content)

def main():
    # 创建套接字
    # 这个套接字相当于监听
    tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 绑定本地信息 bind
    tcp_server_socket.bind(('', 7892))

    # 让默认套接字有主动改为被动(因为默认的是主动) listen
    tcp_server_socket.listen(128)

    while True:
        # 等待客户端的连接 accept(会返回一个新的套接字为客户端服务,还返回客户端的ip和端口
        new_client_socket, client_addr = tcp_server_socket.accept()  # 元组拆包
        # 调用发送文件函数 回送数据给客户端
        send_file(new_client_socket, client_addr)
        new_client_socket.close()
    # 关闭套接字
    tcp_server_socket.close()

if __name__ == "__main__":
    main()

TCP注意点:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值