• socket基本用法


    socket介绍

    1、什么是socket

      socket是应用层与传输层中间的一个软件抽象层,它是一组接口。它把TCP/IP这些复杂的协议统一封装起来

      这样我们只要知道如何使用socket就好,就已经符合了传输层往下的一大串协议

    2、为什么要使用socket

      如果没有socket而我们写的代码又要让别人能正确解析,就需要一层层往下研究协议,写出符合协议的代码

      而我们大家传输层往下的代码基本一样,所以把这些代码封装成一个模块,方便大家使用,不用去考虑传输层

      以下的东西

    3、socket发展

      套接字起源于20世纪70年代,一开始,套接字被设计用在同一台主机上多个应用程序的通讯,这也被称为

      进程间通讯或者IPC。后来网络发展,又被应用于网络协议上。

      套接字有两种(或者称为有两个种族):

        基于文件类型的套接字家族:名字  --> AF_UNIX

        基于网络类型的套接字家族:名字  --> AF_INET被用于ipv4       AF_INET6被用于ipv6

    socket用法

    # 需要明确的是:

      关于网络协议和socket相关概念,对于所有编程语言都是一致的,区别仅仅是个编程语言的函数名称不同

    1、服务器端

    import socket
    # 获得socket对象 AF_INET表示基于网络的套接字
    sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    # SOCK_STREAM表示的是TCP协议  SOCK_DGRAM表示的是UDP协议
    # 将socket对象绑定ip地址和端口号
    sk.bind(('127.0.0.1',8080))     # 参数需要传入一个元组
    # 相当于电话的开机 括号里的参数表示可以同时接收5个请求
    sk.listen(5)
    
    # 一般服务器都不需要关闭,所以加个while循环
    while True:
    # 进入监听状态,等待别人链接过来,有两个返回值,一个是对方的socket对象,一个是对方的ip以及端口
        client,addr = sk.accept()
        # 收发消息一般都需要多次循环发送,也加个while循环
        while True:
            try: # 如果对面强行关闭,为了程序不崩,就需要异常处理
                msg = client.recv(1024)    # recv表示接收,括号里是最大接收字节
                if not msg: # 如果接收到的消息是空字符串,就表示对面正常退出,需要打断循环
                    break
                # send表示发送数据,发送的数据必须是二进制数据
                client.send('二进制数据'.encode('utf-8'))
            except Exception as e:
                print(e)
                break
        client.close()  # 关闭对面传过来的对象
    sk.close()  # 关闭服务器的socket对象

    2、客户端

    import socket
    # 获取socket对象,括号里默认是AF_INET  和 SOCK_STREAM  所以可以不写
    sk = socket.socket()
    # 链接到服务器端 括号里也是一个元组,包含ip地址以及对方的端口号
    sk.connect(('127.0.0.1',8080))      # 自己的端口号系统会随机分配,不需要设置
    
    while True: # 收发信息也需要循环
        try: # 为了防止服务器非正常下线而导致客户端直接崩溃,需要加入异常处理
            cmd = input('>>(q:退出)')
            if cmd == 'q':  # 给客户端一个可以正常退出的方法
                break
            if not cmd: # 如果直接敲回车,那么cmd就是空字符串,TCP协议对此进行优化
                continue    # 正常收发消息过程中,你传入空字符串,它不会帮你发送
            sk.send(cmd.encode('utf-8'))
    # 如果上面没有做空判断,输入空会直接跳过send这步,这样客户端和服务器端都处于接收状态,卡住不动
            sk.recv(1024) 
        except Exception as e:
            print(e)
            break
    sk.close() # 关闭socket对象

    3、基于TCP的socket通讯流程图

    socket常见问题

    1、端口占用

    报错信息

    Traceback (most recent call last):
    File "F:/pyprogram/day31/homework/topic2/test.py", line 6, in <module>
    sk.bind(('127.0.0.1',8080))
    OSError: [WinError 10048] 通常每个套接字地址(协议/网络地址/端口)只允许使用一次。

    问题发生的原因

      1.可能是由于你已经启动了服务器程序,却又再次启动了服务器程序,同一个端口不能被多个进程使用导致

      2.三次握手或四次挥手时,发生了异常导致对方程序已经结束而服务器任然处于time_wait状态导致

      3.在高并发的场景下,由于连接的客户端太多,也会产生大量处于time_wait状态连接

    解决的方案

      第一种重新选择端口后就可以,或者把之前的占用端口的进程关闭掉

      第二三种以后再说

    2、强行关闭链接

    报错信息

    Traceback (most recent call last):
    File "F:/pyprogram/day31/part2/客户端.py", line 12, in <module>
    client.send(msg.encode('utf-8'))
    ConnectionResetError: [WinError 10054] 远程主机强迫关闭了一个现有的连接。

    问题发生的原因

      当客户端与服务器链接成功后,如果一方没有执行close,而是直接强行终止程序(或是遇到异常被迫终止)

      都会导致另一方发生问题

      在windows下,接收数据的一方在recv函数处将抛出异常

    解决的方案

      用try...except语法抓取异常,抓到对方强退异常后并处理

    3、客户端正常结束,服务器端无限循环空字符

    报错信息

      不会产生报错信息,但是服务器端会一直循环空字符串

    问题发生的原因

      客户端正常close()之后,会给服务器发送一个空字符串,

      如果服务器端没有发送数据的话,就会一直循环接收这个空字符串,占用CPU资源

    解决的方案

      在服务器端接收的地方加上空字符串判断,如果是空字符串,就表示对方客户端退出了

      那么判断空成功,让自己也退出循环

  • 相关阅读:
    [LeetCode] Search in Rotated Sorted Array II
    [LeetCode] Search in Rotated Sorted Array
    [LeetCode] Rotate List
    [LeetCode] Rotate Array
    [LeetCode] Product of Array Except Self
    [LeetCode] Recover Binary Search Tree
    [LeetCode] Jump Game II
    [LeetCode] Jump Game
    [LeetCode] Delete Node in a Linked List
    [LeetCode] Climbing Stairs
  • 原文地址:https://www.cnblogs.com/hesujian/p/10938420.html
Copyright © 2020-2023  润新知