Network Programming - Server & Client B : File Transfer
In this chapter, we're going to extend Python Network Programming I - Basic Server / Client A, and try to file transfer from a server to numerous clients. The main purpose is to check the performance of the server from which clients download files.
Here is the code to send a file from a local server to a local client.
# server.py import socket # Import socket module port = 60000 # Reserve a port for your service. s = socket.socket() # Create a socket object host = socket.gethostname() # Get local machine name s.bind((host, port)) # Bind to the port s.listen(5) # Now wait for client connection. print 'Server listening....' while True: conn, addr = s.accept() # Establish connection with client. print 'Got connection from', addr data = conn.recv(1024) print('Server received', repr(data)) filename='mytext.txt' f = open(filename,'rb') l = f.read(1024) while (l): conn.send(l) print('Sent ',repr(l)) l = f.read(1024) f.close() print('Done sending') conn.send('Thank you for connecting') conn.close() # client.py import socket # Import socket module s = socket.socket() # Create a socket object host = socket.gethostname() # Get local machine name port = 60000 # Reserve a port for your service. s.connect((host, port)) s.send("Hello server!") with open('received_file', 'wb') as f: print 'file opened' while True: print('receiving data...') data = s.recv(1024) print('data=%s', (data)) if not data: break # write data to a file f.write(data) f.close() print('Successfully get the file') s.close() print('connection closed')
Output on a local server:
Server listening.... Got connection from ('192.168.56.10', 62854) ('Server received', "'Hello server!'") ('Sent ', "'1 1234567890\\n ... ('Sent ', "'4567890\\n105 ... ('Sent ', "'300 1234567890\\n'") Done sending
Output on a local client:
file opened receiving data... data=1 1234567890 2 1234567890 ... 103 1234567890 104 123 receiving data... data=4567890 105 1234567890 106 1234567890 ... 299 1234567890 receiving data... data=300 1234567890 Thank you for connecting receiving data... data= Successfully get the file connection closed
Our server code above can only interact with one client. If we try to connect with a second client, however, it simply won't reply to the new client. To let the server interact with multiple clients, we need to use multi-threading. Here is the new server script to accept multiple client connections:
# server2.py import socket from threading import Thread from SocketServer import ThreadingMixIn TCP_IP = 'localhost' TCP_PORT = 9001 BUFFER_SIZE = 1024 class ClientThread(Thread): def __init__(self,ip,port,sock): Thread.__init__(self) self.ip = ip self.port = port self.sock = sock print " New thread started for "+ip+":"+str(port) def run(self): filename='mytext.txt' f = open(filename,'rb') while True: l = f.read(BUFFER_SIZE) while (l): self.sock.send(l) #print('Sent ',repr(l)) l = f.read(BUFFER_SIZE) if not l: f.close() self.sock.close() break tcpsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) tcpsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) tcpsock.bind((TCP_IP, TCP_PORT)) threads = [] while True: tcpsock.listen(5) print "Waiting for incoming connections..." (conn, (ip,port)) = tcpsock.accept() print 'Got connection from ', (ip,port) newthread = ClientThread(ip,port,conn) newthread.start() threads.append(newthread) for t in threads: t.join() # client2.py #!/usr/bin/env python import socket TCP_IP = 'localhost' TCP_PORT = 9001 BUFFER_SIZE = 1024 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((TCP_IP, TCP_PORT)) with open('received_file', 'wb') as f: print 'file opened' while True: #print('receiving data...') data = s.recv(BUFFER_SIZE) print('data=%s', (data)) if not data: f.close() print 'file close()' break # write data to a file f.write(data) print('Successfully get the file') s.close() print('connection closed')
Below is the output from the server console when we run two clients simultaneously:
$ python server2.py Waiting for incoming connections... Got connection from ('127.0.0.1', 55184) New thread started for 127.0.0.1:55184 Waiting for incoming connections... Got connection from ('127.0.0.1', 55185) New thread started for 127.0.0.1:55185 Waiting for incoming connections...
In the following codes, we made two changes:
- ip switched to amazon ec2 ip
- To calculate the time to take download a file, we import time module.
# server3.py on EC2 instance import socket from threading import Thread from SocketServer import ThreadingMixIn # TCP_IP = 'localhost' TCP_IP = socket.gethostbyaddr("your-ec2-public_ip")[0] TCP_PORT = 60001 BUFFER_SIZE = 1024 print 'TCP_IP=',TCP_IP print 'TCP_PORT=',TCP_PORT class ClientThread(Thread): def __init__(self,ip,port,sock): Thread.__init__(self) self.ip = ip self.port = port self.sock = sock print " New thread started for "+ip+":"+str(port) def run(self): filename='mytext.txt' f = open(filename,'rb') while True: l = f.read(BUFFER_SIZE) while (l): self.sock.send(l) #print('Sent ',repr(l)) l = f.read(BUFFER_SIZE) if not l: f.close() self.sock.close() break tcpsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) tcpsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) tcpsock.bind((TCP_IP, TCP_PORT)) threads = [] while True: tcpsock.listen(5) print "Waiting for incoming connections..." (conn, (ip,port)) = tcpsock.accept() print 'Got connection from ', (ip,port) newthread = ClientThread(ip,port,conn) newthread.start() threads.append(newthread) for t in threads: t.join() # client3.py on local machine #!/usr/bin/env python #!/usr/bin/env python import socket import time #TCP_IP = 'localhost' TCP_IP = 'ip-ec2-instance' TCP_PORT = 60001 BUFFER_SIZE = 1024 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((TCP_IP, TCP_PORT)) clock_start = time.clock() time_start = time.time() with open('received_file', 'wb') as f: print 'file opened' while True: #print('receiving data...') data = s.recv(1024) #print('data=%s', (data)) if not data: f.close() print 'file close()' break # write data to a file f.write(data) print('Successfully get the file') s.close() print('connection closed') clock_end = time.clock() time_end = time.time() duration_clock = clock_end - clock_start print 'clock: start = ',clock_start, ' end = ',clock_end print 'clock: duration_clock = ', duration_clock duration_time = time_end - time_start print 'time: start = ',time_start, ' end = ',time_end print 'time: duration_time = ', duration_time
Server console shows the following output after a connection from my local home machine:
$ python server3.py TCP_IP= ec2-... TCP_PORT= 60001 Waiting for incoming connections... Got connection from ('108.239.135.40', 56742) New thread started for 108.239.135.40:56742
The ip is isp's:
On my local mac:
$ python client3.py file opened file close() Successfully get the file connection closed clock: start = 0.018806 end = 0.038608 clock: duration_clock = 0.019802 time: start = 1434991840.37 end = 1434991840.42 time: duration_time = 0.0457620620728
File downloaded from EC2, received_file is simple, and it looks like this:
From EC2 1 2 3 4 5 6 7 8 9
Here is the output showing the wall-clock time depending on the number of concurrent connections:
Our server is located in California, and the following picture compares the download speed between US and Japan:
Python Network Programming
Network Programming - Server & Client A : Basics
Network Programming - Server & Client B : File Transfer
Network Programming II - Chat Server & Client
Network Programming III - SocketServer
Network Programming IV - SocketServer Asynchronous request
Python tutorial
Python Home
Introduction
Running Python Programs (os, sys, import)
Modules and IDLE (Import, Reload, exec)
Object Types - Numbers, Strings, and None
Strings - Escape Sequence, Raw String, and Slicing
Strings - Methods
Formatting Strings - expressions and method calls
Files and os.path
Traversing directories recursively
Subprocess Module
Regular Expressions with Python
Regular Expressions Cheat Sheet
Object Types - Lists
Object Types - Dictionaries and Tuples
Functions def, *args, **kargs
Functions lambda
Built-in Functions
map, filter, and reduce
Decorators
List Comprehension
Sets (union/intersection) and itertools - Jaccard coefficient and shingling to check plagiarism
Hashing (Hash tables and hashlib)
Dictionary Comprehension with zip
The yield keyword
Generator Functions and Expressions
generator.send() method
Iterators
Classes and Instances (__init__, __call__, etc.)
if__name__ == '__main__'
argparse
Exceptions
@static method vs class method
Private attributes and private methods
bits, bytes, bitstring, and constBitStream
json.dump(s) and json.load(s)
Python Object Serialization - pickle and json
Python Object Serialization - yaml and json
Priority queue and heap queue data structure
Graph data structure
Dijkstra's shortest path algorithm
Prim's spanning tree algorithm
Closure
Functional programming in Python
Remote running a local file using ssh
SQLite 3 - A. Connecting to DB, create/drop table, and insert data into a table
SQLite 3 - B. Selecting, updating and deleting data
MongoDB with PyMongo I - Installing MongoDB ...
Python HTTP Web Services - urllib, httplib2
Web scraping with Selenium for checking domain availability
REST API : Http Requests for Humans with Flask
Blog app with Tornado
Multithreading ...
Python Network Programming I - Basic Server / Client : A Basics
Python Network Programming I - Basic Server / Client : B File Transfer
Python Network Programming II - Chat Server / Client
Python Network Programming III - Echo Server using socketserver network framework
Python Network Programming IV - Asynchronous Request Handling : ThreadingMixIn and ForkingMixIn
Python Coding Questions I
Python Coding Questions II
Python Coding Questions III
Python Coding Questions IV
Python Coding Questions V
Python Coding Questions VI
Python Coding Questions VII
Python Coding Questions VIII
Python Coding Questions IX
Python Coding Questions X
Image processing with Python image library Pillow
Python and C++ with SIP
PyDev with Eclipse
Matplotlib
Redis with Python
NumPy array basics A
NumPy Matrix and Linear Algebra
Pandas with NumPy and Matplotlib
Celluar Automata
Batch gradient descent algorithm
Longest Common Substring Algorithm
Python Unit Test - TDD using unittest.TestCase class
Simple tool - Google page ranking by keywords
Google App Hello World
Google App webapp2 and WSGI
Uploading Google App Hello World
Python 2 vs Python 3
virtualenv and virtualenvwrapper
Uploading a big file to AWS S3 using boto module
Scheduled stopping and starting an AWS instance
Cloudera CDH5 - Scheduled stopping and starting services
Removing Cloud Files - Rackspace API with curl and subprocess
Checking if a process is running/hanging and stop/run a scheduled task on Windows
Apache Spark 1.3 with PySpark (Spark Python API) Shell
Apache Spark 1.2 Streaming
bottle 0.12.7 - Fast and simple WSGI-micro framework for small web-applications ...
Flask app with Apache WSGI on Ubuntu14/CentOS7 ...
Fabric - streamlining the use of SSH for application deployment
Ansible Quick Preview - Setting up web servers with Nginx, configure enviroments, and deploy an App
Neural Networks with backpropagation for XOR using one hidden layer
NLP - NLTK (Natural Language Toolkit) ...
RabbitMQ(Message broker server) and Celery(Task queue) ...
OpenCV3 and Matplotlib ...
Simple tool - Concatenating slides using FFmpeg ...
iPython - Signal Processing with NumPy
iPython and Jupyter - Install Jupyter, iPython Notebook, drawing with Matplotlib, and publishing it to Github
iPython and Jupyter Notebook with Embedded D3.js
Downloading YouTube videos using youtube-dl embedded with Python
Machine Learning : scikit-learn ...
Django 1.6/1.8 Web Framework ...
Ph.D. / Golden Gate Ave, San Francisco / Seoul National Univ / Carnegie Mellon / UC Berkeley / DevOps / Deep Learning / Visualization