Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 036e436

Browse files
committed
tcp服务
1 parent 625b4d1 commit 036e436

File tree

3 files changed

+196
-0
lines changed

3 files changed

+196
-0
lines changed

pytcp/__init__.py

Whitespace-only changes.

pytcp/multithreadedClient.py

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
#!/usr/bin/env python
2+
"""
3+
Multi-threaded TCP Client
4+
multithreadedClient.py is a TCP client that maintains a maximum number of worker threads which continuously send a given
5+
number of requests to multithreadedServer.py and print the server's response.
6+
This is derived from an assignment for the Distributed Systems class at Bennington College
7+
"""
8+
9+
from argparse import ArgumentParser
10+
from queue import Queue
11+
from socket import SO_REUSEADDR, SOCK_STREAM, error, socket, SOL_SOCKET, AF_INET
12+
from threading import Thread
13+
14+
# -------------------------------------#
15+
########## ARGUMENT HANDLING ##########
16+
# -------------------------------------#
17+
18+
# Initialize instance of an argument parser
19+
parser = ArgumentParser(description='Multi-threaded TCP Client')
20+
21+
# Add optional arguments, with given default values if user gives no args
22+
parser.add_argument('-r', '--requests', default=10, type=int, help='Total number of requests to send to server')
23+
parser.add_argument('-w', '--workerThreads', default=5, type=int, help='Max number of worker threads to be created')
24+
parser.add_argument('-i', '--ip', default='127.0.0.1', help='IP address to connect over')
25+
parser.add_argument('-p', '--port', default=9000, type=int, help='Port over which to connect')
26+
27+
# Get the arguments
28+
args = parser.parse_args()
29+
30+
31+
# --------------------------------------#
32+
########## CLIENT CONSTRUCTOR ##########
33+
# --------------------------------------#
34+
35+
36+
class Client:
37+
def __init__(self, id, address, port, message):
38+
self.s = socket(AF_INET, SOCK_STREAM)
39+
self.id = id
40+
self.address = address
41+
self.port = port
42+
self.message = message
43+
44+
def run(self):
45+
try:
46+
# Timeout if the no connection can be made in 5 seconds
47+
self.s.settimeout(5)
48+
# Allow socket address reuse
49+
self.s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
50+
# Connect to the ip over the given port
51+
self.s.connect((self.address, self.port))
52+
# Send the defined request message
53+
self.s.send(self.message)
54+
# Wait to receive data back from server
55+
data = self.s.recv(1024)
56+
# Notify that data has been received
57+
print
58+
self.id, ": received: ", data
59+
# CLOSE THE SOCKET
60+
self.s.close()
61+
# If something went wrong, notify the user
62+
except error as e:
63+
print
64+
"\nERROR: Could not connect to ", self.address, " over port", self.port, "\n"
65+
raise e
66+
67+
68+
# ------------------------------------------------#
69+
########## DEFINE QUEUE WORKER FUNCTION ##########
70+
# ------------------------------------------------#
71+
72+
# Create a queue to hold the tasks for the worker threads
73+
q = Queue(maxsize=0)
74+
75+
76+
# Function which generates a Client instance, getting the work item to be processed from the queue
77+
def worker():
78+
message = "HELO"
79+
80+
while True:
81+
# Get the task from teh work queue
82+
item = q.get()
83+
84+
new_client = Client(item, args.ip, args.port, message)
85+
new_client.run()
86+
# Mark this task item done, thus removing it from the work queue
87+
q.task_done()
88+
89+
90+
# --------------------------------------------------#
91+
########## INITIATE CLIENT WORKER THREADS ##########
92+
# --------------------------------------------------#
93+
94+
# Populate the work queue with a list of numbers as long as the total number of requests wished to be sent.
95+
# These queue items can be thought of as decrementing counters for the client thread workers.
96+
for item in range(args.requests):
97+
q.put(item)
98+
99+
# Create a number of threads, given by the maxWorkerThread variable, to initiate clients and begin sending requests.
100+
for i in range(args.workerThreads):
101+
t = Thread(target=worker)
102+
t.daemon = True
103+
t.start()
104+
105+
# Do not exit the main thread until the sub-threads complete their work queue
106+
q.join()

pytcp/multithreadedServer.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
#!/usr/bin/env python
2+
"""
3+
Multi-threaded TCP Server
4+
multithreadedServer.py acts as a standard TCP server, with multi-threaded integration, spawning a new thread for each
5+
client request it receives.
6+
This is derived from an assignment for the Distributed Systems class at Bennington College
7+
"""
8+
9+
from argparse import ArgumentParser
10+
from socket import SO_REUSEADDR, SOCK_STREAM, socket, SOL_SOCKET, AF_INET
11+
from threading import Lock, Thread
12+
13+
# ---------------------------------------#
14+
########## USER INPUT HANDLING ##########
15+
# ---------------------------------------#
16+
17+
# Initialize instance of an argument parser
18+
parser = ArgumentParser(description='Multi-threaded TCP Server')
19+
20+
# Add optional argument, with given default values if user gives no arg
21+
parser.add_argument('-p', '--port', default=9000, type=int, help='Port over which to connect')
22+
23+
# Get the arguments
24+
args = parser.parse_args()
25+
26+
# -------------------------------------------#
27+
########## DEFINE GLOBAL VARIABLES ##########
28+
# -------------------------------------------#
29+
30+
counter = 0
31+
response_message = "Now serving, number: "
32+
thread_lock = Lock()
33+
34+
# Create a server TCP socket and allow address re-use
35+
s = socket(AF_INET, SOCK_STREAM)
36+
s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
37+
s.bind(('localhost', args.port))
38+
39+
# Create a list in which threads will be stored in order to be joined later
40+
threads = []
41+
42+
43+
# ---------------------------------------------------------#
44+
########## THREADED CLIENT HANDLER CONSTRUCTION ###########
45+
# ---------------------------------------------------------#
46+
47+
48+
class ClientHandler(Thread):
49+
def __init__(self, address, port, socket, response_message, lock):
50+
Thread.__init__(self)
51+
self.address = address
52+
self.port = port
53+
self.socket = socket
54+
self.response_message = response_message
55+
self.lock = lock
56+
57+
# Define the actions the thread will execute when called.
58+
def run(self):
59+
global counter
60+
self.socket.send(self.response_message + str(counter))
61+
# Lock the changing of the shared counter value to prevent erratic multithread changing behavior
62+
with self.lock:
63+
counter += 1
64+
self.socket.close()
65+
66+
67+
# -----------------------------------------------#
68+
########## MAIN-THREAD SERVER INSTANCE ##########
69+
# -----------------------------------------------#
70+
71+
# Continuously listen for a client request and spawn a new thread to handle every request
72+
while 1:
73+
74+
try:
75+
# Listen for a request
76+
s.listen(1)
77+
# Accept the request
78+
sock, addr = s.accept()
79+
# Spawn a new thread for the given request
80+
newThread = ClientHandler(addr[0], addr[1], sock, response_message, thread_lock)
81+
newThread.start()
82+
threads.append(newThread)
83+
except KeyboardInterrupt:
84+
print
85+
"\nExiting Server\n"
86+
break
87+
88+
# When server ends gracefully (through user keyboard interrupt), wait until remaining threads finish
89+
for item in threads:
90+
item.join()

0 commit comments

Comments
 (0)