python network(非常好)

发布时间:2019-08-28 09:20:16编辑:auto阅读(2933)

                                                      转载原文请点击

    关于网络编程以及socket 等一些概念和函数介绍就不再重复了,这里示例性用python 编写客户端和服务器端。


    一、最简单的客户端流程:

    1. Create a socket
    2. Connect to remote server
    3. Send some data
    4. Receive a reply

     Python Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    #Socket client example in python
     
    import socket   #for sockets
    import sys  #for exit
    import struct
    import time
     
    #create an INET, STREAMing socket
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    except socket.error:
        print 'Failed to create socket'
        sys.exit()
         
    print 'Socket Created'
     
    host = 'www.google.com';
    port = 80;
     
    try:
        remote_ip = socket.gethostbyname( host )
     
    except socket.gaierror:
        #could not resolve
        print 'Hostname could not be resolved. Exiting'
        sys.exit()
     
    #Connect to remote server
    s.connect((remote_ip , port))
     
    print 'Socket Connected to ' + host + ' on ip ' + remote_ip
     
    #Send some data to remote server
    message = "GET / HTTP/1.1\r\n\r\n"
     
    try :
        #Set the whole string
        s.sendall(message)
    except socket.error:
        #Send failed
        print 'Send failed'
        sys.exit()
     
    print 'Message send successfully'
     
    def recv_timeout(the_socket,timeout=2):
        #make socket non blocking
        the_socket.setblocking(0)
         
        #total data partwise in an array
        total_data=[];
        data='';
         
        #beginning time
        begin=time.time()
        while 1:
            #if you got some data, then break after timeout
            if total_data and time.time()-begin > timeout:
                break
             
            #if you got no data at all, wait a little longer, twice the timeout
            elif time.time()-begin > timeout*2:
                break
             
            #recv something
            try:
                data = the_socket.recv(8192)
                if data:
                    total_data.append(data)
                    #change the beginning time for measurement
                    begin=time.time()
                else:
                    #sleep for sometime to indicate a gap
                    time.sleep(0.1)
            except:
                pass
         
        #join all parts to make final string
        return ''.join(total_data)
     
    #get reply and print
    print recv_timeout(s)
     
    #Close the socket
    s.close()

    需要注意的是也许http 响应数据比较大,要经过多次才能完整接收,设置socket 非阻塞,设定timeout,最后join 数据;因为我们并不知道具体数据到底多大,故不能这样使用 data. s.recv(4096 , socket.MSG_WAITALL); 如果最后一次来的数据不够4096,那么将一直阻塞。输出如下:



    二、最简单的服务器端流程:

    1. Open a socket
    2. Bind to a address(and port).
    3. Listen for incoming connections.
    4. Accept connections
    5. Read/Send

     Python Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    import socket
    import sys
     
    HOST = ''   # Symbolic name meaning all available interfaces
    PORT = 8888 # Arbitrary non-privileged port
     
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    print 'Socket created'
     
    try:
        s.bind((HOST, PORT))
    except socket.error , msg:
        print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
        sys.exit()
         
    print 'Socket bind complete'
     
    s.listen(10)
    print 'Socket now listening'
     
    #now keep talking with the client
    while 1:
        #wait to accept a connection - blocking call
        conn, addr = s.accept()
        print 'Connected with ' + addr[0] + ':' + str(addr[1])
         
        data = conn.recv(1024)
        reply = 'OK...' + data
        if not data: 
            break
         
        conn.sendall(reply)
     
    conn.close()
    s.close()

    三、上述程序的缺点是每个连接上来就回应一次就不再搭理了,显然不可取,用多线程改进如下:

     Python Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    import socket
    import sys
    from thread import *
     
    HOST = ''   # Symbolic name meaning all available interfaces
    PORT = 8888 # Arbitrary non-privileged port
     
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    print 'Socket created'
     
    #Bind socket to local host and port
    try:
        s.bind((HOST, PORT))
    except socket.error , msg:
        print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
        sys.exit()
         
    print 'Socket bind complete'
     
    #Start listening on socket
    s.listen(10)
    print 'Socket now listening'
     
    #Function for handling connections. This will be used to create threads
    def clientthread(conn):
        #Sending message to connected client
        conn.send('Welcome to the server. Type something and hit enter\n'#send only takes string
         
        #infinite loop so that function do not terminate and thread do not end.
        while True:
             
            #Receiving from client
            data = conn.recv(1024)
            reply = 'OK...' + data
            if not data: 
                break
         
            conn.sendall(reply)
         
        #came out of loop
        conn.close()
     
    #now keep talking with the client
    while 1:
        #wait to accept a connection - blocking call
        conn, addr = s.accept()
        print 'Connected with ' + addr[0] + ':' + str(addr[1])
         
        #start new thread takes 1st argument as a function name to be run, second is the tuple of arguments to the function.
        start_new_thread(clientthread ,(conn,))
     
    s.close()

    即每accept 返回一个连接,就创建一个线程对其服务。

    启动server,然后开两个窗口telnet 上去,如下:




    四、接下来,我们再用select 来实现,函数原型如下:

    read_sockets,write_sockets,error_sockets = select(read_fds , write_fds, except_fds [, timeout]);

     Python Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    #Socket server in python using select function

    import socket, select

    #Function to broadcast chat messages to all connected clients
    def broadcast_data(sock, message):
        #Do not send the message to master socket and the client who has send us the message
        for socket in CONNECTION_LIST:
            if socket != server_socket and socket != sock:
                try:
                    socket.send(message)
                except:
                    #broken socket connection may be, chat client pressed ctrl+c for example
                    socket.close()
                    CONNECTION_LIST.remove(socket)


    if __name__ == "__main__":

        CONNECTION_LIST = [] #list of socket clients 
        RECV_BUFFER = 4096 #Advisable to keep it as an exponent of 2
        PORT = 5000

        server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        #this has no effect, why?
        server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        server_socket.bind(("0.0.0.0", PORT))
        server_socket.listen(10)

        #Add server socket to the list of readable connections
        CONNECTION_LIST.append(server_socket)

        print "Chat server started on port " + str(PORT)

        while 1:
            #Get the list sockets which are ready to be read through select
            read_sockets, write_sockets, error_sockets = select.select(CONNECTION_LIST, [], [])

            for sock in read_sockets:
                #New connection
                if sock == server_socket:
                    #handle the case in which there is a new connection recieved through server_socket
                    sockfd, addr = server_socket.accept()
                    CONNECTION_LIST.append(sockfd)
                    print "Client (%s, %s) connected" % addr
                
                #Some incoming message from a client
                else:
                    #Data recieved from client, process it
                    try:
                        #In windows, sometimes when a Tcp program closes abruptly
                        #a "Connection reset by peer" exception will be thrown
                        data = sock.recv(RECV_BUFFER)
                        #echo back the client message
                        if data:
                            sock.send('Ok...' + data)
                    
                    #client disconnected, so remove from socket list
                    except:
                        broadcast_data(sock, "Client (%s, %s) is offline" % addr)
                        print "Client (%s, %s) is offline" % addr
                        sock.close()
                        CONNECTION_LIST.remove(sock)
                        continue

        server_socket.close()

    五、最后使用poll 来实现,如下:

    launcelot.py

     Python Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    #!/usr/bin/env python
    #coding=utf-8
    #Constants and routines for supporting a certain network conversation.
    import sys, socket
    PORT = 1060
    qa = (('What is your name?''My name is Sir Launcelot of Camelot.'),
            ('What is your quest?''To seek the Holy Grail.'),
            ('What is your favorite color?''Blue.'))
    qadict = dict(qa)
    def recv_until(sock, suffix):
        message = ''
        while not message.endswith(suffix):
            data = sock.recv(4096)
            if not data:
                raise EOFError('socket closed before we saw %r' % suffix)
            message += data
        return message
    def setup():
        if len(sys.argv) != 2:
            print >>sys.stderr, 'usage: %s interface' % sys.argv[0]
            exit(2)
        interface = sys.argv[1]
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        sock.bind((interface, PORT))
        sock.listen(128)
        print 'Ready and listening at %r port %d' % (interface, PORT)
        return sock


    poll_server.py

     Python Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    # An event-driven approach to serving several clients with poll().
    import launcelot
    import select

    listen_sock = launcelot.setup()
    sockets = {listen_sock.fileno():listen_sock}
    requests = {}
    responses = {}

    poll = select.poll()
    poll.register(listen_sock, select.POLLIN)

    while True:
        for fd, event in poll.poll():
            sock = sockets[fd]
            #Removed closed sockets from our list.
            if event & (select.POLLHUP | select.POLLERR | select.POLLNVAL):
                poll.unregister(fd)
                del sockets[fd]
                requests.pop(sock, None)
                responses.pop(sock, None)
            
            #Accept connections from new sockets.
            elif sock is listen_sock:
                newsock, sockname = sock.accept()
                newsock.setblocking(False)
                fd = newsock.fileno()
                sockets[fd] = newsock
                poll.register(fd, select.POLLIN)
                requests[newsock] = ''
            
            #Collect incoming data until it forms a question.
            elif event & select.POLLIN:
                data = sock.recv(4096)
                if not data: #end of file
                    sock.close()    # make POLLNVAL happen next time
                    continue
                requests[sock] += data.replace('\r\n''')
                if '?' in requests[sock]:
                    question = requests.pop(sock)
                    answer = dict(launcelot.qa)[question]
                    poll.modify(sock, select.POLLOUT)
                    responses[sock] = answer

            
            #Send out pieces of each reply until they are all sent
            elif event & select.POLLOUT:
                response = responses.pop(sock)
                n = sock.send(response)
                if n < len(response):
                    responses[sock] = response[n:]
                else:
                    poll.modify(sock, select.POLLIN)
                    requests[sock] = ''
        


    客户端需要发送launcelot.qa 其中一个问题,然后server 索引到答案发回给客户端。


    参考:

    http://www.binarytides.com/

    《Foundations of Python Network Programming》


关键字

上一篇: python+opencv处理视频

下一篇: Python SOAP 调用