zoukankan      html  css  js  c++  java
  • python之网络编程

    软件开发的架构

    我们了解涉及到的俩个程序之间的通讯大致可以分为俩种:

    第一种:应用类:qq、微信、网盘、这一类需要安装的桌面应用

    第二种:web类:比如百度、知乎、博客园等使用浏览器就可以使用的应用

    这些应用的本质上其实都是两个程序之间的通讯,而这俩个分类对应了俩个开发的架构

    1、C/S 架构

    C/S 即:Client与Server, 中文的意思是:客户端与服务端架构.这种架构也是从用户层面(也可以是物理层面)来划分的

    这里的客户端一般是泛指的是客户端程序EXE,程序先安装后,才能运行在用户的电脑上,对用户的电脑操作系统环境依赖比较大

     2、B/S  架构

    B/S 即 Browser 与 Server 中文的意思:浏览器与服务端架构、这种架构是从用户层面来划分的

    Browser浏览器,其实也是一种Client客户端,只是这个客户端不需要大家去安装什么应用程序,只需要在浏览器上通过HTTP请求服务器相关的资源(网页资源),客户端Browser浏览器就可以进行增删改查

    tcp协议和udp协议

    用于应用程序之间的通信.如果说ip地址和mac地址帮我们确定唯一一台机器,那么我们怎么找到一台机器上的软件呢?

    端口

    我们知道、一台拥有ip地址的主机可以提供许多服务,比如web服务,FTP服务,SMTP服务,这些服务完全可以通过一个ip地址来实现,那么,主机是怎样区分不同网络服务?显然不能只靠IP地址,因为IP地址与网络服务的关系的一对多的关系.实际上通过“IP地址加端口号来区分不同的服务的”

    TCP协议

    当应用程序希望通过TCP与另一个应用程序通信时,它会发送一个通信请求,这个通信请求必须被送到一个确切的地址,在双方握手之后,TCP将俩个程序之间建立一个全双工的通信。

    这个全双工的的通信将占用俩个计算机之间的通信线路,直到它被一方或者双方都关闭为止

     三次握手

    TCP是因特网中的传输层协议,使用三次握手协议建立连接,当主动方发出SYN连接请求后,等待对方回答SYN+ACK,并最终对方的syn执行ACK确认.

    这种建立连接的方法可以防止产生错误的连接.

    TCP三次握手过程如下:

    客户端方式SYN(SEQ = x)报文给服务器端,进入SYN_SEND状态.

    服务器端收到SYN报文,回应一个SYN(SEQ = y)ACK(ACK = x+1)报文,进入SYN_RECV状态

    客户端收到服务器端SYN报文,回应一个ACK(ACK = y+1)报文,进入Establishe状态

    三次握手完成,TCP客户端和服务器端成功的建立连接,可以开始传输数据了。

    四次挥手:

    建立一个连接需要三次握手,而终止一个连接要经过四次挥手,这是TCP半关闭(half-close)造成的

    1. 某个应用进程首先close,称该端执行“主动关闭”(active-close).该端的tcp于是发送一个FIN分节,表示数据发送完毕
    2. 接受这个FIN对端执行“被动关闭”(Passive close) 这个FIN由TCP确认(注意:FIN的接受也作为一个文件结束符(end-of-fiel)传递给接收应用进程,放在已排队等候该应用进程接收的任何其他数据之后,因为,FIN的接收意味着接收端应用进程在相应连接上再无额外数据可接收。)
    3. 一段时间后,接收在文件结束符的应用进程将调用close关闭它的套接字,这导致它的TCP也发送一个FIN
    4. 接收这个最终的FIN的原发送端TCP(即执行主动关闭的那一端)确认这个FIN

    既然每个方向都需要一个FIN和一个ACK,因此通常需要4个分节。

    UDP协议

    当应用程序希望通过UDP与一个应用程序通信时,传输数据之前源端和终端不建立连接。

    当它想传送时就简单地去抓取来自应用程序的数据,并尽可能快地把它扔到网络上。

    TCP和UDP的对比

    TCP---传输控制协议,提供的是面向连接、可靠的字节流服务。当客户和服务器彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能传输数据。TCP提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到另一端。 

    UDP---用户数据报协议,是一个简单的面向数据报的运输层协议。UDP不提供可靠性,它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地。由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快

    套接字(socket)初识

    基于TCP协议的socket

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

    server端

    import socket
    sk = socket.socket()
    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()  # 关闭服务器套接字(可选)

    client端

    import socket
    sk = socket.socket()  # 创建客户套接字
    sk.connect(('127.0.0.1',8898))  # 尝试连接服务器
    sk.send(b'hello!')
    ret = sk.recv(1024)  # 对话(发送/接收)
    print(ret)
    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()  # 关闭服务器套接字(可选)

     基于UDP协议的socket

    udp是无链接的,启动服务之后可以直接接受消息 , 不需要提前建立链接

    简单使用:server端

    import socket
    udp_sk = socket.socket(type=socket.SOCK_DGRAM)   #创建一个服务器的套接字
    udp_sk.bind(('127.0.0.1',9000))        #绑定服务器套接字
    msg,addr = udp_sk.recvfrom(1024)
    print(msg)
    udp_sk.sendto(b'hi',addr)                 # 对话(接收与发送)
    udp_sk.close()                         # 关闭服务器套接字

    client端:

    import socket
    ip_port=('127.0.0.1',9000)
    udp_sk=socket.socket(type=socket.SOCK_DGRAM)
    udp_sk.sendto(b'hello',ip_port)
    back_msg,addr=udp_sk.recvfrom(1024)
    print(back_msg.decode('utf-8'),addr)

    QQ聊天:

    server

    #_*_coding:utf-8_*_
    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)
    
    server

     client

    #_*_coding:utf-8_*_
    import socket
    BUFSIZE=1024
    udp_client_socket=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    
    qq_name_dic={
        '金老板':('127.0.0.1',8081),
        '哪吒':('127.0.0.1',8081),
        'egg':('127.0.0.1',8081),
        'yuan':('127.0.0.1',8081),
    }
    
    
    while True:
        qq_name=input('请选择聊天对象: ').strip()
        while True:
            msg=input('请输入消息,回车发送,输入q结束和他的聊天: ').strip()
            if msg == 'q':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()

     

  • 相关阅读:
    参数模型和非参数模型
    windows上安装第二个mysql
    Mysql 连接数,最大并发数设置
    mybatis 一次执行多条sql
    微信小程序发布新版本的小程序之后,从发现-小程序中启动,还是看的到旧版本。[转]
    Fragment调用startActivityForResult导致的回调Activity无法获取正确的requestId的问题
    不可重入锁和可重入锁
    Android gradle 各种版本下载
    android 各国语言对应的缩写
    解决乱码setCharacterEncoding("UTF-8")不生效的问题
  • 原文地址:https://www.cnblogs.com/Zhao--C/p/10320109.html
Copyright © 2011-2022 走看看