zoukankan      html  css  js  c++  java
  • python socket编程

    一、socket基础知识

    在网络编程中的一个基本组件就是套接字(socket).
    1.有阻塞(同步网络编程)
    2.有非阻塞(异步网络编程)
    套接字基本上是两个端点的程序之间的"信息通道".程序可能分布在不同计算机上,通过套接字相互发送信息.

    套接字包括两个:
    1.服务套接字
    创建一个服务套接字后:
    1.让它等待连接,这样它就在某个网络地址处(ip地址和端口号的组合)监听,直到有客户端套接字连接.
    连接完成后,两者就可以进行交互了.
    2.使用bind(host,port)方法后,再调用listen(只有一个参数,服务器未处理连接的长度(即允许排队等待的连接数目,
    在这些连接禁用之前))去监听某个特定位置的地址.
    3.服务端开始监听后,便可以接受客户端连接.这个步骤使用accept方法来完成.这个方法会阻塞(等待)
    直到客户连接,然后该方法返回一个格式为(client,address)的元组,
    4.服务器处理完一个与客户端连接后,再次调用accept方法开始等待下一个连接.这个过程通常是个无限循环
    2.客户机套接字
    1.客户机简单的连接,完成事务,断开连接.
    2.客户端使用connect(host,port)方法连接到服务器,
    3.client是客户端套接字,address是一个前面解释过的地址.

    一个套接字就是socket模块中socket类的一个实例.
    这个实例需要三个参数
    1.地址族(默认是socket.AF_INET)
    2.流(socket.SOCK_STREAM,默认值)或数据报(socket.SOCK_DGRAM)套接字
    3.使用协议(默认是0,使用默认值即可)

    套接字有两个方法
    1.send发送
    2.revc接收
    用于接收,用于传输数据,revc参数用来选择最大字节数来接收1024是个好选择。

    二、Socket 类型

    socket参数的详解

    socket.socket(family=AF_INET,type=SOCK_STREAM,proto=0,fileno=None)
     创建socket对象的参数说明:
     

    套接字格式:

    socket(family,type[,protocal]) 使用给定的地址族、套接字类型、协议编号(默认为0)来创建套接字。

    三、Socket 函数

    注意点:

    1)TCP发送数据时,已建立好TCP连接,所以不需要指定地址。UDP是面向无连接的,每次发送要指定是发给谁。

    2)服务端与客户端不能直接发送列表,元组,字典。需要字符串化repr(data)。

     

    四、socket编程思路

    1.基于TCP协议的socket

    注 :启动时应该先启动 server端 ,再启动 client端。

    TCP服务端:

    1 创建套接字,绑定套接字到本地IP与端口

       # socket.socket(socket.AF_INET,socket.SOCK_STREAM) , s.bind()

    2 开始监听连接                   #s.listen()

    3 进入循环,不断接受客户端的连接请求              #s.accept()

    4 然后接收传来的数据,并发送给对方数据         #s.recv() , s.sendall()

    5 传输完毕后,关闭套接字                     #s.close()

    import socket
    sk = socket.socket()  # 创建了一个socket对象
    sk.bind(('127.0.0.1',8080))  # 绑定一台机器的(ip,端口)
    # 回环地址 - 指向自己这台机器
    sk.listen()    # 建立监听等待别人连接
    conn,addr = sk.accept()       # 阻塞:在这里等待直到接到一个连接
    # conn是连接
    # addr是对方的地址
    print(conn)
    print(addr)
    conn.send(b'hello')              # 和对方打招呼
    msg = conn.recv(1024)                 #接收数据,并把接收的数据实例化
    # 有发必有收 收发必相等
    print(msg)
    conn.close()                      # 挂电话
    sk.close()                        # 关机

    TCP客户端:

    1 创建套接字,连接远端地址

           # socket.socket(socket.AF_INET,socket.SOCK_STREAM) , s.connect()

    2 连接后发送数据和接收数据          # s.sendall(), s.recv()

    3 传输完毕后,关闭套接字          #s.close()

    import socket
    sk = socket.socket()  # 买个手机
    sk.connect(('127.0.0.1',8080))  # 拨号
    ret = sk.recv(1024)
    print(ret)
    sk.send(b'byebye!')
    sk.close()

    问题:在启动服务端时可能会遇到 端口报错 这时是因为此端口可能已被占用,无法重复使用,那该怎么解决呢?

    #加入一条socket配置,重用ip和端口
    import socket
    from socket import SOL_SOCKET,SO_REUSEADDR
    sk = socket.socket()
    sk.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #就是它,在bind前加
    sk.bind(('127.0.0.1',8898))  #把地址绑定到套接字
    sk.listen()          #监听链接
    conn,addr = sk.accept() #接受客户端链接
    ret = conn.recv(1024)   #接收客户端信息
    print(ret)              #打印客户端信息
    conn.send(b'hi')        #向客户端发送信息
    conn.close()       #关闭客户端套接字
    sk.close()        #关闭服务器套接字(可选)
    解决方法

    2.基于UDP协议的socket

    使用UDP协议时,不需要建立连接,只需要知道对方的IP地址和端口号,就可以直接发数据包。但是,能不能到达就不知道了。

    虽然用UDP传输数据不可靠,但它的优点是和TCP比,速度快,对于不要求可靠到达的数据,就可以使用UDP协议。

    server端:

    import socket
    sk = socket.socket(type=socket.SOCK_DGRAM)  # 建立一个socket对象,
    # 指定以UDP协议的形式来连接
    sk.bind(('127.0.0.1',8080))
    # 指定服务的地址
     
    msg,addr = sk.recvfrom(1024) # 接收消息,发送端的地址
    print(msg,addr)
    sk.sendto(b'HELLO',addr)   # 给发送端回复消息
     
    sk.close()  # 关闭socket连接

    client端:

    import socket
     
    sk = socket.socket(type=socket.SOCK_DGRAM)
     
    sk.sendto(b'hello',('127.0.0.1',8080))   # 直接给服务器发送一段消息
     
    msg,addr = sk.recvfrom(1024)   # 接收对面的回信
     
    print(msg)
     
    sk.close()

     

    聊天工具应用:

    TCP server端

    import socket
    sk = socket.socket()
    sk.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
    sk.bind(('127.0.0.1',9000))
    sk.listen()
    while True:
        conn,addr = sk.accept()  # 接收连接 三次握手conn
        while True:
            inp = input('>>>')
            if inp == 'q':
                conn.send(inp.encode('utf-8'))
                break
            conn.send(inp.encode('utf-8'))
            msg = conn.recv(1024)
            if msg == b'q':break
            print(msg.decode('utf-8'))
        conn.close()    # 四次挥手
    sk.close()
    TCP-server

    TCP client端

    import socket
    sk = socket.socket()
    sk.connect(('127.0.0.1',9000))
    while True:
        msg = sk.recv(1024)
        print(msg.decode('utf-8'))
        if msg == b'q':break
        inp = input('>>>')
        if inp == 'q':
            sk.send(inp.encode('utf-8'))
            break
        sk.send(inp.encode('utf-8'))
    sk.close()
    TCP-client

    UDP server端

    import socket
    sk = socket.socket(type=socket.SOCK_DGRAM)
    sk.bind(('127.0.0.1',9090))
    while True:
        msg,addr = sk.recvfrom(1024)
        print('来自[%s:%s]的消息--%s'%(addr[0],addr[1],msg.decode('utf-8')))
    
        inp = input('>>>')
        sk.sendto(inp.encode('utf-8'),addr)
    
    sk.close()
    UDP-server

    UDP client

    import socket
    sk = socket.socket(type=socket.SOCK_DGRAM)
    addr = ('127.0.0.1',9090)
    while True:
        msg = input('>>>')
        sk.sendto(msg.encode('utf-8'),addr)
        msg_recv,addr = sk.recvfrom(1024)
        print(msg_recv.decode('utf-8'))
    sk.close()
    UDP-cliend

    时间同步服务器:(适合使用UDP协议)

    # 需求
    #     写一个时间同步的服务器
    #     服务端接收请求
    #     按照client端发送的时间格式,将服务器时间转换成对应格式
    #     发送给客户端
    import time
    import socket
    
    sk = socket.socket(type=socket.SOCK_DGRAM)
    sk.bind(('127.0.0.1',9000))
    while True:
        msg,addr = sk.recvfrom(1024)
        # msg 客户端发送给server端的时间格式 "%Y-%m-%d %H:%M-%S"
        time_format = msg.decode('utf-8')
        time_str = time.strftime(time_format)
        sk.sendto(time_str.encode('utf-8'),addr)
    
    sk.close()
    server端
    # client端每隔一段时间发送请求到服务端
    # 发送时间的格式
    import time
    import socket
    sk = socket.socket(type = socket.SOCK_DGRAM)
    sk.sendto('%Y-%m-%d %H:%M:%S'.encode('utf-8'),('127.0.0.1',9000))
    msg,addr = sk.recvfrom(1024)
    print(msg.decode('utf-8'))
    sk.close()
    
    
    # 方式一
    # 操作系统的定时任务 + python代码的形式
    
    # 方式二
    # while True + time.sleep的形式
    client端
  • 相关阅读:
    狗蛋带仨妞【Beta】Scrum meeting 1
    实验九 团队作业5:团队项目编码与Alpha冲刺
    狗蛋带仨妞【Alpha】Scrum meeting 7
    狗蛋带仨妞【Alpha】Scrum meeting 6
    狗蛋带仨妞【Alpha】Scrum meeting 5
    狗蛋带仨妞 【Alpha】Scrum meeting 1-4
    Rosetta中准备配体的参数文件
    pymol安装
    chemshell的creation之后
    关于KIE的一点认识
  • 原文地址:https://www.cnblogs.com/strive-man/p/8611554.html
Copyright © 2011-2022 走看看