zoukankan      html  css  js  c++  java
  • 网络编程基础-socket的简单实用

    1.软件开发架构

    开发软件需要开发一套客户端与服务端

    客户端与服务端的作用

    客户端:想连接服务端就连接服务端

    服务端:24小时不间断开着为客服端提供服务

    软件开发架构分为两种:

    C/S架构、B/S架构

    C/S架构:

    Client:客户端

    Server:服务端

    优点:软件的使用稳定,并且可以节省网络资源

    如QQ、pycharm等,手机端的微信、王者荣耀等等
    缺点:1.若用户想在同一台设备上使用多个软件,必须下载多个客户端。
    2.软件的每一次更新,客户端也必须跟着重新下载更新。

    B/S架构:

    Browser:浏览器(客户端)

    Server:服务端

    优点:浏览器充当客户端,无需用户下载更新多个软件,直接在浏览器上访问需要使用的软件。

    缺点:消耗网络资源过大,当网络过慢时,软件的使用也会不稳定。
    B/S架构的软件:例如在浏览器(客户端)上输入某个软件的域名

    2.网络编程

    发展历史:
    ————所有先进的技术都源自于军事,希望通过远程获取数据,所以出现了网络编程。
    早期如何实现远程通信:
    ——打电话————》电话线
    ——电脑台式电脑————》网线,有线网卡
    ——笔记本电脑————》有线网卡、无线网卡
    要实现远程通讯必须具备
    1.物理连接介质》网卡......
    2.互联网协议
    人与人之间沟通:中文、英文
    计算机沟通的介质:‘互联网协议’

    3.互联网协议

    ​ 互联网协议又称为网络七层协议,OSI七层协议,OSI是一个世界标准组织

    ### OSI七层协议:
    

    ​ ——应用层
    ​ ——表示层
    ​ ——会话层
    ​ ——传输层
    ​ ——网络层
    ​ ——数据链路层
    ​ ——物理连接层
    ​ 学习由下到上:
    ​ ——物理连接层
    ​ 基于电信号发送二进制的数据

    ​ ——数据链路层
    ​ 数据链路层的以太网协议专门处理基于电信号发送的二进制数据

    以太网协议:

    ​ 1.规定好电信号分组的数据方式
    ​ 2.每一台连接网线的电脑都必须有一块网卡
    ​ 网卡由不同的厂商生产
    ​ 每块网卡都有世界上独一无二的12位编号
    ​ 前六位:厂商号
    ​ 后六位:流水号

    ​ 交换机:可以让多台电脑互联到一起

    ​ 基于以太网协议发送数据:
    ​ 特点:
    ​ 广播、单播
    ​ 弊端:广播风暴、局域网与局域网之间不能夸局域网通信

    广播风暴:指当广播数据充斥网络无法处理,并占用大量网络带宽,导致正常业务不能运行,甚至彻底瘫痪

    ​ 互联网:让局域网之间进行通讯

    ​ ——网络层
    ​ ip地址:用于唯一标识计算机(局域网)的地址
    ​ ip:点分十进制
    ​ 最大值:0.0.0.0
    ​ 最小值:255.255.255.255
    ​ IPV4:互联网通信协议第四版,2011年其位址被用尽
    ​ IPV6:IPV4版本的地址不够用所以出现了IPV6
    ​ 本机IP:回环地址:127.0.0.1——》localhost
    ​ ——传输层
    ​ TCP/UDP
    ​ 端口号:表示电脑的某一个软件

    ​ 端口号范围:0-65535

    注意

     1. 0-1024都被操作系统使用了(不要动)
            2
    
    1. 尽量使用8000以外的端口号

    开发中常用的软件的默认端口号:

         ​        MySQL:3306
         ​        MongoDB:27017
         ​        Django:8000
         ​        Tomcat:8080
         ​        Flask:5000
         ​        Redis:6379
    

    ​ 若想服务端与客户端进行通信,必须建立连接。产生双向通道。
    ​ 一条是客户端往服务器发送消息的,另一端是服务端向客户端发送消息的。
    IP:用于唯一标识计算机的位置。

    port:端口 用于确认计算机上的一个应用软件。

    IP+port:世界上某一台电脑上的一个应用软件。

    TCP协议工作原理:

    ​ TCP协议是流式协议
    ​ TCP协议的工作原理

    三次握手与四次挥手:

    ​ 三次握手,建立连接:建立双向通道,建立好链接。

    三次握手:

    第一次握手:建立连接时,客户端发送syn包(syn=x)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。

    第二次握手:服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(syn=y),即SYN+ACK包,此时服务器进入SYN_RECV状态;

    第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。

    客户端向服务端发送数据,数据存放在客户端的内存中,需要服务端确认收到,数据才会在内存中释放掉,否则会隔一段时间发送一次,让服务端返回确认收到。在一段时间内,若服务端还是不返回消息,则取消发送,并释放掉内存中的数据。

    利用三次握手的洪水攻击出现在第一次握手实时,多台客户端同时向服务端发送syn请求,之后又不回复服务端发过来的建立连接的消息。详细内容参考此链接

    四次挥手:

    1)客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。
    2)服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号seq=v,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。
    3)客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。
    4)服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。
    5)客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。
    6)服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。

    关于三次握手和四次挥手详细内容及相关面试题可以参考该连接

    ​ 反馈机制:客户端往服务端发送消息,服务端接收到消息后必须要返回一个确认消息,否则客户端会一直发送消息,如果很长时间接收不到确认消息就停止发送消息。

    ​ ——应用层

    socket:

    ​ socket是一个模块,可以写一套c/s架构的套接字
    ​ socket套接字封装好各层协议的工作。socket属于抽象出来的一个层并不是真实的存在的,它封装了自己下面的层级。

    使用socket的优点:可以节省开发成本。

    socket的具体工作流程:

    先从服务器端说起。服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。

    socket的详细介绍参考此链接

    具体代码实现:

    服务端:

    import socket
    
    # 默认指定TCP协议
    # 买手机
    server = socket.socket()
    # 插卡
    server.bind(
        # ip + port
        ('127.0.0.1', 9527)
    )
    # 开机,等待接听
    server.listen(5)  # listen(5) 半连接池
    
    # 监听是否有消息
    # conn: 相当于服务端往客户端挖的管道
    conn, addr = server.accept()
    print(addr)
    
    # 听客户端给我说话
    data = conn.recv(1024).decode('utf-8')  # 可以接收1024字节数据
    print(data)
    
    conn.send(b'hello xiao tank')
    
    # 挂电话
    conn.close()
    
    # 关机
    server.close()
    

    客户端:

    import socket
    
    # 买手机
    client = socket.socket()
    
    # 往服务端拨号
    # client: 相当于客户端往服务端挖的管道
    client.connect(
        # ip + port: 寻找服务端
        ('127.0.0.1', 9527)
    )
    
    # 客户端向服务端说话
    
    client.send('你好'.encode('utf-8'))
    data = client.recv(1024)
    print(data)
    
    # 关闭连接
    client.close()
    

    一个服务端与多个客户端进行连接与通信:

    服务端:

    import socket
    
    
    serve = socket.socket()
    serve.bind(('127.0.0.1',9527))
    serve.listen(5)#半连接池:最多同时处于半连接状态的客户端的个数,当连接状态的客户端关闭之后,最早处于半连接的客户端与服务端进行连接,此时可以再有一台客户端进入半连接池等待与服务端的连接,这好比是排队买东西,一次只能排队5个人,当前面的人走了,则后面的人就可以进行消费。
    
    #conn相当于服务端往客户端的的管道
    
    while True:
        conn, addr = serve.accept()
        print(addr)
        while True:
    
            try:
                data = conn.recv(1024).decode('utf-8')
                print(data)
                if data == 'q':
                    break
    
                send_msg = input('server:').encode('utf-8')
                conn.send(send_msg)
            except Exception as e:
                print(e)
                break
        conn.close()
    

    客户端:

    import socket
    
    client = socket.socket()
    
    client.connect(('127.0.0.1',9527))
    
    
    while True:
        msg = input('client:').strip()
        client.send(msg.encode('utf-8'))
        if msg == 'q':
            break
        data = client.recv(1024).decode('utf-8')
        print(data)
    client.close()
    
    

    socket(套接字)的内置方法

    1.服务端套接字函数

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

    2.客户端套接字函数

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

    3.公共用途的套接字函数

    方法 用途
    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() 关闭套接字

    4.面向锁的套接字方法

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

    5.面向文件的套接字的函数

    方法 用途
    s.fileno() 套接字的文件描述符
    s.makefile() 创建一个与该套接字相关的文件
  • 相关阅读:
    Python 学习记录1
    IL 汇编学习笔记(四)
    Petshop 4 学习
    MSN robot 开发相关资料
    MSDN 中文网站的某些翻译简直让人抓狂
    GridView 中如何给删除按钮添加提示
    MSDTC 分布式事务无法启动
    IL 汇编学习笔记(一)
    ASP.NET 2.0 之 Master Page 学习笔记
    IL 汇编学习笔记(二)
  • 原文地址:https://www.cnblogs.com/ghylpb/p/11692953.html
Copyright © 2011-2022 走看看