zoukankan      html  css  js  c++  java
  • Python,socket编程

    TCP协议 IP+端口

    应用层协议做的事不同,但都离不开数据的交换,本质上都是收和发~
    为什么要三次握手?
    目标机器可能不存在,握手期间,发送方也可能down掉。
    客户端————服务器,先发请求的那个是客户端,客户端发送的信息的端口是随机的。。服务器端的端口是固定的
    先要有接收端,相当于服务器
    接收端要申请端口号,服务要启动正常运行开始监听该端口

    地址簇Socket Families

    相当于网络层的一个东西
    socket.AF_UNIX unix本机进程间通信
    socket.AF_INET IPV4
    socket.AF_INET6 IPV6

    a进程和b进程想通信,没有网络的情况下。
    a先dump,b再load。通过硬盘的话速度慢,默认在内存中a进程是不能访问b进程数据的,想快速通信可以借助AF_UNIX,本地启动一个socket在七层协议里转一圈
    a进程传给b

    Socket Types

    socket.SOCK_STREAM #for tcp
    socket.SOCK_DGRAM #for udp
    socket.SOCK_RAW
    #原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;
    其次,SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。
    牛逼了可以伪造IP地址,DDOS攻击,洪水攻击,发送大量请求导致服务关闭
    a访问b要三次握手,a发第一次,后a改自己的IP再发请求,b的回应到不了a
    导致b端该连接出现挂起,a再改IP地址发请求..再挂起..
    socket.SOCK_RDM
    #是一种可靠的UDP形式,即保证交付数据报但不保证顺序。SOCK_RAM用来提供对原始协议的低级访问,
    在需要执行某些特殊操作时使用,如发送ICMP报文。SOCK_RAM通常仅限于高级用户或管理员运行的程序使用。
    socket.SOCK_SEQPACKET #废弃了

    实例:先启动服务器监听端口,再启动客户端:

    # 服务器
    import socket
    
    server = socket.socket()
    server.bind(("localhost",7000))#只是绑定要监听的端口
    server.listen() #监听,我要监听这个端口
    print("我开始监听7000端口了---")
    conn,addr = server.accept()  #等电话,conn就是连接实例,addr为源IP地址随机的
    
    print("请求来了")
    # data = server.recv(1024) #接收1024
    # 通话中又来一个电话要切换,server.switch()要知道先后顺序,可以给每个请求标记就是上面的conn
    data = conn.recv(1024)
    print("recv:",data)
    conn.send(data.upper())
    server.close()
    '''输出:
    我开始监听7000端口了---
    请求来了
    recv: b'helloworld'
    '''
    #客户端
    import socket
    
    client = socket.socket()
    #声明socket类型,同时生成socket对象
    #定义协议类型默认是family=AF_INET, type=SOCK_STREAM
    client.connect(("localhost",7000))
    client.send(b"helloworld")
    data = client.recv(1024)
    print("recv:", data)
    client.close()
    
    #输出:recv: b'HELLOWORLD'

     可以看出上面这种,客户端和服务器端说一句话就断了,那么我想不停地通信怎么办呢?????可以加上死循环

    # 服务器
    import socket
    
    server = socket.socket()
    server.bind(("localhost",7000))
    server.listen() 
    print("我开始监听7000端口了---")
    conn,addr = server.accept()  
    print("请求来了")
    
    while True:
        data = conn.recv(1024)
        print("recv:",data)
        conn.send(data.upper())
    server.close()
    #客户端
    import socket
    
    client = socket.socket()
    client.connect(("localhost",7000))
    while True:
        msg = input(">>:").strip()
        client.send(msg.encode("utf8"))
        data = client.recv(1024)
        print("recv:", data.decode())
    client.close()

    perfect~~~试了几次之后。。。

    又发现一个问题:客户端断了服务器端为什么也断了?

    Windows服务器出错:ConnectionResetError: [WinError 10054] 远程主机强迫关闭了一个现有的连接。

    Linux服务器:会进入进入死循环,recv不到数据(recv到""空),可以服务器端判断data接收的是否为空,是空break死循环

    那么请问,该如何让某一个客户端断了之后其他客户端可以继续连接呢?

    先试试。。可以再在conn上加一层死循环

    ,加了之后Windows还是报10054的错误,Linux里面只能一个通话,另一个占线(挂起),上一个断开了才能跟挂起的那个通话

    后面排着队,上一个结束到下一个,异步的情况下listen(3)里面可以给数字,表示最多挂起几个,。一般不要超过10个

    客户端如果发一个空过去(直接回车),就卡死了,怎么回事呢?是服务器没收到还是什么呢?

    所以不能send空,不能send空,不能send空,重要的事说三遍。。。所以就要在客户端判断一下

    那么可以把客户端模拟成SSH呢?

    服务器端搞成os.popen().read()就可以了,如果某命令执行结果超过1024byte,客户端还在继续发命令。。那么服务器端还是会不停执行

    但客户端每次只能接收1024字节,数据全存在缓冲区排队了

    那么,让客户端一次能接收很大的数据会怎样呢???

    发一个大文件,虽然客户端一次可以接很大,但是服务器端每次只能发32768,依据操作系统而定,so

    让客户端全发,循环发sendall()会怎样呢?

    但是神奇了,客户端接收开始有限制了,好像每次最多10M,依系统区别这个也有区别(在centos上试的,而有的系统还会出错)

    so...看来。。。没办法一次收过来,带宽有限制,网卡也有限制。。recieve有限制的,send也有限制的。

  • 相关阅读:
    phalcon: 当删除循环删除一组数据,需要判断影响的行affectedRows
    java:经典消费生成者
    java:同步和死锁
    java: Thread 和 runnable线程类
    git: windows git ssh keys生成
    ​'JAVAC' 不是内部或外部命令解决方法,记得要重启cmd
    java jar包解析:打包文件,引入文件
    php 对多维数组排序array_multisort
    appium入门基础
    中文Appium API 文档
  • 原文地址:https://www.cnblogs.com/revo/p/7401536.html
Copyright © 2011-2022 走看看