• python network programming tutorial


    关于网络编程以及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 "
     
    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 '#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( ' ''')
                 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函数
    Python的集合框架
    go的相关用法
    如何完整反编译AndroidMainfest.xml
    英语中时间的表达方法
    3. vue脚手架安装 express 框架使用 vue框架 weiUI
    2. TypeScript笔记
    基于SignalR的消息推送与二维码描登录实现
    MVC-Model数据注解(三)-Remote验证的一个注意事项
    MVC Remote属性验证
  • 原文地址:https://www.cnblogs.com/pangblog/p/3357987.html
Copyright © 2020-2023  润新知