zoukankan      html  css  js  c++  java
  • [Python 网络编程] TCP Client (四)

    TCP Client

    • 客户端编程步骤:
    • 创建socket对象
    • 连接到服务端的ip和port,connect()方法
    • 传输数据
      •   使用send、recv方法发送、接收数据
    • 关闭连接,释放资源 

    最简单的客户端:

    #TCP Client客户端
    import socket
    
    client = socket.socket()
    client.connect(('127.0.0.1',9999))
    
    client.send("Hi, I'm client1.".encode())
    client.close()
    
    #运行
    

      

    服务端状态:

    [16:08:25]	 [showthreads,1796] [<_MainThread(MainThread, started 9816)>, <Thread(show_client, started daemon 9344)>, <Thread(accept, started daemon 5908)>, <Thread(showthreads, started 1796)>]
    [16:08:26]	 [accept,5908] <socket.socket fd=424, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 9999), raddr=('127.0.0.1', 5287)>-('127.0.0.1', 5287)
    [16:08:26]	 [show_client,9344] {('127.0.0.1', 5287): <_io.TextIOWrapper mode='rw' encoding='utf8'>}
    2017/12/24 16:08:26 127.0.0.1:5287
    Hi, I'm client1.
    
    [16:08:26]	 [recv,980] 2017/12/24 16:08:26 127.0.0.1:5287
    Hi, I'm client1.
    
    [16:08:26]	 [recv,980] ('127.0.0.1', 5287) quit
    [16:08:28]	 [showthreads,1796] [<_MainThread(MainThread, started 9816)>, <Thread(show_client, started daemon 9344)>, <Thread(accept, started daemon 5908)>, <Thread(showthreads, started 1796)>]
    

      

    将上面的TCP Client封装成类:

    1)搭架子

    #TCP Client客户端 封装成类
    import socket
    
    
    class ChatClient:
        def __init__(self):
            pass
    
        def start(self):
            pass
    
        def _recv(self):
            pass
    
        def send(self):
            pass
    
        def stop(self):
            pass
    

      

    2)基础功能

    客户端:

    #TCP Client客户端 封装成类
    import socket,threading,logging,datetime
    DATEFMT="%H:%M:%S"
    FORMAT = "[%(asctime)s]	 [%(threadName)s,%(thread)d] %(message)s"
    logging.basicConfig(level=logging.INFO,format=FORMAT,datefmt=DATEFMT)
    
    
    class ChatClient:
        def __init__(self,ip='127.0.0.1',port=9999):
            self.sock = socket.socket()
            self.addr = (ip,port)
    
            self.event = threading.Event()
            self.start()
    
    
        def start(self):
            self.sock.connect(self.addr)
    
            # 准备接收数据,recv是阻塞的,启动新的线程
            threading.Thread(target=self._recv,name='recv').start()
    
    
        def _recv(self):
            while not self.event.is_set():
                try:
                    data = self.sock.recv(1024) #阻塞
    
                except Exception as e:
                    logging.info(e) #有任何异常保证退出
                    break
                msg = "{:%H:%M:%S} {}:{}
    {}
    ".format(datetime.datetime.now(),*self.addr,data.decode().strip())
                # print(type(msg),msg)
                logging.info("{}".format(data.decode()))
    
        def send(self,msg:str):
            data = "{}
    ".format(msg.strip()).encode()
            self.sock.send(data)
    
        def stop(self):
            logging.info("{} broken".format(self.addr))
            self.sock.close()
    
            self.event.wait(3)
            self.event.set()
            logging.info("byebye")
    
    
    def main():
        e = threading.Event()
        cc = ChatClient()
    
        while True:
            msg = input(">>> ")
            if msg.strip() == 'quit':
                cc.stop()
                break
            cc.send(msg)
    
    
    if __name__ == '__main__':
        main()
    

      

    服务端:

    #TCP Server 改装成makefile
    import threading,logging,time,random,datetime,socket
    DATEFMT="%H:%M:%S"
    FORMAT = "[%(asctime)s]	 [%(threadName)s,%(thread)d] %(message)s"
    logging.basicConfig(level=logging.INFO,format=FORMAT,datefmt=DATEFMT)
    
    class ChatServer:
        def __init__(self,ip='127.0.0.1',port=9999): #启动服务
            self.addr = (ip,port)
            self.sock = socket.socket()
            self.event = threading.Event()
    
            self.clients = {} #客户端
    
        def show_client(self):
            while not self.event.is_set():
                if len(self.clients) > 0:
                    logging.info(self.clients)
                    self.event.wait(3)
    
    
        def start(self):
            self.sock.bind(self.addr)
            self.sock.listen()
            # accept会阻塞主线程,所以开一个新线程
            threading.Thread(target=self._accept,name='accept',daemon=True).start()
            threading.Thread(target=self.show_client,name='show_client',daemon=True).start()
    
    
        def stop(self):
            for c in self.clients.values():
                c.close()
            self.sock.close()
            self.event.wait(3)
            self.event.set()
    
        def _accept(self):
            while not self.event.is_set(): #多人连接
                conn,client = self.sock.accept()  #阻塞
                f = conn.makefile(mode='rw')
                self.clients[client] = f
    
                logging.info("{}-{}".format(conn,client))
                # recv 默认阻塞,每一个连接单独起一个recv线程准备接收数据
                threading.Thread(target=self._recv, args=(f, client), name='recv',daemon=True).start()
    
        def _recv(self, f, client): #接收客户端数据
            while not self.event.is_set():
                try:
                    data = f.readline()
                except Exception:
                    data = 'quit'
                finally:
                    msg = data.strip()
                    # Client通知退出机制
                    if msg == 'quit':
                        f.close()
                        self.clients.pop(client)
    
                        logging.info('{} quit'.format(client))
                        break
    
                msg = "{:%Y/%m/%d %H:%M:%S} {}:{}
    {}
    ".format(datetime.datetime.now(),*client,data)
                # msg = data
                print(msg)
                logging.info(msg)
    
                for c in self.clients.values():
                    # print(type(msg))
                    c.writelines(msg)
                    c.flush()
    
    
    
    cs = ChatServer()
    print('!!!!!!!!!!!')
    cs.start()
    print('~~~~~~~~~~~~~~~~~~~~')
    e = threading.Event()
    def showthreads(e:threading.Event):
        while not e.wait(3):
            logging.info(threading.enumerate())
    
    threading.Thread(target=showthreads,name='showthreads',args=(e,)).start()
    
    while not e.wait(1): # Sever控制台退出方式
        cmd = input('>>> ').strip()
        if cmd == 'quit':
            cs.stop()
            e.wait(3)
            break
    

      

    运行结果:

    #服务端
    ~~~~~~~~~~~~~~~~~~~~
    >>> [17:26:14]	 [show_client,7824] {('127.0.0.1', 7517): <_io.TextIOWrapper mode='rw' encoding='cp936'>}
    [17:26:14]	 [accept,3832] <socket.socket fd=400, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 9999), raddr=('127.0.0.1', 7517)>-('127.0.0.1', 7517)
    [17:26:15]	 [showthreads,5928] [<Thread(accept, started daemon 3832)>, <Thread(show_client, started daemon 7824)>, <Thread(recv, started daemon 2112)>, <_MainThread(MainThread, started 7412)>, <Thread(showthreads, started 5928)>]
    [17:26:17]	 [show_client,7824] {('127.0.0.1', 7517): <_io.TextIOWrapper mode='rw' encoding='cp936'>}
    [17:26:18]	 [showthreads,5928] [<Thread(accept, started daemon 3832)>, <Thread(show_client, started daemon 7824)>, <Thread(recv, started daemon 2112)>, <_MainThread(MainThread, started 7412)>, <Thread(showthreads, started 5928)>]
    [17:26:19]	 [recv,2112] 2017/12/24 17:26:19 127.0.0.1:7517
    hello1
    
    
    2017/12/24 17:26:19 127.0.0.1:7517
    hello1
    
    
    [17:26:20]	 [show_client,7824] {('127.0.0.1', 7517): <_io.TextIOWrapper mode='rw' encoding='cp936'>}
    [17:26:21]	 [showthreads,5928] [<Thread(accept, started daemon 3832)>, <Thread(show_client, started daemon 7824)>, <Thread(recv, started daemon 2112)>, <_MainThread(MainThread, started 7412)>, <Thread(showthreads, started 5928)>]
    [17:26:23]	 [show_client,7824] {('127.0.0.1', 7517): <_io.TextIOWrapper mode='rw' encoding='cp936'>}
    [17:26:23]	 [accept,3832] <socket.socket fd=436, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 9999), raddr=('127.0.0.1', 7539)>-('127.0.0.1', 7539)
    [17:26:24]	 [showthreads,5928] [<Thread(show_client, started daemon 7824)>, <Thread(recv, started daemon 2112)>, <_MainThread(MainThread, started 7412)>, <Thread(accept, started daemon 3832)>, <Thread(recv, started daemon 6748)>, <Thread(showthreads, started 5928)>]
    2017/12/24 17:26:25 127.0.0.1:7539
    [17:26:25]	 [recv,6748] 2017/12/24 17:26:25 127.0.0.1:7539
    hello2
    hello2
    
    
    
    
    [17:26:26]	 [show_client,7824] {('127.0.0.1', 7517): <_io.TextIOWrapper mode='rw' encoding='cp936'>, ('127.0.0.1', 7539): <_io.TextIOWrapper mode='rw' encoding='cp936'>}
    [17:26:27]	 [showthreads,5928] [<Thread(show_client, started daemon 7824)>, <Thread(recv, started daemon 2112)>, <_MainThread(MainThread, started 7412)>, <Thread(accept, started daemon 3832)>, <Thread(recv, started daemon 6748)>, <Thread(showthreads, started 5928)>]
    [17:26:29]	 [show_client,7824] {('127.0.0.1', 7517): <_io.TextIOWrapper mode='rw' encoding='cp936'>, ('127.0.0.1', 7539): <_io.TextIOWrapper mode='rw' encoding='cp936'>}
    [17:26:30]	 [showthreads,5928] [<Thread(show_client, started daemon 7824)>, <Thread(recv, started daemon 2112)>, <_MainThread(MainThread, started 7412)>, <Thread(accept, started daemon 3832)>, <Thread(recv, started daemon 6748)>, <Thread(showthreads, started 5928)>]
    [17:26:32]	 [show_client,7824] {('127.0.0.1', 7517): <_io.TextIOWrapper mode='rw' encoding='cp936'>, ('127.0.0.1', 7539): <_io.TextIOWrapper mode='rw' encoding='cp936'>}
    [17:26:33]	 [showthreads,5928] [<Thread(show_client, started daemon 7824)>, <Thread(recv, started daemon 2112)>, <_MainThread(MainThread, started 7412)>, <Thread(accept, started daemon 3832)>, <Thread(recv, started daemon 6748)>, <Thread(showthreads, started 5928)>]
    [17:26:35]	 [show_client,7824] {('127.0.0.1', 7517): <_io.TextIOWrapper mode='rw' encoding='cp936'>, ('127.0.0.1', 7539): <_io.TextIOWrapper mode='rw' encoding='cp936'>}
    [17:26:36]	 [showthreads,5928] [<Thread(show_client, started daemon 7824)>, <Thread(recv, started daemon 2112)>, <_MainThread(MainThread, started 7412)>, <Thread(accept, started daemon 3832)>, <Thread(recv, started daemon 6748)>, <Thread(showthreads, started 5928)>]
    

      

    #客户端1
    >>> hello1
    [17:26:19]	 [recv,2604] 2017/12/24 17:26:19 127.0.0.1:7517
    hello1
    >>> 
    
    [17:26:25]	 [recv,2604] 2017/12/24 17:26:25 127.0.0.1:7539
    hello2
    
    
    [17:26:37]	 [recv,2604] [WinError 10054] 远程主机强迫关闭了一个现有的连接。
    

      

    #客户端2
    >>> hello2
    >>> [17:26:25]	 [recv,4044] 2017/12/24 17:26:25 127.0.0.1:7539
    hello2
    
    
    [17:26:37]	 [recv,4044] [WinError 10054] 远程主机强迫关闭了一个现有的连接。
    

      

    以上例子在客户端,如果服务端主动断开,客户端需要异常处理。

  • 相关阅读:
    HttpServletRequest和HttpServletResponse
    .NET Core 通过 Ef Core 操作 Mysql
    spring-boot整合shiro实现权限管理
    spring-boot整合mongodb多数据源的案例
    spring-boot整合mybaits多数据源动态切换案例
    spring-boot整合Mybatis多数据源案例
    spring-boot整合mongodb的案例
    spring-boot和redis的缓存使用
    spring-boot 定时任务案例
    spring-cloud:熔断监控Hystrix Dashboard和Turbine的示例
  • 原文地址:https://www.cnblogs.com/i-honey/p/8098677.html
Copyright © 2011-2022 走看看