zoukankan      html  css  js  c++  java
  • Socket通信的Python实现

          Python中实现socket通信,socket通信的服务端比较复杂,而客户端非常简单,所以客户端基本上都是用sockct模块实现,而服务

    端用有很多模块可以使用。下面就说一下服务端可使用的模块。

    模块名简介使用情况
    socket 最原始,最低端的模块,如果你想亲自体验socket的整个实现过程,那就用它吧 不用
    SocketServer 它把socket的实现进行了很好的封装,比如server端要为每个TCP连接创建一个新的线程/进程等等,这些你不用关心,它会帮你搞定,用户的主要工作是写已连接TCP/UDP的处理方法handle() 比较常用
    select 在一个线程/进程中同时监控处理多个已连接好的socket 比较常用
    Twisted 很牛逼的一个模块,功能很强大,已经算是一个框架了 比较常用
    其它异步框架

    如gevent等

    比较常用

          下面用上面几个常用的模块实现TCP类型socket通信:Client端发送字符串,Server端收到后在数据前加处理线程/进程的id返回,Client端收到后打

    印出来。Client端如果输入的是空字符,那就关闭Client的socket,接着结束该Client进程(它会触发Server端对应的connected_socket.recv()返回空

    字符串,关闭connect_sock。以下都是在Windows上运行通过。如果想结束server或client端,那就直接kill就行了,它会自动释放占用的所有资源。

    1、使用socket模块

    Server(多线程实现)

          在Winows下,子进程的入口参数不是能有socket类对象,详见http://bugs.python.org/issue11119,所以要想实现多进程比较麻烦;而Linux上没

    有这个问题,在下面代码的基础上很小的修改就行实现。Server端监听TCP连接,对于建立好的每个连接,监听进程为其创建一个线程/进程,并检测线程/

    进程的状态,如果已结束,那就进行收尾工作。监听进程使用的是非阻塞Socket(不是立即返回,有超时),这是因为监听进程除了处理新连接之外还要检

    查子进程的状态。如果设定成阻塞,那它将所有已建立的连接POP出来由交由子线程后,就会一直阻塞在accept(),如果一直没有新的已建立好的连接,那它

    就会一直阻塞下去,就没有办法检测子线程的状态了。所以为了既能检查已建立的连接队列又能检查子进程的状态,需把该socket设置成非阻塞。handle()是

    为每个建立好的连接创建的子线程的入口。

    #-*- coding:utf-8 -*-
    
    import socket
    import threading
    
    BUFSIZE = 1024
    def handle(connected_sock): while True: data = connected_sock.recv(BUFSIZE) if len(data) >0: print 'receive:',data
    cur_thread = threading.current_thread() send_data
    = '{}:{}'.format(cur_thread.ident,data) connected_sock.sendall(send_data) #用sendall,不要用send,send并不一定发送所有send_data,可能发送了部分就返回了
    print 'send:',send_data else: print 'close the connected socket and terminate sub thread' connected_sock.close() break HOST = '' PORT = 12356 ADDR = (HOST,PORT) sub_threads = [] listen_sock = socket.socket() listen_sock.settimeout(5.0) #设定超时时间后,socket其实内部变成了非阻塞,但有一个超时时间 listen_sock.bind(ADDR) listen_sock.listen(2) print 'build connect when new TCP comes' while True: try: connected_sock,client_addr = listen_sock.accept() except socket.timeout: length = len(sub_threads) while length: sub = sub_threads.pop(0) sub_id = sub.ident #进程ID sub.join(0.1) #等待线程结束,0.1秒 if sub.isAlive(): sub_threads.append(sub) else: print 'killed sub thread ',sub_id length -=1 else: t = threading.Thread(target=handle,name='sub thread',args=(connected_sock,)) #它继承了listen_socket的阻塞/非阻塞特性,因为listen_socket是非阻塞的,所以它也是非阻塞的 #要让他变为阻塞,所以要调用setblocking connected_sock.setblocking(1) t.start() sub_threads.append(t)

    Client端

    #-*- coding:utf-8 -*-
    
    import socket
    HOST = 'localhost'
    PORT = 12356
    ADDR =(HOST,PORT)
    BUFSIZE = 1024
    
    sock = socket.socket()
    try:
        a = sock.connect(ADDR)
    except Exception,e:
        print 'error',e
        sock.close()
        sys.exit()
    
    print 'have connected with server'
    
    while True:
        data = raw_input('> ')
        if len(data)>0:
    print 'send:',data sock.sendall(data) #不要用send() recv_data
    = sock.recv(BUFSIZE) print 'receive::',recv_data else: sock.close() break

     2、SocketServer模块

    Server(多线程实现,Linux下建议用多进程)

          在Linux上可以用多进程实现,基本上把下面代码中的ThreadingTCPServer改为ForkingTCPServer就可以了。在Windows下无法用多进程,因为

    SocketServer为每个已连接创建进程时,用的是os.fork(),windows上没有fork() API,哎,干嘛不搞个兼容Windows的API啊。

          可以看到,下面的代码非常简洁,用户不用去子线程的结束后,父进程对它的收尾,也不用关心socket的关闭。这些都由SocketServer完成。

    Handler中的handle()方法与上面用socket模块写的handle方法基本相同。

    #-*- coding:utf-8 -*-
    from SocketServer import BaseRequestHandler,ThreadingTCPServer
    import threading
    
    BUF_SIZE=1024
    
    class Handler(BaseRequestHandler):
        def handle(self):
            while True:
                data = self.request.recv(BUF_SIZE)
                if len(data)>0:
                    print 'receive=',data
                    cur_thread = threading.current_thread()
                    response = '{}:{}'.format(cur_thread.ident,data)
                    self.request.sendall(response)
                    print 'send:',response
                else:
                    print 'close'
                    break
    
    
    
    if __name__ == '__main__':
        HOST = ''
        PORT = 12356
        ADDR = (HOST,PORT)
        server = ThreadingTCPServers(ADDR,Handler)  #参数为监听地址和已建立连接的处理类
        print 'listening'
        server.serve_forever()  #监听,建立好TCP连接后,为该连接创建新的socket和线程,并由处理类中的handle方法处理
  • 相关阅读:
    收银钱箱弹出设置
    IOS4.0 实例练习时钟
    mysql 日期查询操作 copy
    ios 学习笔记 2
    SVN 不能移动 xx\entries 到 xx\entries
    做一个基于PHPCMS V9架构的商城
    基于JDBC API 的事务管理代码示例
    mysql 数据类型
    Discuz!NT CreditsOperationType
    spring 事务传播行为
  • 原文地址:https://www.cnblogs.com/ajianbeyourself/p/3771198.html
Copyright © 2011-2022 走看看