• 网络编程基础之socket套接字编程实现同一IP下的信息传输


    鲁照山

    1、网络协议的5层模型,每层内容的整理
    2、画图描述三次握手四次挥手,和C端S端的状态
    3、写一个客户端,实现给服务端发送hello world 字符串,
    写一个服务端,将客户端发送的数据变成大写后返回。
    
    

    5层协议:应传网数物

    应用层、传输层、网络层、数据链路层、物理层【简称:应传网数物】

    应用层

    ## 应用层:使用B/s架构或者C/s架构的应用程序进行访问。
    上网流程分析
    --在浏览器输入www.baidu.com
    --会取DNS服务器通过域名解析成IP地址
    --向IP+端口号这个地址发送请求,就会访问到百度的服务器。
    scoket:在应用层和传输层之间的一个抽象层,他爸TCP/IP层复杂的操作抽象为几个接口供应层调用已实现进程在网络中的通信。
    
    

    传输层

    ## 传输层:
    TCP协议:
    -三次握手,四次挥手【重点】,连接如何建立,
    dos和ddos攻击称之为:拒绝服务攻击,和分布式的拒绝服务攻击。
    --端口号:
    端口范围0-65535,0-1023为系统占用端口
    --udp协议:
    发送数据,不需要响应,所以数据不可靠,主要用于看视频这些网站上
    --端口:
    通IP+子网掩码----可以确定一台设备
    通过IP+子网掩码+端口号---可以确定一个软件
    
    

    网络层

    --ip:
        ipv4:32位2进制表示,范围有限,不能表示出所有的设备,于是出现了
        ipv6
    --子网掩码:
        通过子网掩码和IP判断两个IP是否在同一个网段,通过IP地址和子网掩码做按位和运算。
    ip地址:  172.16.10.1:      10101100.00010000.00001010.000000001
    子网掩码:255.255.255.0:     11111111.11111111.11111111.000000000
    按位与运算:172.16.10.0      10101100.00010000.00001010.000000000
    -ip跟mac有转换关系
            -主机172.16.10.10/24访问172.16.10.11/24
            - ARP协议:广播的方式发送数据包,获取目标主机的mac地址
            -mac地址学习:mac地址和ip地址的映射表
                -第一次接收到就会在ip/mac映射表中添加一条数据{’172.16.10.11“:ddsadfgegsdgsdg}
        -任何一种协议都有头和内容   
        
    
    
    

    数据链路层

    --把物理层的电信号分组,每一组叫一个数据报/数据帧,每一数据帧分成:报头head和数据data两部分。
    ---每一个数据报,都由报头和数据部分
            -头:固定18个字节,6:发送者地址/6:接收者地址/6:数据类型
        -mac地址 :发送者,接收者地址,就是mac地址
            -每块网卡都有一个唯一mac地址:12位16进制数表示(前六位是厂商编号,后六位是流水线号)
        -广播:同一个局域网内通信  ,会出现广播风暴
    

    物理层

    就是一堆010101的电信号。

    三次握手

    三次握手:
    第一次握手:客户端发送syn包(syn=x)到服务器,并进入SYN_SEND状态,等待服务器确认;
    第二次握手:服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(syn=y),即SYN+ACK包,此时服务器进入SYN_RECV状态;
    第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。
    握手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。理想状态下,TCP连接一旦建立,在通信双方中的任何一方主动关闭连接之前,TCP 连接都将被一直保持下去。
    
    
    
    

    三次握手图解

    img

    四次挥手

    四次挥手
    与建立连接的“三次握手”类似,断开一个TCP连接则需要“四次握手”。
    第一次挥手:主动关闭方发送一个FIN,用来关闭主动方到被动关闭方的数据传送,也就是主动关闭方告诉被动关闭方:我已经不 会再给你发数据了(当然,在fin包之前发送出去的数据,如果没有收到对应的ack确认报文,主动关闭方依然会重发这些数据),但是,此时主动关闭方还可 以接受数据。
    第二次挥手:被动关闭方收到FIN包后,发送一个ACK给对方,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号)。
    第三次挥手:被动关闭方发送一个FIN,用来关闭被动关闭方到主动关闭方的数据传送,也就是告诉主动关闭方,我的数据也发送完了,不会再给你发数据了。
    第四次挥手:主动关闭方收到FIN后,发送一个ACK给被动关闭方,确认序号为收到序号+1,至此,完成四次挥手。
    

    四次挥手图解

    img

    FIN_WAIT_1: 这个状态要好好解释一下,其实FIN_WAIT_1和FIN_WAIT_2状态的真正含义都是表示等待对方的FIN报文。而这两种状态的区别 是:FIN_WAIT_1状态实际上是当SOCKET在ESTABLISHED状态时,它想主动关闭连接,向对方发送了FIN报文,此时该SOCKET即 进入到FIN_WAIT_1状态。而当对方回应ACK报文后,则进入到FIN_WAIT_2状态,当然在实际的正常情况下,无论对方何种情况下,都应该马 上回应ACK报文,所以FIN_WAIT_1状态一般是比较难见到的,而FIN_WAIT_2状态还有时常常可以用netstat看到。 
    FIN_WAIT_2:上面已经详细解释了这种状态,实际上FIN_WAIT_2状态下的SOCKET,表示半连接,也即有一方要求close连接,但另外还告诉对方,我暂时还有点数据需要传送给你,稍后再关闭连接。 
    TIME_WAIT: 表示收到了对方的FIN报文,并发送出了ACK报文,就等2MSL后即可回到CLOSED可用状态了。如果FIN_WAIT_1状态下,收到了对方同时带 FIN标志和ACK标志的报文时,可以直接进入到TIME_WAIT状态,而无须经过FIN_WAIT_2状态。 
    CLOSING: 这种状态比较特殊,实际情况中应该是很少见,属于一种比较罕见的例外状态。正常情况下,当你发送FIN报文后,按理来说是应该先收到(或同时收到)对方的 ACK报文,再收到对方的FIN报文。但是CLOSING状态表示你发送FIN报文后,并没有收到对方的ACK报文,反而却也收到了对方的FIN报文。什 么情况下会出现此种情况呢?其实细想一下,也不难得出结论:那就是如果双方几乎在同时close一个SOCKET的话,那么就出现了双方同时发送FIN报 文的情况,也即会出现CLOSING状态,表示双方都正在关闭SOCKET连接。 
    CLOSE_WAIT: 这种状态的含义其实是表示在等待关闭。怎么理解呢?当对方close一个SOCKET后发送FIN报文给自己,你系统毫无疑问地会回应一个ACK报文给对 方,此时则进入到CLOSE_WAIT状态。接下来呢,实际上你真正需要考虑的事情是察看你是否还有数据发送给对方,如果没有的话,那么你也就可以 close这个SOCKET,发送FIN报文给对方,也即关闭连接。所以你在CLOSE_WAIT状态下,需要完成的事情是等待你去关闭连接。 
    LAST_ACK: 这个状态还是比较容易好理解的,它是被动关闭一方在发送FIN报文后,最后等待对方的ACK报文。当收到ACK报文后,也即可以进入到CLOSED可用状态了。
    
    为什么建立连接协议是三次握手,而关闭连接却是四次握手呢? 
    这 是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的建连请求后,它可以把ACK和SYN(ACK起应答作用,而SYN起同步作用)放在一 个报文里来发送。但关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你可以未 必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以它这里的ACK报文 和FIN报文多数情况下都是分开发送的。
    

    通信服务端

    
    
    #导入一个socket模块
    import socket
    
    #想象成买手机打电话:socket.SOCK_STREAM 表示建立tcp连接 ,udp连接socket.SOCK_DGRAM
    #买了个手机
    soc=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    #插电话卡:绑定ip地址  传元组:(ip,端口号)
    soc.bind(('192.168.11.254',8080))  #如果写本机ip,局域网外部可以访问
    # 监听对方打电话
    soc.listen(5)
    #等待别人给我打电话
    conn,addr=soc.accept()
    # conn 就是通路
    #接收1024个字节
    data=conn.recv(1024)
    print('我收到用户端发的',data.upper())      #转换为大写
    #conn.send  发送数据,数据必须是bytes格式
    conn.send(bytes(data.upper()))
    
    #挂断电话
    conn.close()
    #销毁手机
    soc.close()
    
    
    
    
    
    
    

    通信用户端

    
    import socket
    #创建一个socket对象
    soc=socket.socket()
    #连接服务端
    soc.connect(('192.168.11.254',8080))
    #发送消息
    soc.send(b'hello world')
    
    data=soc.recv(1024)
    print('我收到服务端回的',data)
    #关闭连接
    soc.close()
    
  • 相关阅读:
    ThreadLocal总结
    zookeeper学习笔记
    安装solr
    VirtualBox安装Centos7
    Solr学习
    Redis缓存会出现的问题?
    面试题目总结
    mysql分库分表
    Java内存模型
    HashMap在多线程中循环链表问题(jdk1.7)
  • 原文地址:https://www.cnblogs.com/ludundun/p/11466878.html
Copyright © 2020-2023  润新知