• Python——socket网络编程



    socket编程

    应用程序架构的分类:
    C/S 客户端/服务器
    B/S 浏览器/服务器

    C/S架构和B/S架构的区别
    C/S架构的优点:

    1. 个性化更容易实现
    2. 更安全
    3. 占用网络资源少

    B/S结构的优点:

    1. 更新方便
    2. 使用方便
    3. 几乎不占用本地资源

    @


    前言

    1. C/S架构与socket的关系:我们学习socket的目的是为了实现C/S架构;
    2. 还有一种架构是基于socket来实现的,写一个服务器端软件,客户端软件不用写,客户端就是浏览器(浏览器的本质是套接字写的客户端);

    一、什么是网络

    在一台计算机上由硬件,硬件之上是操作系统,操作系统之上是应用程序(为客户端软件)
    在另一台计算机上硬件之上是操作系统,在操作系统之上是应用程序(服务器端软件),这两台计算机是基于网络通信的

    什么是网络:

    1. 物理介质:网线;

    2. 协议(就像两个人打电话,物理介质是电话线,两个人处于不同的地区,两个人说的话彼此听不懂,怎么解决?定义一个标准,称之为互联网协议)

    总结:
    在计算机通信中,计算机除了物理链接介质外,想要通信,计算机必须有一个标准,称之为互联网协议
    即(网络就是物理链接介质和互联网协议)
    接下来写一个客户端软件和服务器软件,两者之间基于网络通信(网络包含:物理链接介质,(是网络工程师干的);我们要干的事情是客户端软件给服务器软件发消息,必须让服务器软件和客户端软件遵循互联网协议)

    二、互联网协议按照功能不同分为osi七层或tcp/ip五层或tcp/ip四层

    (我们主要学习五层)
    在这里插入图片描述
    数据的封装与解封装详情见:https://www.cnblogs.com/huoxc/p/13611394.html
    在网络层:IP协议
    传输层:TCP/UDP协议
    数据链路层:以太网协议
    应用层:http协议,DNS协议,ftp协议

    三:什么是socket

    在这里插入图片描述

    • 应用层软件是我们写的,想要发数据传给传输层,应用层规定好的协议其他层控制不了,是客户端和服务器端规定好的,没人管,但是往外发数据,必须按照UDP或者TCP协议;如果用TCP协议必须按照TCP的协议来,必须把TCP协议学会以及IP协议等;那么效率比较低;
    • 怎么解决:对于这种情况把TCP,IP协议等疯涨起来,对于我来说TCP以下我都不打交道了,我只跟应用层打交道,socket就是在应用层和传输层之间的,传输层一下的都封装到socket中,对于我来遵循套接字的标准,那么我们基于socket来开发的;针对这种协议,python中有一个模块,socket

    四:套接字的工作流程

    (TCP协议的套接字)
    在这里插入图片描述
    首先:
    1:服务器端先拿到一个套接字对象
    2:接下来绑定IP和端口
    3:接下来监听
    4:等待客户端的链接
    其次:
    1:客户端拿到一个套接字对象
    2:客户端和服务器建立链接(即3次握手,双向链接)
    3:客户端向服务器发送数据
    4:服务器对请求进行处理,处理完毕后再响应给客户端
    5:关闭客户端

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

    服务端

    import socket
    ip_port=('127.0.0.1',9000)  
    BUFSIZE=1024                #收发消息的大小
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #其中socket.AF_INET:基于网络通信的套接字;
    #socket.SOCK_STREAM:流式套接字又称之为TCP协议
    s.bind(ip_port) #绑定的IP和端口(IP为服务器的IP)
    s.listen(5)     #监听,如打电话,在跟别人通话的时候,还可能来多个电话,这个链接处于挂起的状态,如果当前的链接以结束,立马就跟刚刚挂起的电话通信,在TCP协议中被称之为连接池的大小
    
    
    conn,addr=s.accept()            #手机接电话(accept是一种阻塞操作,什么时候变成非阻塞状态,有人链接就会变成非阻塞状态)返回一个链接对象,客户端的IP地址和端口
    # print(conn)
    # print(addr)
    print('接到来自%s的电话' %addr[0])
    
    msg=conn.recv(BUFSIZE)             #接受消息
    print(msg,type(msg))
    
    conn.send(msg.upper())          #发消息,
    
    conn.close()                    #关闭链接
    
    s.close()                       #关闭套接字
    
    

    客户端:

    import socket
    ip_port=('127.0.0.1',9000)
    BUFSIZE=1024
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    
    s.connect(ip_port)           #建立链接
    
    s.send('lheiehei '.encode('utf-8'))         #发消息(基于网络发送的是二进制格式)
    
    feedback=s.recv(BUFSIZE)                           #收消息
    print(feedback.decode('utf-8'))
    
    s.close()                                       #关闭链接
    
    

    有可能还会出现以下的情况:
    在这里插入图片描述
    怎么解决:
    这个是由于你的服务端仍然存在四次挥手的time_wait状态在占用地址(如果不懂,请深入研究1.tcp三次握手,四次挥手 2.syn洪水攻击 3.服务器高并发情况下会有大量的time_wait状态的优化方法)

    #加入一条socket配置,重用ip和端口  或者重新写一个非著名端口
    
    phone=socket(AF_INET,SOCK_STREAM)
    phone.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #就是它,在bind前加
    phone.bind(('127.0.0.1',8080))
    

    如果在Linux中解决方法如下:

    发现系统存在大量TIME_WAIT状态的连接,通过调整linux内核参数解决,
    vi /etc/sysctl.conf
    
    编辑文件,加入以下内容:
    net.ipv4.tcp_syncookies = 1
    net.ipv4.tcp_tw_reuse = 1
    net.ipv4.tcp_tw_recycle = 1
    net.ipv4.tcp_fin_timeout = 30
     
    然后执行 /sbin/sysctl -p 让参数生效。
     
    net.ipv4.tcp_syncookies = 1 表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭;
    
    net.ipv4.tcp_tw_reuse = 1 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;
    
    net.ipv4.tcp_tw_recycle = 1 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。
    
    net.ipv4.tcp_fin_timeout 修改系統默认的 TIMEOUT 时间
    

    加上链接循环与通信循环:

    服务端:
    import socket
    ip_port=('127.0.0.1',9000)  #电话卡
    BUFSIZE=1024                #收发消息的尺寸
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #买手机
    print(s)      #s是套接字对象:这个套接字对象主要用来建立三次握手
    s.bind(ip_port) #手机插卡
    s.listen(5)     #手机待机
    
    
    conn,addr=s.accept()            #手机接电话
    # print(conn)
    # print(addr)
    while True:
    	msg=conn.recv(BUFSIZE)             #听消息,听话(这种套接字主要用来收发消息,跟一个客户端收发消息,因为跟一个客户端建号的三次握手)
    	conn.send(msg.upper())          #发消息,说话
    
    conn.close()                    #挂电话
    
    s.close()
    
    客户端:
    import socket
    ip_port=('127.0.0.1',9000)
    BUFSIZE=1024
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    
    s.connect(ip_port)           #拨电话
    while True:
    	s.send('linhaifeng nb'.encode('utf-8'))         #发消息,说话(只能发送字节类型)
    	feedback=s.recv(BUFSIZE)                           #收消息,听话
    	print(feedback.decode('utf-8'))
    
    s.close()                                       #挂电话
    

    总结:

    服务端套接字有几种形式:

    1. conn这种套接字(这种套接字主要用来收发消息,跟一个客户端收发消息,因为跟一个客户端建号的三次握手)
      如果再换一个客户端链接,就是一个新的conn对象;
    2. 刚开始的时候,拿到的s套接字对象,这个套接字对象主要用来建立三次握手;

    如果客户端发的是空,则直接卡住了,在客户端没有卡住,在服务器端卡住了,服务端一直在等着,怎么解决?,在客户端解决;

    import socket
    ip_port=('127.0.0.1',9000)
    BUFSIZE=1024
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    
    s.connect(ip_port)           #拨电话
    while True:
    	msg=input('>>>:').strip()
    	if not msg:continue   #当为空的时候,继续让用户输入
    		
    
    s.close()                                       #挂电话
    

    粘包:

    须知:只有TCP有粘包现象,UDP永远不会粘包,首先需要掌握一个socket收发消息的原理

    在这里插入图片描述

    解决粘包:https://www.cnblogs.com/huoxc/p/13999288.html

    有志者,事竟成,破釜沉舟,百二秦关终属楚; 苦心人,天不负,卧薪尝胆,三千越甲可吞吴。 想到与得到中间还有两个字——做到。
  • 相关阅读:
    java学习之—栈
    java中的a++与++a的区别
    java学习之—数组的曾删改查
    Mybatis #{ } 和 ${ } 区别
    详解Windows不重启使环境变量修改生效(经典)
    laravel artisan常用命令
    Laravel 出现 No application encryption key has been specified.
    springboot的几种启动方式
    Angular 服务的简单使用
    Angular-1.6 路由 简单使用
  • 原文地址:https://www.cnblogs.com/huoxc/p/13606374.html
Copyright © 2020-2023  润新知