Hunter的大杂烩 技术学习笔记

March 18, 2020

Python 2.7下的非阻塞tcp client实现

Filed under: 技术话题 — hunter @ 5:05 pm

因为要实现一个简单的网络服务性能测试工具,需要衡量TCP CONNECT环节耗时,发现目前网上对于python 2下的非阻塞connect/send/recv介绍很少,于是自己实现了一个

参考:

https://docs.python.org/2/howto/sockets.html#sockets

https://docs.python.org/2/howto/sockets.html#non-blocking-sockets

https://learnku.com/docs/pymotw/select-wait-for-io-efficiently/3429

https://stackoverflow.com/questions/8277970/what-are-possible-reason-for-socket-error-einprogress-in-solaris

https://www.cnblogs.com/MnCu8261/p/6403340.html

https://gist.github.com/hduffddybz/daa4c931f6ea0bd7ed93


# -*- coding: utf-8 -*
"""
    CopyLeft!2020 by hunter
    转载请保留此文件头
    用途:
        异步tcp client,基于python 2.7
"""

import socket, select
import errno


class TCPClient(object):
    def __init__(self, host, port,  handler=None):
        self.host = host
        self.port = port
        self.handler = handler
        self.sock_server = None

    def connect(self, timeout):
        try:
            self.sock_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.sock_server.setblocking(False)
            err_code = self.sock_server.connect_ex((self.host, self.port))
            if err_code != errno.EINPROGRESS and err_code != errno.EWOULDBLOCK:
                print errno
                return False
            if err_code == 0:
                return True

            inputs = [self.sock_server]
            while True:
                infds, outfds, errfds = select.select(inputs, inputs, inputs, timeout)
                #timeout
                if len(infds) == 0 and len(outfds) == 0 and len(errfds) == 0:
                    return False
                if len(errfds) != 0:
                    return False
                if len(infds) != 0:
                    break
                if len(outfds) != 0:
                    break

            return True
        except Exception as e:
            print('Connect Error. %s' % e)
            return False

    def stop(self):
        if self.sock_server is not None:
            self.sock_server.close()

    def send(self, msg, timeout):
        try:
            outputs = [self.sock_server]
            total_sent = 0
            msg_len = len(msg)
            while total_sent < msg_len:
                infds, outfds, errfds = select.select([], outputs, outputs, timeout)
                #timeout
                if len(infds) == 0 and len(outfds) == 0 and len(errfds) == 0:
                    raise RuntimeError("timeout.")
                if len(outfds) != 0:
                    sent = self.sock_server.send(msg[total_sent:])
                    if sent == 0:
                        raise RuntimeError("socket connection broken")
                    total_sent = total_sent + sent
                if len(errfds) != 0:
                    raise RuntimeError("send exception.")
            return True
        except Exception as e:
            print('Send Error. %s' % e)
            return False

    def receive(self, pkg_max_len, timeout):
        try:
            chunks = []
            bytes_recd = 0
            inputs = [self.sock_server]
            while bytes_recd < pkg_max_len:
                infds, outfds, errfds = select.select(inputs, [], inputs, timeout)
                #timeout
                if len(infds) == 0 and len(outfds) == 0 and len(errfds) == 0:
                    raise RuntimeError("timeout.")
                if len(infds) > 0:
                    chunk = self.sock_server.recv(min(pkg_max_len - bytes_recd, 2048))
                    if chunk == '':
                        raise RuntimeError("socket connection broken")
                    chunks.append(chunk)
                    bytes_recd = bytes_recd + len(chunk)
                if len(errfds) != 0:
                    raise RuntimeError("send exception.")
            return ''.join(chunks)
        except Exception as e:
            print('Recv Error. %s' % e)
            return None

No Comments

No comments yet.

RSS feed for comments on this post.

Sorry, the comment form is closed at this time.

Powered by WordPress