您的位置:68399皇家赌场 > 域名注册 > 68399皇家赌场:Java 互连网编程底蕴学习

68399皇家赌场:Java 互连网编程底蕴学习

发布时间:2020-03-18 12:56编辑:域名注册浏览(126)

    TCP开采:1.服务端基于SocketAsyncEvent,帮助高产出,每秒可收到5000个接二连三,同一时候3万个延续通讯测验通过2.平放了spliter解决带有,粘包等主题材料,易用性高3.TCP服务端帮助对顾客端的限制速度效率4.TCP服务端内置了分组功效,客户端能够参加组,可以依据组来发送数据5.提供了高级封装类,能够直接传输对象6.TCP客商端类能够设置断线重连7.TCP客商端在接连别的服务器时,也能够透过spliter方便的切割数据包和包装发送8.完毕了二个简便便捷的TCP代理类,通过此类能够完结抓包,纠正包,端口转载等作用UDP开拓:1.簇新封装UDP通讯类,内置选择队列,超级大裁减了收纳丢包的可能率2.该通讯类还合併了组播功效,用起来特别平价进度间通讯:1.贯彻了管道双工通讯2.贯彻了分享内部存储器的单工和双工通讯项目地址:安装命令:Install-PackageSiS.Communication

    2.1客商端通过地点和端口号与服务端构建Socket连接,并写入有关数据。

    - connectToServerWithCommand:(NSString *)command{ _socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)]; [_socket setUserData:command]; NSError *error = nil; [_socket connectToHost:WIFI_DIRECT_HOST onPort:WIFI_DIRECT_PORT error:&error]; if  { NSLog(@"__connect error:%@",error.userInfo); } [_socket writeData:[command dataUsingEncoding:NSUTF8StringEncoding] withTimeout:10.0f tag:6];}
    

    哪些是粘包

    唯有TCP有粘包现象,UDP恒久不会粘包

    先是供给精通三个socket收发音信的原理

    68399皇家赌场 1

      所谓粘包难题至关首要依然因为选用方不晓得消息之间的尽头,不了解一回性领取多少字节的数量所形成的

      别的,发送方引起的粘包是由TCP合同本人形成的,TCP为提升传输作用,发送方往往要搜聚到丰富多的数目后才发送一个TCP段。若总是若干回索要send的多少都比非常少,平日TCP会依据优化算法把这个多少合成三个TCP段后叁回发送出去,那样采取方就接到了粘包数据。

      1.TCP(transport control protocol,传输调整左券)是面向连接的,面向流的,提供高可信性服务。收发两端(顾客端和服务器端)都要有各种成没错socket,因而,发送端为了将多少个发往接收端的包,更使得的发到对方,使用了优化措施(Nagle算法),将一再间距十分的小且数据量小的数目,归并成三个大的数据块,然后开展封包。那样,选拔端,就难办分辨出来了,必得提供精确的拆包机制。 即面向流的通信是无音讯爱抚边界的 

       2.UDP(user datagram protocol,客户数量报公约)是无连接的,面向音信的,提供高成效服务。不会利用块的统一优化算法,, 由于UDP援救的是一对多的方式,所以采用端的skbuff(套接字缓冲区)选取了链式布局来记录每二个达到的UDP包,在种种UDP包中就有了消息头(音信来源地址,端口等新闻),那样,对于采用带来讲,就便于开展区分管理了。 即面向音讯的通讯是有消息珍重边界的。

       3.tcp是依靠数据流的,于是收发的音讯不能够为空,那就须要在客商端和服务端都增加空音讯的处理机制,幸免程序卡住,而udp是依照数据报的,即就是您输入的是空内容(直接回车),那亦不是空音讯,udp公约会帮您封装上海消防息头

     

    粘包测验一

     

    发出在顾客端的粘包

    68399皇家赌场 268399皇家赌场 3

    import socket
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s.bind(('127.0.0.1',8080))
    s.listen(5)
    
    conn,addr=s.accept()
    
    data1=conn.recv(10)
    data2=conn.recv(10)
    
    print(data1)
    print(data2)
    

    socket_server

    68399皇家赌场 468399皇家赌场 5

    import socket
    c=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    
    c.connect(('127.0.0.1',8080))
    
    c.send('hello'.encode('utf-8'))
    c.send('world'.encode('utf-8'))
    

    socke_client

    分级运转服务端与顾客端,开掘server端推行结果为下图

    68399皇家赌场 6

    按说来讲应该data1打字与印刷一部分,data2打字与印刷一部分。为什么data1都打字与印刷了?

    缘由在于clinet端,客商端send一回的结果并不是一直send到服务端,而是发给了本身的缓存,再由缓存发送到对端的缓存中,然后服务端的套接字再到温馨的缓存中抽取数据。能够看下面标红的TCP这段

    68399皇家赌场 7

    粘包测验二

    发生在服务端的粘包

    68399皇家赌场 868399皇家赌场 9

    import socket
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s.bind(('127.0.0.1',8080))
    s.listen(5)
    
    conn,addr=s.accept()
    
    data1=conn.recv(1)      #只收一个,收不完。自己的缓存区里还有elloworld,
    data2=conn.recv(100)
    
    print(data1)
    print(data2)
    

    socket_server

    68399皇家赌场 1068399皇家赌场 11

    import socket,time
    c=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    
    c.connect(('127.0.0.1',8080))
    
    c.send('hello world'.encode('utf-8'))
    #发一条消息不会粘包
    time.sleep(5)#设置间隔时间,防止在客户端粘包
    c.send('nihao'.encode('utf-8'))
    

    socket_clinet

     

    个别运行服务端与顾客端,开掘推行结果如下图。明明第三遍recv的字节为100,可以把缓存区剩下的数量总体领到出来,为何只打字与印刷了三个'ello world'

    68399皇家赌场 12

    由来在于,服务端选择若干遍后前后相继已经走完。而客商端发完第三回数据后间距了五秒又再次发包,那时候服务端已经终止,顾客端还在发包。所以服务端根本不会鸟它。

     

    减轻方法很简短,顾客端睡五秒,那么自身服务端也随后睡五秒

    68399皇家赌场 1368399皇家赌场 14

    import socket
    import time
    
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s.bind(('127.0.0.1',8080))
    s.listen(5)
    
    conn,addr=s.accept()
    
    data1=conn.recv(1)
    time.sleep(6)
    data2=conn.recv(100)
    
    print(data1)
    print(data2)
    

    改正版服务端

    TCP粘包,为何TCP会粘包,就是因为TCP基于流(streamState of Qatar,数据流专门的工作的。数据流的特色是一向不音信的境界,所招致使服务端根本不知情收多少个字节

     

    那么难点来了?怎么消除这种难题吧?上边的平息是在您领悟的场馆下,倘诺一切都以未知的气象那该要是化解呢?

    缓和情势:依旧用上边包车型地铁长途推行命令代码来测验

    正如LOW逼的情势

    在实事求是数据重回从前,先len一下要回去的数额的长短,之后将长度先回去给客商端。顾客端依据重回的轻重,再进行更正取值

    68399皇家赌场 1568399皇家赌场 16

    import socket
    import subprocess       #使用这个模块可以调用操作系统的命令
    import struct
    
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s.bind(('127.0.0.1',8080))
    s.listen(5)
    
    while True:
        #连接循环
        conn,addr=s.accept()
        print('新的客户端连接',addr)
        while True:
            try:
                # 通信循环
                cmd = conn.recv(1024)
                cmd=cmd.decode('utf-8')
                if not cmd: break
                print('客户端发来的命令是:%s' % cmd)
                cmd_res=subprocess.Popen(cmd,shell=True,
                                 stderr=subprocess.PIPE,
                                 stdout=subprocess.PIPE,
                                 )
                err=cmd_res.stderr.read()
                if err:
                    res=err
                else:
                    res=cmd_res.stdout.read()
    
                print('命令执行结果长度',len(res))
                # conn.send(str(len(res)).encode('utf-8'))#虽然这样就实现了,但是这个send与下面的send必然会粘到一块
                #解决方法:将长度做成一个固定字节的beyts。使用struct模块
                #导入模块后就不能用上面的方法send
                conn.send(struct.pack('i',len(res)))    #使用struct模块打包,i代表打包成整型,固定长度为4,客户端第一次接受4个字节再解包就知道真实数据要多少字节
                conn.send(res)     #发送真实数据
    
    
            except ConnectionResetError:
                break
    
    
        conn.close()
    s.close()    
    

    改进版服务端

    68399皇家赌场 1768399皇家赌场 18

    import socket
    import struct
    clinet=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    clinet.connect(('127.0.0.1',8080))
    
    
    while True:
        cmd=input('>>:')
        if not cmd:continue
        clinet.send(cmd.encode('utf-8'))
    
        #第一阶段:收数据的长度
        x=clinet.recv(4)          #struct模块打包后固定长度就为4,所以接收4个字节那么就不会与后面的数据发生粘包
        data_len=struct.unpack('i',x)[0]    #怎么打包就怎么解包,解包后是一个元组的形式,第一个元素就是真实数据的字节
        #第二阶段:根据数据的长度,收真实数据
        data=clinet.recv(data_len)
        print(data.decode('gbk'))
    
    clinet.close()
    

    精雕细琢版客商端

    地点的代码已经得以兑现不粘包了,只不过比较low,前面还应该有更屌爆了的秘技,我们稍安勿躁。上边的代码是由此tcp完结的远程实行命令,那么本身再用一个udp公约写一个基于udp的中远间隔实行命令

    68399皇家赌场 1968399皇家赌场 20

    import socket
    import subprocess #执行命令模块
    import struct       #打包模块,在udp中就不需要了
    
    s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)   #数据报形式,所有udp没有粘包
    #创建基于UDP的套接字
    s.bind(('127.0.0.1',8080))
    
    while True:
        cmd,addr=s.recvfrom(1024)
        print('客户端连接信息是:',addr)
        cmd=cmd.decode('utf-8')
        print('客户端发来的命令是:',cmd)
        cmd_res=subprocess.Popen(cmd,shell=True,
                         stderr=subprocess.PIPE,
                         stdout=subprocess.PIPE)
        err=cmd_res.stderr.read()
        if err:
            res=err
        else:
            res=cmd_res.stdout.read()
        print(len(res))     #打印数据长度
        s.sendto(res,addr)
    
    s.close()
    

    udp服务端

    68399皇家赌场 2168399皇家赌场 22

    import socket
    
    c=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    
    while True:
        cmd=input('>>:')
        c.sendto(cmd.encode('utf-8'),('127.0.0.1',8080))
    
        data,addr=c.recvfrom(1024)
        print(data.decode('gbk'))
    

    udp客户端

     

    在测量检验的时候,要是回去叁个低于1024字节的开始和结果,windows会输出,可是只要回到结果当先选取端要抽出的字节时,那么就能报错。这是Windows的一种机制,能够见到,笔者试行'ipconfig /all' 时重返长度为2338,而选择端只收1024,剩下的字节就丢包了。因为udp归属不可相信传输,不可靠就在于小编多少发送出去后,不管对端有没有收起,作者都把作者的缓冲区清空。固然选拔端收不全,服务端也不会给你重发了。Windows有限量,所以我们只可以在linux上做测验了,注意客商端选拔的编码为utf-8。然后笔者实践三个剧情比较长的一声令下,'ps aux' 经常情状下是8000多字节(图一卡塔尔(قطر‎,通过python测量检验后(图二State of Qatar

    68399皇家赌场 23

                图一

    68399皇家赌场 24

                              图二

    服务端选拔的音信

    68399皇家赌场 25

    能够看来图二跟服务端选拔的字节完全不相符,也正是随意服务端发多少,小编就接到10二十几个字节

    据此说udp是不会时有产生粘包的 ,而且是不行靠传输

     

      刚刚大家依据二种不相同的协商分别编写制定了长途施行命令的剧本,发现tcp有粘包现象,大家也用了一种比较low的主意消除了,上面我们就用二个相比牛X的法门来消除那个粘包难点

     

    自定义报头

      上边我们用struct模块自定义报头,我们事情发生此前从来用数码的长度打包,那样会非凡的,大家地点打包命令是:'struct.pack('i',123456卡塔尔(قطر‎,这里面包车型客车'i'代表整型,整型最多能够打包成4个字节,如若缺乏用,也足以用'q'为长整型,打包成8个字节。可是难点就出以后那,假如本人的数码超级大,上T了。比方'num=1234567891011121314151617181920'这么长,那么本人struct.pack就不可能打包进去。

     

    解决方法:

    你想,上述的法子要定义报头,报头是在实际数据前边的一段描述音讯,里面许多包罗了某些数额的牵线,文件名,文件大小,哈希值等等

    之所以大家就用字典的样式来定义报头

     

    68399皇家赌场 2668399皇家赌场 27

    import socket
    import subprocess       #使用这个模块可以调用操作系统的命令
    import struct
    import json
    
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s.bind(('127.0.0.1',8080))
    s.listen(5)
    
    while True:
        #连接循环
        conn,addr=s.accept()
        print('新的客户端连接',addr)
        while True:
            try:
                # 通信循环
                cmd = conn.recv(1024)
                cmd=cmd.decode('utf-8')
                if not cmd: break
                print('客户端发来的命令是:%s' % cmd)
                cmd_res=subprocess.Popen(cmd,shell=True,
                                 stderr=subprocess.PIPE,
                                 stdout=subprocess.PIPE,
                                 )
                err=cmd_res.stderr.read()
                if err:
                    res=err
                else:
                    res=cmd_res.stdout.read()
                #自定义报头信息
                head_dic={'filename':'a.txt','size':len(res)}#将报头设置为字典格式,定义文件名,文件大小,查看长度
                head_json=json.dumps(head_dic)       #序列化字典,将字典转换成字符串
                head_bytes=head_json.encode('utf-8')    #将字符串转换成二进制。进行网络通信
    
    
                conn.send(struct.pack('i',len(head_bytes)))
                #第一次发送head_bytes的长度信息到客户端
                conn.send(head_bytes)
                #第二次,发送报头
                conn.send(res)
                #第三次,发送真实数据
            except ConnectionResetError:
                break
    
        conn.close()
    s.close()
    

    究极版服务端 

    68399皇家赌场 2868399皇家赌场 29

    import socket
    import struct
    import json
    clinet=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    clinet.connect(('127.0.0.1',8080))
    
    
    while True:
        cmd=input('>>:')
        if not cmd:continue
        clinet.send(cmd.encode('utf-8'))
    
        #第一阶段:收数据的长度
        x=clinet.recv(4)               #报头的长度
        head_len=struct.unpack('i',x)[0]    #解出报头的长度
    
        #第二次接收数据
        head_bytes=clinet.recv(head_len)     #接收报头的长度,为bytes格式
        head_json=head_bytes.decode('utf-8')    #将bytes格式报头解码为json格式
        head_dic=json.loads(head_json)       #使用json序列化将字符串转换成字典
    
        data_len=head_dic['size']   #取出真实数据的长度
    
        #第二阶段:根据上面取出的长度,收真实数据
        recv_size= 0           #定义一个空值
        res=b''                 #定义一个空bytes
        while recv_size < data_len:     #做一个while循环取值,我每次只取1024
            recv_data=clinet.recv(1024)             
            res =recv_data                  #res每次加取到的值
            recv_size =len(recv_data)           #len一下 取到数据,并不是每次都是1024,可能最后一次只去了10个字节
            print('收到的大小:%s 数据的总大小:%s' %(recv_size,data_len))
        print(res.decode('gbk'))
    
    clinet.close()
    

    究极版顾客端

     

    3.TCP和UDP的特点

    TCP特点

    • 成立连接,产生传输数据的大道
    • 在连年中开展一大波的数目传输
    • 贰回握手,可相信
    • 鉴于必须树立连接,功能稍低

    UDP特点

    • 将数据、源和指标封装成数据包,没有需求树立连接
    • 种种数据报的分寸约束在64k
    • 不可靠,也许丢包
    • 由于无需树立连接,所以速度快

    布衣蔬食的接纳境况
    UDP:闲谈,摄像会议
    TCP:下载文件


    Step 3 连接确认

    当服务端Socket监听到顾客端Socket建议的连天央求时作出响应,营造二个新的进度,把劳务端Socket的汇报发送给顾客端,该描述获得客商端确认后就可创建起Socket连接。而服务端Socket则持续处在监听状态,继续吸收接纳别的客商端Socket的伸手。

    - connectToServer:sender { // 1.与服务器通过三次握手建立连接 NSString *host = @"192.168.1.58"; int port = 1212; //创建一个socket对象 _socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)]; NSError *error = nil; // 开始连接 [_socket connectToHost:host onPort:port error:&error]; if  { NSLog(@"%@",error); }}#pragma mark - Socket代理方法// 连接成功- socket:(GCDAsyncSocket *)sockdidConnectToHost:(NSString *)host port:port { NSLog(@"%s",__func__);}// 断开连接- socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err { if  { NSLog; } else { NSLog; }}// 发送数据- socket:(GCDAsyncSocket *)sockdidWriteDataWithTag:tag { NSLog(@"%s",__func__); //发送完数据手动读取,-1不设置超时 [sock readDataWithTimeout:-1 tag:tag];}// 读取数据-socket:(GCDAsyncSocket *)sock didReadData:data withTag:tag { NSString *receiverStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"%s %@",__func__,receiverStr);}
    

    远程施行命令

    68399皇家赌场 3068399皇家赌场 31

    import socket
    import subprocess       #使用这个模块可以调用操作系统的命令
    
    
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s.bind(('127.0.0.1',8080))
    s.listen(5)
    
    while True:
        #连接循环
        conn,addr=s.accept()
        print('新的客户端连接',addr)
        while True:
            try:
                # 通信循环
                cmd = conn.recv(1024)
                cmd=cmd.decode('utf-8')
                if not cmd: break
                print('客户端发来的命令是:%s' % cmd)
                cmd_res=subprocess.Popen(cmd,shell=True,
                                 stderr=subprocess.PIPE,
                                 stdout=subprocess.PIPE,
                                 )
                #第一个参数执行这个命令,第二个参数以shell形式,第三个参数,如果有错误将错误丢到管道中,第四个参数,将输出结果丢到管道中
                #PIPE这个管道就是给我们取拿结果,可能是对的也可能是错误的结果
                err=cmd_res.stderr.read()   #读取cmd_res里面是否有错误内容
                if err:         #如果err里面有值,那么就返回res
                    res=err
                else:
                    res=cmd_res.stdout.read()
                conn.send(res)          #像客户端返回结果
            except ConnectionResetError:
                break
    
        conn.close()
    s.close()
    

    长间隔实行命令TCP服务端

    68399皇家赌场 3268399皇家赌场 33

    import socket
    clinet=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    clinet.connect(('127.0.0.1',8080))
    
    
    while True:
        cmd=input('>>:')
        if not cmd:continue
        clinet.send(cmd.encode('utf-8'))
    
        data=clinet.recv(1024)
        print(data.decode('gbk'))       #由于在windows上默认的字符编码为gbk所以解码的时候也是gbk格式
    
    
    clinet.close()
    

    长途试行命令TCP客商端

     

    地点的服务端也然则写在linux上,显示出一种跨平台性,前提要改好编码格式,还可能有IP地址哦

     

    上边的代码已经得以基本落时效益,可是各位有未有开采标题?

    自个儿实践dir命令后,推行ipconfig /all 再度奉行dir命令开采最后一遍dir命令是上面那多少个样子,输出的依旧ipconfig的通令

    68399皇家赌场 34

    缘何会自但是然这种意义了,那就涉及到二个粘包的主题材料

    读书进度是看毕向东老师的录制。

    Socket是网络通讯的基本,是支撑TCP/IP左券的网络通讯的基本操作单元,满含实行网络通讯的总得的多样音讯:

     

    6.TCP差没有多少实例

    顾客端代码:

    public class TcpClient {
        public static void main(String[] args) {
            String info = "Hello world!";
            boolean b = sendMessage(info);
            if (b) {
                System.out.println("ok");
            }
        }
    
        private static boolean sendMessage(String info) {
            int port = 10902;
            try {
                InetAddress address = InetAddress.getByName("192.168.0.103");
                // 1 建立Socket
                Socket socket = new Socket(address, port);
                // 2 拿到输出流
                OutputStream outputStream = socket.getOutputStream();
                // 3 写入数据
                outputStream.write(info.getBytes());
                // 4 关闭Socket
                socket.close();
                return true;
            } catch (Exception e) {
                return false;
            }
        }
    }
    

    服务端代码:

    public class TcpServer {
        public static void main(String[] args) {
            receInfo();
        }
    
        private static void receInfo() {
            try {
                // 1 建立ServerSocket
                ServerSocket serverSocket = new ServerSocket(10902);
                // 2 通过accept()拿到Socket
                Socket socket = serverSocket.accept();
                // 打印IP
                System.out.println(socket.getInetAddress().getHostAddress());
                // 3 通过Socket拿到输入流
                InputStream inputStream = socket.getInputStream();
                byte[] buf = new byte[1024];
                int len;
                // 4 读取数据
                while ((len = inputStream.read(buf)) != -1) {
                    String info = new String(buf, 0, len);
                    System.out.println(info);
                }
                // 5 关闭Socket和ServerSocket
                socket.close();
                serverSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    

    客户端Socket和服务端ServerSocket68399皇家赌场,的端口号为三个。ServerSocket不怕通过端口号和顾客端的Socket通过accept()创立联系。


    互联网上八个程序通过四个双向通讯连接实现数据交互作用,这种双向通讯的总是叫做Socket。

    套接字发展史及分类

    套接字起点于 20 世纪 70 时期密苏里高校Berkeley分校版本的 Unix,即大家所说的 BSD Unix。 因而,临时大家也把套接字称为“Berkeley套接字”或“BSD 套接字”。一初始,套接字被设计用在同 一台主机上八个应用程序之间的简报。那也被称经过间通讯,或 IPC。套接字有三种(或许叫做有多个种族),分别是依照文件型的和依附互连网型的。 

     

    依附文件类型的套接字亲族

    套接字亲族的名字:AF_UNIX

    unix一切皆文件,基于文件的套接字调用的正是底层的文件系统来取数据,四个套接字进度运转在同一机器,能够透过探问同一个文件系统直接完毕通讯

    依赖互连网项目标套接字亲族

    套接字宗族的名字:AF_INET

    (还有AF_INET6被用于ipv6,还应该有一部分其余的地址亲族,可是,他们可能是只用于有些平台,要么正是早已被裁撤,大概是比超级少被接收,可能是历来未有兑现,全体地点宗族中,AF_INET是行使最广泛的三个,python帮衬很各个地址亲族,可是出于大家只关切网络编制程序,所以半数以上时候小编么只使用AF_INET)

     

    1.互连网模型

    OSI参考模型
    应用层
    表示层
    会话层
    传输层
    网络层
    数据链路层
    物理层

    面试的时候,本领老总最后和自家谈起此处时,作者代表一脸隐瞒,说不出这7层名字都是啥。


    TCP/IP 参考模型
    应用层
    传输层
    网络层
    主机至网络层

    听别人说自家近来的垂询,笔者是在最上层应用层开辟。

    网络通信要素:

    • IP地址
    • 端口号
    • 传输合同

    本文由68399皇家赌场发布于域名注册,转载请注明出处:68399皇家赌场:Java 互连网编程底蕴学习

    关键词: iO 通信 客户端 双工 服务端

上一篇:Index--过滤索引和参数化

下一篇:没有了