python network(非常好)

                                                  转载原文请点击

关于网络编程以及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》


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值