• socket 代码实例


    1. TCP SOCKET

    客户端:

    #!/usr/bin/env python
    # -*-coding:utf-8 -*-
    import socket
    HOST = 'localhost'
    PORT = 50001
    
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client.connect((HOST, PORT))
    
    while True:
        msg = input('>>:').strip()
        if len(msg) == 0: continue  # 如果输入为空,跳过此次循环进行下一次。 TCP 协议不可以发空
        client.send(msg.encode()) # 发送输入的数据,必须为bytes格式
        data = client.recv(1024)
        print('recived:', data.decode())  # 收到服务器传过来的数据,要decode 一下
    

    服务端:

    #!/usr/bin/env python
    # -*-coding:utf-8 -*-
    import socket
    HOST = ''
    PORT = 50001
    
    gd_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    gd_server.bind((HOST, PORT))
    
    gd_server.listen(1)  # 开始监听,1代表在允许有一个连接排队,更多的新连接连进来时就会被拒绝
    conn, addr = gd_server.accept()  # 阻塞直到有连接为止,有了一个新连接进来后,就会为这个请求生成一个连接对象
    print(conn, addr)
    
    with conn:
        print('Connected by', addr)
        while True:
            data = conn.recv(1024)  # 接收1024个字节
            print("server recv:", conn.getpeername(), data.decode())
            if not data: break  # 收不到数据,就break
            conn.sendall(data)  # 把收到的数据再全部返回给客户端
    

    先启动服务端,再启动客户端

    # 客户端:
    >>:hello
    recived: hello
    >>:茉莉
    recived: 茉莉
    >>:
    
    # 服务端
    <socket.socket fd=268, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 50001), raddr=('127.0.0.1', 51711)> ('127.0.0.1', 51711)
    Connected by ('127.0.0.1', 51711)
    server recv: ('127.0.0.1', 51711) hello
    server recv: ('127.0.0.1', 51711) 茉莉
    


    简单版聊天软件

    客户端代码同上

    服务端代码:

    #!/usr/bin/env python
    # -*-coding:utf-8 -*-
    import socket
    HOST = ''
    PORT = 50002
    
    gd_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    gd_server.bind((HOST, PORT))
    
    gd_server.listen(1)  # 开始监听,1代表在允许有一个连接排队,更多的新连接连进来时就会被拒绝
    conn, addr = gd_server.accept()  # 阻塞直到有连接为止,有了一个新连接进来后,就会为这个请求生成一个连接对象
    print(conn, addr)
    
    with conn:
        print('Connected by', addr)
        while True:
            data = conn.recv(1024)  # 接收1024个字节
            print("recv from client:", conn.getpeername(), data.decode())
            if not data: break  # 收不到数据,就break
    
            response = input(">>>").strip()
            conn.send(response.encode())
            print("send to client:",response)
    

    运行结果

    如果想要服务端一直在运行中的状体,即服务端不会因为客户端断而链接断开,可以在最外层再加一个 while True 循环即可:


    s.send()
    # 发送TCP数据,将string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小。 所以,send() 执行一次,可能不会把所有数据都发送完毕。
    
    s.sendall()
    
    # 完整发送TCP数据,完整发送TCP数据。将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常。 
    

    如果遇到这个问题:

    解决方法:

    sock_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock_server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #一行代码搞定,写在bind之前
    sock_server.bind((HOST, PORT))
    


    2. UDP SOCKET

    udp 不需要经过3次握手和4次挥手,不需要提前建立连接,直接发数据就行。

    客户端:

    #!/usr/bin/env python
    # -*-coding:utf-8 -*-
    import socket
    ip_port = ('127.0.0.1',9000)
    BUFSIZE = 1024
    udp_server_client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # socket.SOCK_DGRAM
    
    while True:
        msg=input('>>: ').strip()
        if not msg:continue
        udp_server_client.sendto(msg.encode('utf-8'),ip_port)  # sendto
    
        back_msg,addr = udp_server_client.recvfrom(BUFSIZE)
        print(back_msg.decode('utf-8'),addr)
    

    服务端:

    import socket
    ip_port=('127.0.0.1', 9000)
    BUFSIZE=1024
    
    udp_server_client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)  # udp类型
    udp_server_client.bind(ip_port)
    
    while True:
        msg,addr=udp_server_client.recvfrom(BUFSIZE)  # recvfrom
        print("recv ",msg,addr)
    
        udp_server_client.sendto(msg.upper(), addr)
    


    3. UDP and TCP

    tcp基于链接通信

    • 基于链接,则需要listen(backlog),指定连接池的大小
    • 基于链接,必须先运行的服务端,然后客户端发起链接请求
    • 对于mac系统:如果一端断开了链接,那另外一端的链接也跟着完蛋recv将不会阻塞,收到的是空(解决方法是:服务端在收消息后加上if判断,空消息就break掉通信循环)
    • 对于windows/linux系统:如果一端断开了链接,那另外一端的链接也跟着完蛋recv将不会阻塞,收到的是空(解决方法是:服务端通信循环内加异常处理,捕捉到异常后就break掉通讯循环)

    udp无链接

    • 无链接,因而无需listen(backlog),更加没有什么连接池之说了
    • 无链接,udp的sendinto不用管是否有一个正在运行的服务端,可以己端一个劲的发消息,只不过数据丢失
    • recvfrom收的数据小于sendinto发送的数据时,在mac和linux系统上数据直接丢失,在windows系统上发送的比接收的大直接报错
    • 只有sendinto发送数据没有recvfrom收数据,数据丢失
  • 相关阅读:
    用户与组
    初识linux
    权限管理
    认识vim 编辑器
    文件归档
    路由相关术语
    Access、Hybrid和Trunk
    #error作用
    交换芯片收发包的 DMA 实现原理
    linux网络学习
  • 原文地址:https://www.cnblogs.com/friday69/p/9473350.html
Copyright © 2020-2023  润新知