Python高级 -- 02 网络(udp、tcp)

一、socket


1、socket简介


        socket(简称 套接字) 是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于 Socket 来完成通信的


2、创建socket


在python中,使用socket模块的函数可以完成:

import socket

"""
	函数:socket.socket(AddressFamily, Type)
	创建一个socket,该函数有两个参数:
		AddressFamily:可以选择AF_INET(用于Internet进程间通信)或者AF_UNIX(用于同一台机器进程间通信),实际工作中常用AF_INET
		Type:套接字类型,可以是SOCKET_STREAM(流式套接字,主要用于TCP协议)或者SOCK_DGRAM(数据报套接字,主要用于UDP协议)
"""

3、udp发送数据


(1)、ubuntu桌面编写python代码




(2)、使用命令运行代码




(3)、在虚拟机xp系统中查看是否接收到数据




注意:xp中用到的接收软件在本博客资料中


http://download.csdn.net/download/wingzhezhe/10226876


4、练习:发送带有退出功能的可多次发送的udp数据




5、接收udp数据


(1)、ubuntu中使用udp接收数据的代码



import socket
 
 
 def main():
     # 1.创建套接字
     udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
 
     # 2.给当前套接字对象绑定一个ip和端口号
     #   使用的函数是 :bind((ip, port))   bind的参数是一个元组
     #       ip :当前本机的ip,一般不用写,用""代替,代表本机ip
     #       port : 给当前套接字对象指定端口号
     local_info = ("", 8888)
     udp_socket.bind(local_info)
 
     # 3.接收数据 : 使用函数recvfrom(args)   参数args表示本次接收的最大字节数
     """
         接收的数据是一个元组类型的 : (字节类型的接收到的内容, (发送方的ip, 发送方的port))
             需要使用 decode(args) 方法将接收的字节类型的数据进行转码
     """
     recv_data = udp_socket.recvfrom(1024)
     print(type(recv_data))
 
     # 对接收的数据进行处理
     recv_content = recv_data[0].decode("gbk")   # window中默认编码时gbk,因此转码也要使用gbk
     recv_info = recv_data[1]
 
     # 4.打印数据
     print("接收到的数据内容是:%s \n 发送方的信息是:%s" % (recv_content, recv_info))
 
     # 关闭套接字
     udp_socket.close()
 
 
 if __name__ == "__main__":
     main()


(2)、运行程序,演示操作




6、使用同一个套接字首发upd数据


(1)、在ubuntu系统中安装网路调试助手


(2)、编写代码



def main():
     # 1.创建一个套接字对象
     udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
 
     # 2.获取对方的ip/port
     dest_ip = input("请输入对方的ip:")
     dest_port = int(input("请输入对方的port:"))
 
     # 3.从键盘获取数据
     content = input("请输入要发送的内容:")
 
     # 4.使用套接字发送数据
     udp_socket.sendto(content.encode("utf-8"), (dest_ip, dest_port))
 
     # 接收对方发送的套接字数据
     recv = udp_socket.recvfrom(1024)
     print(recv)
     
     # 5.关闭套接字
     udp_socket.close()
 
 
 if __name__ == "__main__":
     main()

(3)、测试运行




7、使用udp实现简易聊天室




import socket

def send_msg(udp_socket):
    """发送数据"""
    dest_ip = input("请输入目的地ip:")
    dest_port = int(input("请输入目的地port:"))
    dest_content = input("请输入要发送的内容:")
    # 发送数据
    udp_socket.sendto(dest_content.encode("utf-8"), (dest_ip, dest_port))


def recv_msg(udp_socket):
    """接收数据"""
    recv_data = udp_socket.recvfrom(1024)
    print("端口号和ip为:%s 发送的数据是:%s  " % (recv_data[1], recv_data[0].decode("utf-8")))



def main():
    # 1.创建套接字对象
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    
    # 2.给套接字绑定ip和端口号
    udp_socket.bind(("",8888))
    
    # 3.使用循环来实现收发功能
    while True:
        print("---------------XXX聊天室---------------")
        opt = input("请输入您要进行的操作:1(发送消息)  2(接收消息)   3(退出系统)")
        if opt == "1":
            send_msg(udp_socket)
        elif opt == "2":
            recv_msg(udp_socket)
        elif opt == "3":
            break
        else:
            print("输入有误")
    
    # 4.关闭套接字
    udp_socket.close()


if __name__ == "__main__":
    main()

测试运行:




二、tcp


1、tcp协议介绍


TCP协议,传输控制协议(英语:Transmission Control Protocol,缩写为 TCP)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793定义。

TCP通信需要经过创建连接、数据传送、终止连接三个步骤。、

TCP通信模型中,在通信开始之前,一定要先建立相关的链接,才能发送数据


2、Tcp的特点


(1)、面向连接


通信双方必须先建立连接才能进行数据的传输,双方都必须为该连接分配必要的系统内核资源,以管理连接的状态和连接上的传输。

双方间的数据传输都可以通过这一个连接进行。

完成数据交换后,双方必须断开此连接,以释放系统资源。

这种连接是一对一的,因此TCP不适用于广播的应用程序,基于广播的应用程序请使用UDP协议。


(2)、可靠传输


1)TCP采用发送应答机制


TCP发送的每个报文段都必须得到接收方的应答才认为这个TCP报文段传输成功


2)超时重传


发送端发出一个报文段之后就启动定时器,如果在定时时间内没有收到应答就重新发送这个报文段。

TCP为了保证不发生丢包,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的包发回一个相应的确认(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据包就被假设为已丢失将会被进行重传。


(3)、错误校验


TCP用一个校验和函数来检验数据是否有错误;在发送和接收时都要计算校验和。


4) 流量控制和阻塞管理


流量控制用来避免主机发送得过快而使接收方来不及完全收下。


TCP与UDP的不同点


        面向连接(确认有创建三方交握,连接已创建才作传输。)

        有序数据传输

        重发丢失的数据包

       舍弃重复的数据包

       无差错的数据传输

       阻塞/流量控制


3、tcp通信模型




4、使用tcp客户端发送数据



import socket


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

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

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

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


if __name__ == "__main__":
    main()



5、tcp服务器


(1)、创建服务器流程


        socket创建一个套接字

        bind绑定ip和port

        listen使套接字变为可以被动链接

        accept等待客户端的链接

        recv/send接收发送数据


(2)、创建tcp服务器demo



def main():
    # 1.创建tcp套接字
    tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	
    # 2.绑定本地信息
    tcp_server_socket.bind(("", 8888))
	
    # 3.让默认的套接字由主动变为被动
    tcp_server_socket.listen(128)
    print("----------程序启动,等待客户端链接------------")
	
    """
        4.等待客户端的链接,返回值是一个元组(client_socket, client_addr)
            步骤1创建的套接字对象只负责等待客户端进行链接,如果有链接,服务端就创建一个套接字,用来为客户端服务
            client_socket : 服务器创建的套接字对象,用来为客户端服务
            client_addr : 存放的是客户端的信息,是一个元组(client_ip, client_port)
    """
    client_socket, client_addr = tcp_server_socket.accept()
    print("-----------接收到客户端链接-----------")
    print(client_addr)
	
    # 5.接收客户端发送过来的数据,返回值就是一个字节数据
    recv_data = client_socket.recv(1024)
    print(recv_data)
	
    # 6.服务器接收到数据后,给客户端返回数据
    client_socket.send("数据已经收到".encode("utf-8"))
	
    # 7.关闭套接字
    client_socket.close()
    tcp_server_socket.close()
	
	
if __name__ == "__main__":
    main()



(3)、实现tcp服务端循环为多个客户端服务






(4)、实现tcp服务器循环为多个客户服务,并且多次为一个客户提供服务






6、模拟下载文件


(1)、tcp服务端代码

import socket
 
 
def send_file_2_client(client_socket, client_addr):

    # 1.接收客户端发过来的信息(要下载的文件名)
    file_name = client_socket.recv(1024).decode("utf-8")
    print("客户端要下载的文件名为:%s" % file_name)

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

    # 3.发送数据给客户端
    if file_content:
        client_socket.send(file_content)


def main():
    # 1.创建服务端的套接字对象
    tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # 2.绑定服务端信息
    tcp_server_socket.bind(("", 8888))

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

    # 让下载程序为多个客户端服务
    while True:
        # 4.等待客户端的链接
        client_socket, client_addr = tcp_server_socket.accept()

        # 5.调用方法,读取文件内容,并发送给客户端
        send_file_2_client(client_socket, client_addr)


        # 关闭套接字
        client_socket.close()

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


if __name__ == "__main__":
    main()    main()

(2)、tcp客户端代码

import socket
 
 
 def main():
     # 1.创建tcp套接字对象
     tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 
     # 2.获取服务器的ip和port
     server_ip = input("请输入服务器的ip:")
     server_port = int(input("请输入服务器的port:"))
 
     # 3.链接服务器
     tcp_socket.connect((server_ip, server_port))
 
     # 4.获取要下载的文件的名字
     download_file_name = input("请输入要下载的文件名:")
 
     # 5.将文件名发送到服务器
     tcp_socket.send(download_file_name.encode("utf-8"))
 
     # 6.接收从服务器中发送多来的文件中的数据,参数是最大接收的字节数,1024代表1K
     recv_data = tcp_socket.recv(1024)
 
     """
         7.保存数据到一个文件中
         
         with open(fileName, option) as f:
 
         以上代码的作用 :在文件能打开的前提下,替代了使用try...except的时候,
         如果抛出异常,需要手动关闭文件流的操作,
         即,使用以上写法,如果在操作过程中,出现异常,系统自动会关闭文件流
         如果没有出现异常,也会在操作结束的时候自动关闭文件流
     """
     if recv_data:
         # 如果文件内容不是空,才进行下载
         with open("[下载]" + download_file_name, "wb") as f:
             f.write(recv_data)
 
     # 8.关闭套接字
     tcp_socket.close()
 
 
 if __name__ == "__main__":
 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章