Client server communication via sockets within same file/program in Python? - python

I need to make a program that communicates within the same program back and forth between client and server, but after following the instructions on: http://woozle.org/~neale/papers/sockets.html it just keeps listening and I see nothing printed.
How do I enable basic client server functionality within the same file?
#!/usr/bin/python # This is server.py file
import socket # Import socket module
import random
import os
import time as t
#open socket
s = socket.socket() # Create a socket object
host = socket.gethostname() # Get local machine name
port = random.randint(0,65535) # Reserve a port for your service.
if os.fork() == 0:
#server
s.listen(1)
print 'about to listen'
while 1:
c = s.accept()
cli_sock, cli_addr = c
cli_sock.send("Hello to you! %s" % cli_addr)
elif os.fork() == 0:
t.sleep(1)
#client
print 'in here2'
s.bind((host, port)) # Bind to the port
s.connect((host,port))
s.send("Hello!\n")
print s.recv(8192)
s.close()

You're never going to hit your client code, as you enter an infinite loop right after starting the listener. For a toy example like this, you'll need to create 2 socket objects, one for the server and one for the client, then pingpong back and forth between them within your code; you can't use a serve forever style loop like you are here unless it runs in a parallel thread/process so you don't block execution of the main thread.

Related

Communication between 2 python script in which the first one is continuously running

I have 2 python scripts.
To make it simple
1st script :
It is a simple infinite while loop in which a variable 'x' is being increased by 1(This script is always running)
Now what I want a 2nd script, when I call this script it should give me the present value of x
I read about multiprocessing ,pipe and queue but was not able to implement it
EDIT:
I tried the socket solution and I am getting errors
Client Side
import serial
import time
from multiprocessing import Process
import sys
import socket
s=socket.socket()
port=43470
s.connect(('127.0.0.1',port))
sertx = serial.Serial('COM4', 115200)
while 1:
for i in range(4):
msg = str(i+1)
# print('sending: ',msg.encode())
msgstat = 'A' + msg
#print(msgstat)
#print(type(msgstat))
tx_t = time.time()
sertx.write(msg.encode())
tx_t=str(tx_t)
s.send(tx_t.encode())
s.close()
time.sleep(0.001)
Error - File ".\tx.py", line 23, in
s.send(tx_t.encode())
OSError: [WinError 10038] An operation was attempted on something that is not a socket
PS C:\Users\ambuj\Documents\Python Scripts>
Server
import socket
s = socket.socket()
port = 43470 # make this any random port
s.bind(('127.0.0.1', port))
s.listen(5) # put the socket into listen mode
while True:
c, addr = s.accept()
data = c.recv(1024).decode("utf-8") # This data is received from the client script
print(data)
c.close()
You can surely achieve this thing using socket communication. Just create a server script like this which will listen to any incoming data to a specific port...
import socket
s = socket.socket()
port = 43470 # make this any random port
s.bind(('127.0.0.1', port))
s.listen(5) # put the socket into listen mode
while True:
c, addr = s.accept()
data = c.recv(1024).decode("utf-8") # This data is received from the client script
c.close()
Now in your client script, you have to connect to the socket that is binded in that port. Make a client script like this...
import socket
s = socket.socket()
port = 43470 # Use the same port number here as you did in the server script.
s.connect(('127.0.0.1', port))
s.send(b"This data will be received by the server!")
s.close()
You can do the reverse as well. So the server will be able to send the data to the client script. Its a two-way communication.
Remeber: This is just a simple demonstraction to make things work. In actual case, modification is much needed.

How to fix multiprocessing echo server to handle multiple clients

I want to create a multiprocessing echo server. I am currently using telnet as my client to send messages to my echo server.Currently I can handle one telnet request and it echos the response. I initially, thought I should intialize the pid whenever I create a socket. Is that correct?
How do I allow several clients to connect to my server using multiprocessing.
#!/usr/bin/env python
import socket
import os
from multiprocessing import Process
def create_socket():
# Create socket
sockfd = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Port for socket and Host
PORT = 8002
HOST = 'localhost'
# bind the socket to host and port
sockfd.bind((HOST, PORT))
# become a server socket
sockfd.listen(5)
start_socket(sockfd)
def start_socket(sockfd):
while True:
# Establish and accept connections woth client
(clientsocket, address) = sockfd.accept()
# Get the process id.
process_id = os.getpid()
print("Process id:", process_id)
print("Got connection from", address)
# Recieve message from the client
message = clientsocket.recv(2024)
print("Server received: " + message.decode('utf-8'))
reply = ("Server output: " + message.decode('utf-8'))
if not message:
print("Client has been disconnected.....")
break
# Display messags.
clientsocket.sendall(str.encode(reply))
# Close the connection with the client
clientsocket.close()
if __name__ == '__main__':
process = Process(target = create_socket)
process.start()
It's probably a good idea to understand which are blocking system calls and which are not. listen for example is not blocking and accept is blocking one. So basically - you created one process through Process(..), that blocks at the accept and when a connection is made - handles that connection.
Your code should have a structure - something like following (pseudo code)
def handle_connection(accepted_socket):
# do whatever you want with the socket
pass
def server():
# Create socket and listen to it.
sock = socket.socket(....)
sock.bind((HOST, PORT))
sock.listen(5)
while True:
new_client = sock.accept() # blocks here.
# unblocked
client_process = Process(target=handle_connection, args=(new_client))
client_process.start()
I must also mention, while this is a good way to just understand how things can be done, it is not a good idea to start a new process for every connection.
The initial part of setting up the server, binding, listening etc (your create_socket) should be in the master process.
Once you accept and get a socket, you should spawn off a separate process to take care of that connection. In other words, your start_socket should be spawned off in a separate process and should loop forever.

Python 2.7 Socket programming ports

I had an exercise of port carousel which means that I need to build a server-client which the server asks the client for a port and then they starting to listen to the port that given, and this is the loop I got a error and I don't know how to fix it.
server:
import socket
import random
def main():
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('0.0.0.0', 1729))
server_socket.listen(1)
(client_socket, server_socket) = server_socket.accept()
done = False
while not done:
port = client_socket.recv(4096)
client_socket.send('i got the port' + port)
port = int(port)
if port != 1:
server_socket.bind(('0.0.0.0', port))
continue
else:
done = True
if __name__ == '__main__':
main()
client:
import socket
import random
def main():
print 'hi at anytime enter 1 to break the loop'
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(('127.0.0.1', 1729))
done = False
while not done:
port = client_socket.send(raw_input("enter port:"))
data = client_socket.recv(4096)
print data
port = int(port)
if port != 1:
client_socket.connect(('127.0.0.1', port))
continue
else:
done = True
client_socket.close()
if __name__ == '__main__':
main()
the error output for the server:
File "C:/Cyber/ServerFolder/ports_carrousel.py", line 18, in main
server_socket.bind(('0.0.0.0', port))
AttributeError: 'tuple' object has no attribute 'bind'
In your main function, you do the following:
(client_socket, server_socket) = server_socket.accept()
but, server_socket.accept() actually returns two objects. The first, is a socket object, and the second one is a tuple that contains (sourceIPString, sourcePort).
Thus, by using this line of code, outlined above, you are essentially overriding the server_socket by a tuple object.
Notice that later, in line 18, you are trying to access the "bind" function of a socket, but, using a reference to a tuple object, that does not implement such a function.
What you should be doing is something along the lines of
(client_socket, client_connection_info) = server_socket.accept()
and adjust your code accordingly.
Just a couple of things wrong here. First, accept returns a 2-tuple containing the newly-connected socket, and the client's address (which is itself a 2-tuple of IP address and port number). It does not return two sockets. But you're overwriting your server_socket variable with the second returned value. That doesn't make sense and it's why the interpreter is telling you that the 2-tuple has no bind attribute: it's not a socket object. The accept call should look something like this:
client_socket, client_addr = server_socket.accept()
Next, after receiving the new port number from the client, you must create a new socket (you cannot re-use the same listening socket), then bind that new socket to the new port, then listen; finally you can accept a new client connection from the new listening socket.
You should also close sockets you're finished with so that you don't continually leak file descriptors. That means each time you receive a new port number from the client, you should close the client socket, and the listening socket, then create a new listening socket (and bind and listen), then accept the new client socket.
Altogether that will mean restructuring your code in the server significantly. You need to pull the creation of a listening socket down into your main while not done loop.
Another thing to keep in mind. On the client side, immediately after sending the port number to the server, you're attempting a connect to that new port number. However, it's almost certain that your connect request will reach the server before the server has had a chance to create a new listening socket, and bind it. So your client will either need to delay a moment before attempting to connect, or it will need to have logic to retry the connect for some period of time.
EDIT:
Also, you must create a new socket on the client side too when reconnecting. Once a stream socket has been bound to a port (which also happens automatically when you connect), you can never use it to bind or connect to a different address/port.

python multithreading server

I am new to networking programming and python.
I am trying to figure out how to run different jobs at the server side.
For example, I want one function to create connections for incoming clients but in the same time I can still do some administration work from the terminal.
My code is as below but it doesn't work:
Edited: it doesn't work means it will get stuck in the init_conn() function
Like:
starting up on localhost port 8887
Thread: 0 Connected with 127.0.0.1:48080
# waiting
I am looking into SocketServer framework but don't know how that works.
from thread import *
import socket
def init_conn():
thread_count =0
# Create a TCP/IP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Bind the socket to the port
server_address = ('localhost', 8887)
print >>sys.stderr, 'starting up on %s port %s' % server_address
sock.bind(server_address)
# Listen for incoming connections
sock.listen(10)
#now keep talking with the client
while 1:
#wait to accept a connection - blocking call
conn, addr = sock.accept()
print 'Thread: '+ str(thread_count) + ' 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,))
thread_count +=1
sock.close()
def clientthread(conn):
# receive data from client and send back
def console():
print 'this is console'
option = raw_input('-v view clients')
if option == 'v':
print 'you press v'
def main():
start_new_thread( init_conn(),() )
start_new_thread( console(),() )
if __name__ == "__main__":
main()
Your problem is probably that you start the program, sometimes it prints "this is console" and then it ends.
The first bug is that you call the methods instead of passing the handle to start_new_thread. It must be:
start_new_thread( init_conn, () )
i.e. no () after the function name.
The program doesn't do much because start_new_thread() apparent starts a thread and then waits for it to stop. The documentation is pretty unclear. It's better to use the new threading module; See http://pymotw.com/2/threading/
def main():
t = threading.Thread( target=init_conn )
t.daemon = True
t.start()
console()
so the code will run until console() ends.
I suggest to split the server and the command line tool. Create a client which accepts commands from the command line and sends them to the server. That way, you can start the console from anywhere and you can keep the code for the two separate.
Seeing that you're new to python, have you tried taking a look at the threading module that comes with the standard library?
import threading
... #rest of your code
while conditions==True:
i = threading.Thread(target=init_conn)
c = threading.Thread(target=console)
i.start()
c.start()
Can't say I've done too much with networking programming with python, so I don't really have much to say in that manner, but at least this should get you started with adding multithreading to your project.
Using SocketServer you may implement a client/server system. The documentation gives small examples which may be useful for you. Here is an extended example from there:
server.py :
import SocketServer
import os
import logging
FORMAT = '[%(asctime)-15s] %(message)s'
logging.basicConfig(format=FORMAT, level=logging.DEBUG)
class MyServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
# By setting this we allow the server to re-bind to the address by
# setting SO_REUSEADDR, meaning you don't have to wait for
# timeouts when you kill the server and the sockets don't get
# closed down correctly.
allow_reuse_address = True
request_queue_size = 10
def __init__(self, port):
self.host = os.uname()[1]
self.port = port
SocketServer.TCPServer.__init__(self, (self.host,self.port), MyTCPHandler)
logging.info( "Server has been started on {h}:{p}".format(h=self.host,p=self.port) )
class MyTCPHandler(SocketServer.BaseRequestHandler):
"""
The RequestHandler class for our server.
It is instantiated once per connection to the server, and must
override the handle() method to implement communication to the
client.
"""
def handle(self):
# self.request is the TCP socket connected to the client
# max length is here 1024 chars
self.data = self.request.recv(1024).strip()
logging.info( "received: {d}".format(d=self.data) )
# here you may execute different functions according to the
# request string
# here: just send back the same data, but upper-cased
self.request.sendall(self.data.upper())
PORT = 8887
if __name__ == "__main__":
# Create the server, binding to localhost on port 8887
#server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)
server = MyServer( PORT )
# Activate the server; this will keep running until you
# interrupt the program with Ctrl-C
server.serve_forever()
client.py
import socket
import sys
import logging
FORMAT = '[%(asctime)-15s] %(message)s'
logging.basicConfig(format=FORMAT, level=logging.DEBUG)
HOST, PORT = "workstation04", 8887
logging.info( "connect to server {h}:{p}".format(h=HOST,p=PORT ) )
# read command line
data = " ".join(sys.argv[1:])
# Create a socket (SOCK_STREAM means a TCP socket)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
# Connect to server and send data
sock.connect((HOST, PORT))
sock.sendall(data + "\n")
# Receive data from the server and shut down
received = sock.recv(1024)
finally:
sock.close()
logging.info( "Sent: {}".format(data) )
logging.info( "Received: {}".format(received) )
The output looks something like:
server side:
> python server.py
[2015-05-28 11:17:49,263] Server has been started on disasterarea:8887
[2015-05-28 11:17:50,972] received: my message
client side:
[2015-05-28 11:17:50,971] connect to server disasterarea:8887
[2015-05-28 11:17:50,972] Sent: my message
[2015-05-28 11:17:50,972] Received: MY MESSAGE
You can run several clients (from different consoles) in parallel. You may implement a request processor on the server side which processes the incoming requests and executes certain functions.
Alternatively, you may use the python module ParallelPython which executes python code locally on a multicore system or on a cluster and clusters. Check the http examples.
I had to force pip to install this module:
pip install --allow-external pp --allow-unverified pp pp

How can I know the number of clients connected to the server and return the number of the connected clients to the user?

I want to know these for I am getting crazy with this:
How can I do these:
1-If the server terminates the clients should terminate also. Your server should allow the administrator to close all connections (i.e. the server must wait for the user to terminate the program preferably through a menu interface)
2-In order to know the number of clients connected you will need to identify each client uniquely – this can be accomplished by using the pid that is uniquely assigned for each client connection (store these in a global list). These connections can change dynamically (i.e. clients can disconnect and reconnect) so you must maintain this list on the server.
This is my server side code:
Thanks in advance
import _thread
import socket
import sys
from datetime import datetime
def serveclient(c):
global v, nclient, vlock, nclientlock
while(True):
k=(c.recv(1)).decode('utf-8')
if(k==''):
break
if(k=='D'):
today = str(datetime.now().strftime('%Y-%m-%d'))
c.send(today.encode('utf-8'))
if(k=='T'):
tme = str(datetime.now().strftime('%H:%M:%S'))
c.send(tme.encode('utf-8'))
if(k=='X'):
<<<< # Here I should put the number of clients connected and echo back the number like the above code
vlock.acquire()
v+=k
vlock.release()
#Echo back
c.send(v.encode('utf-8'))
c.close() #End connection
nclientlock.acquire()
nclient-=1
nclientlock.release()
#Main driver code
listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
port = int(sys.argv[1])
listener.bind(('',port))
listener.listen(5)
#Initialize global data
v=''
vlock=_thread.allocate_lock()
nclient=10 #Max number of clients
nclientlock=_thread.allocate_lock()
#accept calls from clients
for i in range(nclient):
(client, ap) = listener.accept()
_thread.start_new_thread(serveclient, (client,))
listener.close()
while nclient >0:
pass #do nothing, just wait for client count to drop to zero
print('The final string is: ', v)
<<<<<<<<<<<<<<<<<<<<<<<<<This the Client Code>>>>>>>>>>>>>>>>>>>>>>>
#Client Program. Sends a single char at a time to the server until the client
#sends a '', this will terminate the client.
#
#usage: python server port
import socket
import sys
#create the socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = sys.argv[1] #Server info from cmd line
port = int(sys.argv[2]) #Port from cmd line
#Conncet to server
s.connect((host, port))
while(True):
#get letter
k = input('enter a letter: ')
s.send(k.encode('utf-8'))
if(k==''):
break
v=s.recv(1024) #receive upto 1024 bytes
print(v.decode('utf-8'))
s.close()
Just increment a count every time you accept a socket, and decrement it every time you close an accepted socket.

Categories

Resources