您的位置:首页 > 理论基础 > 计算机网络

Python全栈(四)高级编程技巧之6.Socket编程-TCP客户端和服务端

2020-03-12 18:43 756 查看

文章目录

  • 二、TCP客户端构建
  • 三、TCP服务端构建流程
  • 四、TCP服务端为多个客户端服务
  • 五、应用--文件下载器
  • 一、TCP介绍

    1.概念

    TCP协议,即传输控制协议,是一种面向连接的、可靠的、基于字节流的传输层通信协议。
    TCP通信需要经过创建连接数据传送终止连接三个步骤。
    TCP通信模型中,在通信开始之前,一定要先建立相关连接,才能发送数据。

    2.TCP特点:

    • 面向连接:
      通信双方必须先建立连接才能进行数据的传输。
    • 可靠传输: TCP采用发送应答机制
    • 超时重传:
      启动定时器,在规定时间内未收到,则重新发送,直到收到。
    • 错误校验
    • 流量控制和阻塞管理

    3.TCP和UDP的比较

    • TCP面向连接;UDP是无连接的,即发送数据之前不需要建立连接.
    • TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付.
    • UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性有较高的通信或广播通信。
    • 每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信。
    • TCP对系统资源要求较多,UDP对系统资源要求较少。
    • TCP严格区分客户端和服务端,UDP不一定区分。

    UDP通信和TCP通信的过程如下:
    UDP通信

    TCP通信

    形象地说:
    UCP类比于写信,别人不一定能收到;
    TCP类比于打电话,可以获知对方是否收到。

    二、TCP客户端构建

    客户端:是需要被服务的一方;
    服务器端:就是提供服务的一方。
    TCP客户端构建流程

    • 创建socket
    • 连接服务器
    • 收发数据(最大接收2014个字节)
    • 关闭套接字

    NetAssist进行配置如下

    此时,NetAssist作为服务端,Python运行作为客户端。

    import socket
    
    def main():
    #创建TCP套接字
    tcp_client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    #连接服务器
    server_ip = input('Server IP:')
    server_port = int(input('Server Port:'))
    tcp_client.connect((server_ip,server_port))
    #接收数据
    recv_data = tcp_client.recv(1024)
    print(recv_data)
    #关闭套接字
    tcp_client.close()
    
    if __name__ == '__main__':
    main()

    显示

    数据进行解码:

    import socket
    
    def main():
    #创建TCP套接字
    tcp_client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    #连接服务器
    server_ip = input('Server IP:')
    server_port = int(input('Server Port:'))
    tcp_client.connect((server_ip,server_port))
    #接收数据
    recv_data = tcp_client.recv(1024).decode('gbk')
    print(recv_data)
    #关闭套接字
    tcp_client.close()
    
    if __name__ == '__main__':
    main()

    显示

    增加发送数据:

    import socket
    
    def main():
    #创建TCP套接字
    tcp_client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    #连接服务器
    server_ip = input('Server IP:')
    server_port = int(input('Server Port:'))
    tcp_client.connect((server_ip,server_port))
    #发送数据
    send_data = input('Data to send:')
    tcp_client.send(send_data.encode('gbk'))
    #接收数据
    recv_data = tcp_client.recv(1024).decode('gbk')
    print(recv_data)
    #关闭套接字
    tcp_client.close()
    
    if __name__ == '__main__':
    main()

    显示

    三、TCP服务端构建流程

    TCP服务端构建过程:

    • socket创建套接字
    • bind绑定IP和port
    • listen使套接字变为可以被动连接
    • accept等待客户端的连接
    • recv/send接收发送数据
    • 关闭套接字

    NetAssist进行配置如下

    此时,NetAssist作为客户端,Python运行作为服务器端;
    在代码未运行时,NetAssist点击连接按钮连接不了,因为此时服务器端还未开启,应该先运行服务器端、再连接。

    import socket
    
    def main():
    #创建TCP监听套接字
    tcp_server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    #绑定信息
    tcp_server.bind(('',7890))
    #默认套接字主动变被动
    tcp_server.listen(128)
    #等待,创建服务套接字
    new_client_socket,client_addr = tcp_server.accept()
    print(client_addr)
    
    if __name__ == '__main__':
    main()

    显示

    TCP监听套接字负责等待新的客户端连接;
    产生的服务套接字负责收发数据。
    进一步完善代码:

    import socket
    
    def main():
    #创建TCP监听套接字
    tcp_server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    #绑定信息
    tcp_server.bind(('',7890))
    #默认套接字主动变被动
    tcp_server.listen(128)
    #等待,创建服务套接字
    new_client_socket,client_addr = tcp_server.accept()
    print(client_addr)
    #接收数据
    recv_data = new_client_socket.recv(1024)
    print(recv_data.decode('gbk'))
    #发送数据
    send_data = input('Data to send:').encode('gbk')
    new_client_socket.send(send_data)
    new_client_socket.close()
    tcp_server.close()
    
    if __name__ == '__main__':
    main()

    显示

    四、TCP服务端为多个客户端服务

    1.代码分析

    服务器端代码

    tcp_server.accept()
    部分会阻塞,阻塞直到有客户端连接;
    new_client_socket.recv()
    部分会阻塞,直到客户端有数据发送或者客户端断开连接解堵塞。

    2.多客户端实现

    import socket
    
    def main():
    # 创建TCP监听套接字
    tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 绑定信息
    tcp_server.bind(('', 7890))
    #为多个客户端服务
    while True:
    # 默认套接字主动变被动
    tcp_server.listen(128)
    # 等待,创建服务套接字
    new_client_socket, client_addr = tcp_server.accept()
    print(client_addr)
    # 接收数据
    recv_data = new_client_socket.recv(1024)
    print(recv_data.decode('gbk'))
    # 发送数据
    send_str = 'Hello, ' +client_addr[0]
    send_data = send_str.encode('gbk')
    new_client_socket.send(send_data)
    new_client_socket.close()
    tcp_server.close()
    
    if __name__ == '__main__':
    main()

    显示

    显然,此时可以连接多个客户端,但是每个客户端只能发送一次数据,再发送会产生异常,自动断开连接,要想多次服务,还需要进一步改进:

    import socket
    
    def main():
    # 创建TCP监听套接字
    tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 绑定信息
    tcp_server.bind(('', 7890))
    #为多个客户端服务
    while True:
    # 默认套接字主动变被动
    tcp_server.listen(128)
    # 等待,创建服务套接字
    new_client_socket, client_addr = tcp_server.accept()
    print(client_addr)
    #为客户端提供多次服务
    while True:
    # 接收数据
    recv_data = new_client_socket.recv(1024)
    # 发送数据
    if recv_data.decode('gbk'):
    print(recv_data.decode('gbk'))
    send_str = 'Hello, ' +client_addr[0]
    send_data = send_str.encode('gbk')
    new_client_socket.send(send_data)
    #无数据,退出循环,关闭连接
    else:
    break
    new_client_socket.close()
    tcp_server.close()
    
    if __name__ == '__main__':
    main()

    显示

    易知,可以实现为多个客户端提供服务,但是一次只能为一个客户端提供服务,不能同时为多个客户端服务。

    五、应用–文件下载器

    TCP客户端实现思路

    • 创建套接字
    • 连接服务器
    • 获取下载文件名称
    • 发送下载文件下载请求
    • 接收服务端发送过来的数据
    • 保存文件
    • 关闭套接字

    tcp_client.py

    import socket
    
    def main():
    #创建套接字
    tcp_client_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    # 连接服务器
    server_ip = input('Server IP:')
    server_port = int(input('Server Port:'))
    tcp_client_socket.connect((server_ip,server_port))
    #获取下载文件名称
    file_name = input('Input File Name:')
    #发送文件下载请求
    tcp_client_socket.send(file_name.encode('gbk'))
    #接收文件
    recv_data = tcp_client_socket.recv(1024*1024)
    #保存文件
    with open('Received ' + file_name,'wb') as f:
    f.write(recv_data)
    #关闭套接字
    tcp_client_socket.close()
    
    if __name__ == '__main__':
    main()

    用NetAssist作服务器端,进行测试,结果

    TCP服务器端实现思路

    • 创建套接字
    • 绑定信息
    • 主动变被动
    • 等待客户端连接
    • 收发数据
    • 关闭套接字

    tcp_server.py

    import socket
    
    def send_file_to_client(new_client_socket):
    file_name = new_client_socket.recv(1024).decode('gbk')
    try:
    with open(file_name,'rb') as f:
    content = f.read()
    new_client_socket.send(content)
    except:
    print('No such File:%s' % file_name)
    return
    
    def main():
    # 创建TCP监听套接字
    tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 绑定信息
    tcp_server.bind(('', 7890))
    # 默认套接字主动变被动
    tcp_server.listen(128)
    # 等待,创建服务套接字
    new_client_socket, client_addr = tcp_server.accept()
    print(client_addr)
    # 给客户端返回文件内容
    send_file_to_client(new_client_socket)
    #关闭客户端
    new_client_socket.close()
    tcp_server.close()
    
    if __name__ == '__main__':
    main()

    服务器端和客户端运行起来,可得结果:

    显示生成新文件的动态过程:

    易知,运行并连接后,在客户端输入文件名,服务器端读写本地文件并发给客户端进行保存生成Received test.py文件。

    • 点赞 11
    • 收藏
    • 分享
    • 文章举报
    cutercorley 发布了86 篇原创文章 · 获赞 571 · 访问量 16万+ 私信 关注
    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: