zoukankan      html  css  js  c++  java
  • day31,socket 客户端 服务端

                                                   网络编程之socket

    socket 是应用层tcp和ip协议的通信,是一种中间的抽象层,它就像是一个接口,里面封装了很多的协议,(也可以自己重写socket)

    socket中的套接字分为两种

        1.AF_UNIX 是一个套接字

             AF_UNIX  是一种基于文件的套接字  

             unix一切皆文件,基于文件的套接字调用的就是底层的文件系统来取数据,

             两个套接字进程运行在同一机器,可以通过访问同一个文件系统间接完成通信

        2,AF_INET是一种套接字

             (还有AF_INET6被用于ipv6,还有一些其他的地址家族,不过,他们要么是只用于某个平台,

             要么就是已经被废弃,或者是很少被使用,或者是根本没有实现,所有地址家族中, AF_INET是使用最广泛的一个,

              python支持很多种地址家族,但是由于大部通讯都是网络通讯,所以大部分时候使用AF_INET)

    基于tcp的socket 就是客服端和服务端,使用socket中的tcp协议来完成客服端和服务端的连接

         什么是客服端:

             客服端就是用户 使用的程序通过用户使用程序来传输信息的这个介子,这个就是客服端

         什么是服务端:

             服务端就是给客户端提供需要的数据的,就相当于是一个库

    如何使用socket来连接客户端和服务端

    tcp 的通讯流程

       

    TCP服务端低级版

    import socket
    ip_port=('127.0.0.1',9000)  #电话卡
    BUFSIZE=1024                #收发消息的尺寸
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #买手机
    s.bind(ip_port) #手机插卡
    s.listen(5)     #手机待机
    
    conn,addr=s.accept()            #手机接电话
    
    print('接到来自%s的电话' %addr[0])
    
    msg=conn.recv(BUFSIZE)             #听消息,听话
    print(msg,type(msg))
    
    conn.send(msg.upper())          #发消息,说话
    
    conn.close()                    #挂电话
    
    s.close()                       #手机关机
    
    服务端
    View Code

    TCP客户端低级版

    import socket
    ip_port=('127.0.0.1',9000)
    BUFSIZE=1024
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    
    s.connect_ex(ip_port)           #拨电话
    
    s.send('linhaifeng nb'.encode('utf-8'))         #发消息,说话(只能发送字节类型)
    
    feedback=s.recv(BUFSIZE)                           #收消息,听话
    print(feedback.decode('utf-8'))
    
    s.close()                                       #挂电话
    View Code

    这样的客户端和服务端不是完善的所以就优化了客户端和服务端(不完善是因为有太多的错误)

    客户端和服务端的常见的错误

    在调试过程中,可能会遇见以下错误:

    问题发生原因:

    1.可能是由于你已经启动了服务器程序,却又再次启动了服务器程序,同一个端口不能被多个进程使用导致!

    2.三次握手或四次挥手时,发生了异常导致对方程序已经结束而服务器任然处于time_wait状态导致!

    3.在高并发的场景下,由于链接的客户端太多,也会产生大量处于time_wait状态的链接

    解决的方案:

    第1种原因,很简单关闭之前运行的服务器即可

    第2,3中原因导致的问题,有两种解决方案:

    1.设置服务器重用端口

    #加入一条socket配置,重用ip和端口
    phone=socket(AF_INET,SOCK_STREAM)
    phone.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #就是它,必须在bind前加
    phone.bind(('127.0.0.1',8081))

    2.通过调整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 时间

    强行关闭链接

    发生错误演示,运行上面的改进版的服务器与客户端,链接成功后直接停止客户端程序)

    当客服端与服务器链接成功后,如果一方没有执行close,而是直接强行终止程序(或是遇到异常被迫终止),都会导致另一方发送问题,

    在windows下,接收数据的一方在recv函数处将抛出异常

    Traceback (most recent call last):
      File "C:/Users/jerry/PycharmProjects/untitled/TCP/server.py", line 9, in <module>
        conn.recv(1024)
    ConnectionResetError: [WinError 10054] 远程主机强迫关闭了一个现有的连接。

    linux下,不会抛出异常会导致接收数据的一方,recv方法不断的收到空消息,造成死循环

    要使应用程序能够在不同平台正常工作,那需要分别处理这两个问题

    解决方案如下:

    import socket
    ip_port=('127.0.0.1',8081)
    BUFSIZE=1024
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s.bind(ip_port)
    s.listen(5)    
    while True:                        
        conn,addr=s.accept()           
        while True:                         
            try:
                msg=conn.recv(BUFSIZE)             
                #linux不会抛出异常,会接收到空消息,这里加以判断
                if not msg:
                    conn.close()
                    break
                print(msg,type(msg))
                conn.send(msg.upper())        
           except ConnectionResetError:
                #只要异常发生则意味着对方以及关闭了,服务器也相应的关闭该链接
                conn.close()
                break
        conn.close()              
    s.close()   
    View Code

    至此TCP通讯模板程序就完成了,可以不断的接收新的链接,不断的收发消息,并且不会因为客户端强制关闭而异常退出!

    然后就优化客户端和服务端

    改进版服务器端

    import socket
    ip_port=('127.0.0.1',8081)#电话卡
    BUFSIZE=1024
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #买手机
    s.bind(ip_port) #手机插卡
    s.listen(5)     #手机待机
    
    while True:                         #新增接收链接循环,可以不停的接电话
        conn,addr=s.accept()            #手机接电话
        # print(conn)
        # print(addr)
        print('接到来自%s的电话' %addr[0])
        while True:                         #新增通信循环,可以不断的通信,收发消息
            msg=conn.recv(BUFSIZE)             #听消息,听话
            print(msg,type(msg))
            conn.send(msg.upper())          #发消息,说话
        conn.close()                    #挂电话
    s.close()                       #手机关机
    View Code

    改进版客户端

    import socket
    ip_port=('127.0.0.1',8081)
    BUFSIZE=1024
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s.connect_ex(ip_port)           #拨电话
    
    while True:                             #新增通信循环,客户端可以不断发收消息
        msg=input('>>: ').strip()
        if len(msg) == 0:continue
        s.send(msg.encode('utf-8'))         #发消息,说话(只能发送字节类型)
        
        feedback=s.recv(BUFSIZE)                           #收消息,听话
        print(feedback.decode('utf-8'))
    s.close()                                       #挂电话
    View Code
  • 相关阅读:
    股票投资
    知道复利终值求本金
    复利计算和单利计算
    实验0:了解和熟悉操作系统
    0909我的编译原理感
    递归下降分析法
    有(很)穷的自动机
    评论
    C语言文法阅读与理解序
    C语言文法阅读与理解
  • 原文地址:https://www.cnblogs.com/WBaiC1/p/10940495.html
Copyright © 2011-2022 走看看