python network programming tutorial
關於網路程式設計以及socket 等一些概念和函式介紹就不再重複了,這裡示例性用python 編寫客戶端和伺服器端。
一、最簡單的客戶端流程:
1. Create a socket
2. Connect to remote server
3. Send some data
4. Receive a reply
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 資料;因為我們並不知道具體資料到底多大,故不能這樣使用 datasock.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
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() |
三、上述程式的缺點是每個連線上來就回應一次就不再搭理了,顯然不可取,用多執行緒改進如下:
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]);
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
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
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 索引到答案發回給客戶端。
參考:
《Foundations of Python Network Programming》
相關文章
- ch21_network_programming
- java-string-tutorial-and-examples-beginners-programmingJava
- CSAPP英語學習系列:Chapter 11: Network ProgrammingAPPAPT
- Python Socket ProgrammingPython
- Python OpenCV Tutorial Introduction影象處理教程PythonOpenCV
- Python3.4 Tutorial9 - Classes (Part 3)Python
- Python3.4 Tutorial9 - Classes (Part 4)Python
- Python3.4 Tutorial9 - Classes (Part 2)Python
- Python3.4 Tutorial9 - Classes (Part 1)Python
- DATA 2100 Major Python ProgrammingPython
- JavaScript TutorialJavaScript
- Programming Computer Vision with Python Test 1Python
- Python3.4 Tutorial10 - Brief Tour of the Standard LibraryPython
- simvison tutorial pdf
- Batch Scripting TutorialBAT
- RabbitMQ tutorial - "Hello world!"MQ
- Python3.4 Tutorial11 - Brief Tour of the Standard Library – Part IIPython
- Programming Computer Vision with Python (學習筆記四)Python筆記
- [譯]A Simple CSS Animation TutorialCSS
- Entity Framework Tutorial Basics(30):Framework
- The Go Programming LanguageGo
- Lubuntu Setup for ProgrammingUbuntu
- Extreme Programming (轉)REM
- the java programming languageJava
- Tutorial: Create SQL Cluster(FCI) on RHELSQL
- 《React官方文件》之教程TutorialReact
- Educational Codeforces Round 1 Tutorial
- Pymongo Tutorial & Pymongo入門教Go
- Microsoft Agent Tutorial Chapter 1 (轉)ROSAPT
- Microsoft Agent Tutorial Chapter 2 (轉)ROSAPT
- oracle networkOracle
- "reactive programming"的概念React
- oracle pl/sql programmingOracleSQL
- CS 551 Systems Programming
- Programming languages Domain summaryAI
- linux symbolic link attack tutorialLinuxSymbol
- Tutorial: Add a node to SQL cluster on RHELSQL
- Entity Framework Tutorial Basics(32):Enum SupportFramework