zoukankan      html  css  js  c++  java
  • Socket

    socket()模块函数用法

    import socket
     socket.socket(socket_family,socket_type,protocal=0)
     socket_family 可以是 AF_UNIX(同主机) 或 AF_INET(网络,用这个)。socket_type 可以是 SOCK_STREAM(流式) 或 SOCK_DGRAM(报文)。protocol 一般不填,默认值为 0。
     
     获取tcp/ip套接字
     tcpSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     
     获取udp/ip套接字
     udpSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
     
     由于 socket 模块中有太多的属性。我们在这里破例使用了'from module import *'语句。使用 'from socket import *',我们就把 socket 模块里的所有属性都带到我们的命名空间里了,这样能 大幅减短我们的代码。
     例如tcpSock = socket(AF_INET, SOCK_STREAM)
    服务端套接字函数
    s.bind() 绑定(主机,端口号)到套接字
    s.listen() 开始TCP监听
    s.accept() 被动接受TCP客户的连接,(阻塞式)等待连接的到来

    客户端套接字函数
    s.connect() 主动初始化TCP服务器连接
    s.connect_ex() connect()函数的扩展版本,出错时返回出错码,而不是抛出异常

    公共用途的套接字函数
    s.recv() 接收TCP数据
    s.send() 发送TCP数据(send在待发送数据量大于己端缓存区剩余空间时,数据丢失,不会发完)
    s.sendall() 发送完整的TCP数据(本质就是循环调用send,sendall在待发送数据量大于己端缓存区剩余空间时,数据不丢失,循环调用send直到发完)
    s.recvfrom() 接收UDP数据
    s.sendto() 发送UDP数据
    s.getpeername() 连接到当前套接字的远端的地址
    s.getsockname() 当前套接字的地址
    s.getsockopt() 返回指定套接字的参数
    s.setsockopt() 设置指定套接字的参数
    s.close() 关闭套接字

    面向锁的套接字方法
    s.setblocking() 设置套接字的阻塞与非阻塞模式
    s.settimeout() 设置阻塞套接字操作的超时时间
    s.gettimeout() 得到阻塞套接字操作的超时时间

    面向文件的套接字的函数
    s.fileno() 套接字的文件描述符
    s.makefile() 创建一个与该套接字相关的文件

    例1:TCP

    from socket import *
    phone=socket(AF_INET,SOCK_STREAM)  #TCP连接
    phone.bind(('127.0.0.1',8081))
    phone.listen(5) #最多5个监听
    
    conn,addr=phone.accept() #等待连接进入
    while True:
        data=conn.recv(1024)
        print('server===>')
        print(data)
        conn.send(data.upper())
    conn.close()
    phone.close()
    服务端
    from socket import *
    
    phone=socket(AF_INET,SOCK_STREAM)
    phone.connect(('127.0.0.1',8081))
    
    while True:
        msg=input('>>: ').strip()
        phone.send(msg.encode('utf-8'))
        print('client====>')
        data=phone.recv(1024)
        print(data)
    客户端

    例2:UDP

    from socket import *
    phone=socket(AF_INET,SOCK_DGRAM)
    phone.bind(('127.0.0.1',8082))
    while True:
        msg,addr=phone.recvfrom(1024)
        phone.sendto(msg.upper(),addr)
    服务端
    from socket import *
    phone=socket(AF_INET,SOCK_DGRAM)
    while True:
        msg=input('>>: ')
        phone.sendto(msg.encode('utf-8'),('127.0.0.1',8082))
        msg,addr=phone.recvfrom(1024)
        print(msg)
    客户端

    tcp服务端:

    ss = socket() #创建服务器套接字
    ss.bind()      #把地址绑定到套接字
    ss.listen()      #监听链接
    inf_loop:      #服务器无限循环
        cs = ss.accept() #接受客户端链接
        comm_loop:         #通讯循环
            cs.recv()/cs.send() #对话(接收与发送)
        cs.close()    #关闭客户端套接字
    ss.close()        #关闭服务器套接字(可选)

    tcp客户端:

    1 cs = socket()    # 创建客户套接字
    2 cs.connect()    # 尝试连接服务器
    3 comm_loop:        # 通讯循环
    4     cs.send()/cs.recv()    # 对话(发送/接收)
    5 cs.close()            # 关闭客户套接字

    案例:

    import socket
    ip_port=('127.0.0.1',8081)
    BUFSIZE=1024
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) # TCP 连接
    s.bind(ip_port) #
    s.listen(5)     #可以5个等待连接
    
    
    while True:                         #新增接收链接循环,可以不停的接收
        conn,addr=s.accept()            #等待连接
        print(conn)
        print(addr)
        while True:                         #新增通信循环,可以不断的通信,收发消息
            msg=conn.recv(BUFSIZE)             #听消息,听话
    
            if len(msg) == 0:break        #如果不加,那么正在链接的客户端突然断开,recv便不再阻塞,死循环发生
    
            print(msg,type(msg))
    
            conn.send(msg.upper())          #发消息,说话
    
        conn.close()                    #挂电话
    
    s.close()                       #手机关机
    服务端
    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()                                       #挂电话
    客户端

    重用socket接口

    重用socket接口,closesocket(一般不会立即关闭而经历TIME_WAIT的过程)后想继续重用该socket:

    #加入一条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的方法:

    发现系统存在大量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 时间

    socketserver()

    基于tcp的socketserver我们自己定义的类中的

    1.   self.server即套接字对象
    2.   self.request即一个链接
    3.   self.client_address即客户端地址

    基于udp的socketserver我们自己定义的类中的

    1.   self.request是一个元组(第一个元素是客户端发来的数据,第二部分是服务端的udp套接字对象),如(b'adsf', <socket.socket fd=200, family=AddressFamily.AF_INET, type=SocketKind.SOCK_DGRAM, proto=0, laddr=('127.0.0.1', 8080)>)
    2.   self.client_address即客户端地址

    创建sockeserver的步骤

    1. 必须自己创建一个请求处理类,并且这个类要继承BaseRequestHandlerclass,并且还有重写父类里的handle()
    2. 你必须实例化TCPServer,并且传递server ip和你在第一步创建的请求处理类给这个TCPServer
    3. 接下来调server.handle_request()(只处理一个请求)或者server.serve_forever()(处理多个客户端请求,永远执行)
    4. 调用server_close()去关闭socket

    实例:

     1 import socketserver
     2 
     3 
     4 class MyTCPHandler(socketserver.BaseRequestHandler):  # 继承BaseRequestHandler这个基类
     5     def handle(self):
     6         # self.request is the TCP socket connected to the client
     7         while True:
     8             try:
     9                 self.data = self.request.recv(1024)
    10                 print("{0} write:".format(self.client_address[0]))
    11                 print(self.data)
    12                 self.request.send(self.data.upper())
    13             except ConnectionResetError as e:  # 抓去异常,这个异常当客户端断开服务端出现断开,这个只有在python3.0才会有
    14                 print("error:", e)
    15                 break
    16 
    17 
    18 if __name__ == "__main__":
    19     HOST, PORT = "localhost", 9999
    20     server = socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler)  # 每起一个TCPServer都会实例化MyTCPHandler这个类
    21     server.serve_forever()  # 实现多个链接
    22     server.server_close()  # 关闭socketserver
    服务端
     1 import socket
     2 
     3 client = socket.socket()
     4 client.connect(("localhost", 9999))
     5 
     6 while True:
     7     cmd = input(">>>:").strip()
     8     if len(cmd) == 0: continue
     9     client.send(cmd.encode("utf-8"))
    10     cmd_res = client.recv(500)
    11     print(cmd_res.decode("utf-8", 'ignore'))
    12 
    13 client.close()
    客户端
  • 相关阅读:
    Vuejs
    Vuejs
    Vuejs
    Vuejs
    JS高级之面试必须知道的几个点
    用vue快速开发app的脚手架工具
    作为一名前端开发工程师,你必须掌握的WEB模板引擎:Handlebars
    REST接口设计规范总结
    eclipse实现JavaWeb应用增量打包
    转载:作为面试官,我是怎么快速判断程序员能力的?
  • 原文地址:https://www.cnblogs.com/litzhiai/p/8039022.html
Copyright © 2011-2022 走看看