• 36、基于TCP、UDP协议的嵌套字通信


    一、套接字工作流程

    1.1、套接字流程

      服务器端先初始化socket:(创建套接字模块)

      和端口绑定bind:(将地址绑定到套接字)

      对端口进行监听listen:(监听链接)

      调用accept堵塞:(接收服务器链接)

      等待客户端连接connect:(客户端尝试连接服务器)

      客户端发送请求send:(客户端发出请求)

      服务器接收请求并处理请求recv:(服务器接收请求)

      将数据返回给客户端send:(服务器发出请求)

      客户端读取数据recv:(客户端接收请求)

      关闭连接close(关闭服务器)

    一、基于TCP协议的嵌套字通信

      TCP是基于链接的,所以需要先启动服务端,在启动客户端去连接服务端

    1.1、名词定义

      SOCK_STREAM:流式协议(tcp协议)

      AF_INET:网络通讯协议

      0.0.0.0:公网服务器地址

      127.0.0.1:服务器地址(自己的,通常用来调试)

    二、通讯循环

      由于tcp是基于链接通信的,所以一旦程序执行完毕就会直接断开,所以需要在程序内添加while循环,保证可以持续服务

    2.1、问题点  

      由于tcp是基于链接通信的,连接的双方,所以:

      1.一旦客户端单方向断开连接,服务器拿到的conn就是无效的,服务器在Windows上会直接报错,linux上会直接死循环

      2.客户端发送的信息为空,应用程序会将信息发给操作系统,操作系统不会将空往外发送,因此,服务器就不会收到消息,而客户端则在等待消息

      

    2.2、解决方案

      1.使用异常捕获,捕获后中断程序

      2.使用if判断,如果收到的消息为空,则跳出循环
    三、连接循环

      服务器的终极目标就是永不停机,所以需要将客户端连接服务器加入while

    3.1、问题

      端口占用:一个端口只能同时执行一个客户端,因此前一个未停止,下一个无法执行,在半连接池里的客户端可以输入内容排队等候

           accept限制了服务器连接客户端的数量,一旦超过将不会进入半连接池

    3.2、解决方法

    phone=socket(AF_INET,SOCK_STREAM)
    phone.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #就是它,在bind前加
    phone.bind(('127.0.0.1',8080))

     

    服务端

    # 服务端应该满足的特点:
    # 1、一直提供服务
    # 2、并发地提供服务
    import socket
    
    # 1、买手机
    phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 流式协议=》tcp协议
    
    # 2、绑定手机卡
    phone.bind(('127.0.0.1',8080)) # 0-65535, 1024以前的都被系统保留使用
    
    # 3、开机
    phone.listen(5) # 5指的是半连接池的大小
    print('服务端启动完成,监听地址为:%s:%s' %('127.0.0.1',8080))
    
    # 4、等待电话连接请求:拿到电话连接conn
    # 加上链接循环
    while True:
        conn,client_addr=phone.accept()
    
        # 5、通信:收发消息
        while True:
            try:
                data=conn.recv(1024) # 最大接收的数据量为1024Bytes,收到的是bytes类型
                if len(data) == 0:
                    # 在unix系统洗,一旦data收到的是空
                    # 意味着是一种异常的行为:客户度非法断开了链接
                    break
                print("客户端发来的消息:",data.decode('utf-8'))
                conn.send(data.upper())
            except Exception:
                # 针对windows系统
                break
    
        # 6、关闭电话连接conn(必选的回收资源的操作)
        conn.close()
    
    # 7、关机(可选操作)
    phone.close()

    客户端

    import socket
    
    #1、买手机
    phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 流式协议=》tcp协议
    
    #2、拨通服务端电话
    phone.connect(('127.0.0.1',8080))
    
    #3、通信
    while True:
        msg=input("输入要发送的消息>>>: ").strip() #msg=''
        if len(msg) == 0:continue
        phone.send(msg.encode('utf-8'))
        print('======?')
        data=phone.recv(1024)
        print(data.decode('utf-8'))
    
    #4、关闭连接(必选的回收资源的操作)
    phone.close()

    四、基于udp协议的套接字通信

      udp是无链接的,所以无论哪一端都不会报错

      服务器和客户端需要初始化socket,设定连接地址,接收数据,以及发出数据,最后断开连接

      

    服务器

    import socket
    
    server=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # 数据报协议=》udp协议
    
    server.bind(('127.0.0.1',8081))    # IP地址
    
    while True:
        data,client_addr=server.recvfrom(1024)   #接收信息
        server.sendto(data.upper(),client_addr)  #发出信息
    
    
    server.close()

    客户端

    import socket
    
    client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # 流式协议=》tcp协议
    
    while True:
        msg=input('>>>: ').strip()
        client.sendto(msg.encode('utf-8'),('127.0.0.1',8081))   #发出信息,设置地址
        res=client.recvfrom(1024)  #接收信息
        print(res)
    
    client.close()
  • 相关阅读:
    linux sort根据日期时间排序方法记录
    gitlab数据迁移与升级记录
    ubuntu加压7z分卷
    docker环境运行elasticsearch以及汉化运行kibana
    nginx 403错误 检查nginx.conf user有没有问题,最好是当前用户
    系统属性file.encoding在JVM启动后,再次设置无法对系统的默认编码造成影响 & sun.jnu.encoding
    IDEA快速选择提示代码的设置
    log4j2可以打印到控制台,但无法打印到文件
    IDEA快捷键
    Eclipse自定义快捷键
  • 原文地址:https://www.cnblogs.com/jingpeng/p/12741338.html
Copyright © 2020-2023  润新知