• socket编程


    Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

    我们无需深入理解tcp/udp协议,socket已经为我们封装好了,我们只需要遵循socket的规定去编程,写出的程序自然就是遵循tcp/udp标准的。

    基于文件类型的套接字家族

    套接字家族的名字:AF_UNIX

    基于网络类型的套接字家族

    套接字家族的名字:AF_INET

    import socket
    socket.socket(socket_family,socket_type,protocal=0)
    socket_family 可以是 AF_UNIX 或 AF_INET。socket_type 可以是 SOCK_STREAM 或 SOCK_DGRAM。protocol 一般不填,默认值为 0。

    获取tcp/ip套接字
    tcpSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    获取udp/ip套接字
    udpSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    由于 socket 模块中有太多的属性。我们在这里破例使用了'from module import *'语句。使用 'from socket import *',我们就把 socket 模块里的所有属性都带到我们的命名空间里了,这样能 大幅减短我们的代码。
    例如tcpSock = socket(AF_INET, SOCK_STREAM)

    服务端套接字函数
    s.bind()    绑定(主机,端口号)到套接字
    s.listen()  开始TCP监听
    s.accept()  被动接受TCP客户的连接,(阻塞式)等待连接的到来

    客户端套接字函数
    s.connect()     主动初始化TCP服务器连接
    s.connect_ex()  connect()函数的扩展版本,出错时返回出错码,而不是抛出异常

    公共用途的套接字函数
    s.recv()            接收TCP数据
    s.send()            发送TCP数据(send在待发送数据量大于己端缓存区剩余空间时,数据丢失,不会发完)
    s.sendall()         发送完整的TCP数据(本质就是循环调用send,sendall在待发送数据量大于己端缓存区剩余空间时,数据不丢失,循环调用send直到发完)
    s.recvfrom()        接收UDP数据
    s.sendto()          发送UDP数据
    s.getpeername()     连接到当前套接字的远端的地址
    s.getsockname()     当前套接字的地址
    s.getsockopt()      返回指定套接字的参数
    s.setsockopt()      设置指定套接字的参数
    s.close()           关闭套接字

    面向锁的套接字方法
    s.setblocking()     设置套接字的阻塞与非阻塞模式
    s.settimeout()      设置阻塞套接字操作的超时时间
    s.gettimeout()      得到阻塞套接字操作的超时时间

    面向文件的套接字的函数
    s.fileno()          套接字的文件描述符
    s.makefile()        创建一个与该套接字相关的文件

    socket实验推演流程

    1:用打电话的流程快速描述socket通信
    2:服务端和客户端加上基于一次链接的循环通信
    3:客户端发送空,卡主,证明是从哪个位置卡的
    服务端:
    from socket import *
    phone=socket(AF_INET,SOCK_STREAM)
    phone.bind(('127.0.0.1',8081))
    phone.listen(5)

    conn,addr=phone.accept()
    while True:
        data=conn.recv(1024)
        print('server===>')
        print(data)
        conn.send(data.upper())
    conn.close()
    phone.close()
    客户端:
    from socket import *

    phone=socket(AF_INET,SOCK_STREAM)
    phone.connect(('127.0.0.1',8081))

    while True:
        msg=input('>>: ').strip()
        phone.send(msg.encode('utf-8'))
        print('client====>')
        data=phone.recv(1024)
        print(data)

    说明卡的原因:缓冲区为空recv就卡住,引出原理图

    4.演示客户端断开链接,服务端的情况,提供解决方法

    5.演示服务端不能重复接受链接,而服务器都是正常运行不断来接受客户链接的

    6:简单演示udp
    服务端
    from socket import *
    phone=socket(AF_INET,SOCK_DGRAM)
    phone.bind(('127.0.0.1',8082))
    while True:
        msg,addr=phone.recvfrom(1024)
        phone.sendto(msg.upper(),addr)
    客户端
    from socket import *
    phone=socket(AF_INET,SOCK_DGRAM)
    while True:
        msg=input('>>: ')
        phone.sendto(msg.encode('utf-8'),('127.0.0.1',8082))
        msg,addr=phone.recvfrom(1024)
        print(msg)

    基于tcp的套接字

    tcp是基于链接的,必须先启动服务端,然后再启动客户端去链接服务器端

    tcp服务端

    ss=socket() 创建服务器套接字

    ss.bind() 把地址绑定到套接字

    ss.listen() 监听链接

    inf_loop:  服务器无限循环

        cs=ss.accept() 接受客户端链接

             cs.recv()/cs.send()  对话(接受与发送)

         cs.close() 关闭客户端套接字

    ss.close()   关闭服务器套接字()

    tcp客户端

    cs=socket() 创建客户套接字

    cs.connect()  尝试链接服务器

    comm_loop:   通讯循环

          cs.send()/cs.recv()  对话(发送/接受)

    cs.close()  关闭客户端套接字

    加上链接循环与通信循环

    import socket

    ip_port=('127.0.0.1,8081')

    BUFSIZE=1024

    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

    s.bind(ip_port)

    s.listen(5)

    while True:

        conn,addr=s.accept()

        print('接受来自%s的电话‘ %addr[0])

        while True:

            msg=conn.recv(BUFSIZE)

            if len(msg) == 0:break

            conn,send(msg.upper())

        conn.close()

    s.close()

    #_*_coding:utf-8_*_
    __author__ = 'Linhaifeng'
    import socket
    ip_port=('127.0.0.1',8081)
    BUFSIZE=1024
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

    s.connect_ex(ip_port)           #拨电话

    while True:                             #新增通信循环,客户端可以不断发收消息
        msg=input('>>: ').strip()
        if len(msg) == 0:continue
        s.send(msg.encode('utf-8'))         #发消息,说话(只能发送字节类型)

        feedback=s.recv(BUFSIZE)                           #收消息,听话
        print(feedback.decode('utf-8'))

    s.close()                                       #挂电话

    客户端改进版

    基于udp的套接字

    udp是无连接的,先启动那一段都不会报错

    udp服务器

    ss = socket()创建一个服务器套接字

    ss.bind() 绑定到服务器套接字

    inf_loop:  服务器无限循环

       cs = ss.recvfrom()/ss.sendto() 对话(发送与接受)

    ss.close()  关闭服务器套接字

    udp客户端

    cs = socket() 创建客户端套接字

    comm_loop:  通讯循环

        cs.sendto()/cs.recvfrom()  对话(发送/接收)

    cs.close() 关闭套接字

    udp套接字简单示例

    import socket

    ip_port=('127.0.0.1',9000)

    BUFSIZE=1024

    udp_server_client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

    udp_server_client.bind(ip_port)

    while True:

        msg,addr=udp_server_client.recvfrom(BUFSIZE)

        print(msg,addr)

        udp_server_client.sendto(msg,upper(),addr)

    import socket

    ip_port=('127.0.0.1',9000)

    BUFSIZE=1024

    udp_server_client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

    while True:

        msg=input('>>:').strip()

        if not msg:continue

        udp_server_client.sendto(msg.encode('utf-8'),ip_port)

        back_msg,addr=udp_server_client.recvfrom(BUFSIZE)

        print(back_msg.decode('utf-8'),addr)

    QQ聊天

    #_*_coding:utf-8_*_
    __author__ = 'Linhaifeng'
    import socket
    ip_port=('127.0.0.1',8081)
    udp_server_sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) #买手机
    udp_server_sock.bind(ip_port)

    while True:
    qq_msg,addr=udp_server_sock.recvfrom(1024)
    print('来自[%s:%s]的一条消息:33[1;44m%s33[0m' %(addr[0],addr[1],qq_msg.decode('utf-8')))
    back_msg=input('回复消息: ').strip()

    udp_server_sock.sendto(back_msg.encode('utf-8'),addr)

    udp服务端

    #_*_coding:utf-8_*_
    __author__ = 'Linhaifeng'
    import socket
    BUFSIZE=1024
    udp_client_socket=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

    qq_name_dic={
    '狗哥alex':('127.0.0.1',8081),
    '瞎驴':('127.0.0.1',8081),
    '一棵树':('127.0.0.1',8081),
    '武大郎':('127.0.0.1',8081),
    }


    while True:
    qq_name=input('请选择聊天对象: ').strip()
    while True:
    msg=input('请输入消息,回车发送: ').strip()
    if msg == 'quit':break
    if not msg or not qq_name or qq_name not in qq_name_dic:continue
    udp_client_socket.sendto(msg.encode('utf-8'),qq_name_dic[qq_name])

    back_msg,addr=udp_client_socket.recvfrom(BUFSIZE)
    print('来自[%s:%s]的一条消息:33[1;44m%s33[0m' %(addr[0],addr[1],back_msg.decode('utf-8')))

    udp_client_socket.close()

    udp客户端1

    ntp时间服务器

    #_*_coding:utf-8_*_
    __author__ = 'Linhaifeng'
    from socket import *
    from time import strftime

    ip_port=('127.0.0.1',9000)
    bufsize=1024

    tcp_server=socket(AF_INET,SOCK_DGRAM)
    tcp_server.bind(ip_port)

    while True:
    msg,addr=tcp_server.recvfrom(bufsize)
    print('===>',msg)

    if not msg:
    time_fmt='%Y-%m-%d %X'
    else:
    time_fmt=msg.decode('utf-8')
    back_msg=strftime(time_fmt)

    tcp_server.sendto(back_msg.encode('utf-8'),addr)

    tcp_server.close()

    ntp客户端

    #_*_coding:utf-8_*_
    __author__ = 'Linhaifeng'
    from socket import *
    ip_port=('127.0.0.1',9000)
    bufsize=1024

    tcp_client=socket(AF_INET,SOCK_DGRAM)

    while True:
    msg=input('请输入时间格式(例%Y %m %d)>>: ').strip()
    tcp_client.sendto(msg.encode('utf-8'),ip_port)

    data=tcp_client.recv(bufsize)

    print(data.decode('utf-8'))

    tcp_client.close()

  • 相关阅读:
    Sharding-Jdbc 自定义分库分表-复合分片算法自定义实现
    sklearn:Python语言开发的通用机器学习库
    php验证码--图片
    ListView中的Item点击事件和子控件的冲突或者item点击没有反应的解决的方法
    【转载】C# Graphics类具体解释
    Oracle之外键(Foreign Key)使用方法具体解释(二)- 级联删除(DELETE CASCADE)
    职业生涯-小公司和大公司的不同(持续更新)
    视音频数据处理入门:AAC音频码流解析
    让人非常easy误解的TCP拥塞控制算法
    Redis资料整理
  • 原文地址:https://www.cnblogs.com/mayicai/p/9216201.html
Copyright © 2020-2023  润新知