I'm new to Python programming and I'm trying to create a server and a client. I still want to be able to type something from the keyboard so i can close the server from the server by typing 'exit'. I've taken samples codes from various sites to get to where I'm at in socket programming and this code.
However, whenever I run the code I get the following error message:
The host name of this machine is 127.0.0.1
The IP address of the host is 127.0.0.1
Server now awaiting client connection on port 2836
im right before the select
Traceback (most recent call last):
File "/root/Server_2.py", line 42, in <module>
inputready, outputready, exceptready = select.select(input, [], [])
TypeError: argument must be an int, or have a fileno() method.
>>>
I was reading around that to get passed this (in Windows) is to remove the sys.stdin because Windows only accepts sockets. I'm trying to write this code in Linux. I've tried all sorts of things to try to get it to work and I'm all out of resources and ideas to try. Below is the server code:
import socket #import socket module
import select
import sys
host = "127.0.0.1"
print ("The host name of this machine is " + host)
hostIP = socket.gethostbyname(host) # get host IP address
print ("The IP address of the host is %s" % (hostIP))
port = 2836 # Reserve the port for the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((hostIP, port)) # This server to a port
s.listen(4) # Now wait for client connection
print("Server now awaiting client connection on port %s" % (port))
#WINDOWS ONLY ACCEPTS SOCKETS FOR SELECT(), no standard in
input = [s, sys.stdin]
running = 1
while running:
print("im right before the select")
# when there's something in input, then we move forward
# ignore what's in output and except because there's nothing
# when it comes to sockets
inputready, outputready, exceptready = select.select(input, [], [])
print("i'm here na")
# check who made a response
for x in inputready:
if x == s:
print(s)
#handle the server socket
client, address = s.accept()
print("connection comming in")
input.append(client)
elif x == sys.stdin:
# handle standard input
stuff = sys.stdin.readline()
if stuff == "exit":
running = 0
else:
print("you typed %s" % (stuff))
else:
#handle all other sockets
data = x.recv(1024)
print("i received " + data)
if data:
if data == "exit":
x.close()
input.remove(x)
running = 0
else:
x.send(data)
print("I am sending %s" % (data))
else:
x.close()
input.remove(x)
s.close()
Any help or ideas would be greatly appreciated. Thanks!!
Well I know you asked this 7 years ago, but I had similar questions so I would figure I answer you. I'm still working and bugfixing a program that has the same functionality, but one thing I do know is that the lists that are the arguments in select.select() need to be file descriptors (ints).
So if you have this block
input = [s, sys.stdin]
running = 1
while running:
print("im right before the select")
# when there's something in input, then we move forward
# ignore what's in output and except because there's nothing
# when it comes to sockets
inputready, outputready, exceptready = select.select(input, [], [])
The first thing I'd say is change your read list to not be input. You'll likely get some clashing with the input() function, which may cause confusing bugs. After that, you want the values to be file descriptors. So that first line should be
inputSockets = [s.fileno(), sys.stdin.fileno()]
Then when checking which socket is ready to ready, you would want to do it like this
for x in inputready:
if x == s.fileno():
# Read from your s socket
elif x == sys.stdin().fileno():
# Read from stdin
else:
'''
Here you would want to read from any other sockets you have.
The only problem is your inputSockets array has ints, not socket
objects. What I did was store an array of actual socket objects
alongside the array of file descriptors. Then I looped through the
list of sockets and found which socket's .fileno() matched x. You could
probably be clever and use a dict() with the filenos as key and socket as
value
'''
I just came across this while writing a unix domain socket (UDS) interface. The server socket id is used to accept incoming client connections. That is pretty much all it does. Once the client is accepted, reading uses its own file descriptor. Something like this works:
conn = None
inputReady, Null, Null = select.select(inputSockets, [], [])
for x in inputReady:
if x == s.fileno():
# accept incoming connect and add to poll list
conn, addr = s.accept()
inputReady.append(conn.fileno())
elif x = sys.stdin.fileno():
# read whole line and remove newline
cmd = sys.stdin.readline()[:-1]
...
elif conn and x == conn.fileno():
data = conn.recv(msglen)
if data:
....
else:
# connection has ended, remove from poll list and close
if conn.fileno() in inputReady:
inputReady.remove(conn.fileno())
conn.close()
Related
I asked a question about my server to client code because I had many problems with and someone told me that the solution to the problems I had was to make a peer to peer chat which I have now done.
Server.py
import socket, threading
host = "127.0.0.1"
port = 4000
s = socket.socket()
s.bind((host,port))
s.listen(5)
client_sockets = []
users = []
print("Listening")
def handle_client(conn):
while True:
try:
data = conn.recv(512)
for x in client_sockets:
try:
x.send(data)
except Exception as e:
print(e)
except:
pass
while True:
conn,addr = s.accept()
client_sockets.append(conn)
print("Connections from", addr[0], "on port",addr[1])
threading.Thread(target = handle_client,args = (conn,)).start()
Client.py
import socket,threading
host = "127.0.0.1"
port = 4000
s = socket.socket()
s.connect((host,port))
def echo_data(sock):
while True:
try:
data = sock.recv(512)
print(data)
except:
pass
while True:
threading.Thread(target=echo_data,args=(s,)).start()
msg = input("Enter your message : ")
s.send(msg.encode())
The problems is that when I run the client and try talking to another client the message doesn't get sent unless the other client hits enter and also that brings me to my second problem, when the clients send messages to each other they get received in this format:
b'hi'Enter your message :
This is the link to my previous question
I will start with general problems not directly related to the question:
except: pass is generally a bad idea, specially when things go wrong because it will hide potentially useful messages. It is allowed by the language but should never exist in real code
in client.py you start a receiving thread per message, while you only need one for the whole client. You should start the thread outside the loop:
threading.Thread(target=echo_data,args=(s,)).start()
while True:
msg = input("Enter your message : ")
s.send(msg.encode())
Now for the questions:
the message doesn't get sent unless the other client hits enter
It can be caused by an IDE. Specifically, IDLE is known to behave poorly with multi-threaded scripts. If you correctly use one single receiving thread and starts the script from the command line (python client.py) it should work correctly
the messages get recived in this format: b'hi'Enter your message
sock.recv(sz) returns a byte string. You need to decode it to convert it to a Python 3 unicode string:
data = sock.recv(512)
print(data.decode())
But that is not all. It is fine for tests, but you should at least allow clients to disconnect from the server and when they do, remove them from client_sockets. And it is common not to send back a message to the sender. So you could improve the server.py loop:
while True:
try:
data = conn.recv(512)
for x in client_sockets:
if x != conn: # do not echo to sender
x.send(data)
except Exception as e: # problem in connection: exit the loop
print(e)
break
# clear the connection
conn.close()
client_sockets.remove(conn)
I am trying to design a multithreaded server. client1 send data to server and server forwards data to client2 for processing. client2 sends processed data to server and then server forwards it to client1.
Data from client1 is received by client2 through server while execution, but my server program after sending data to client2 terminates with error
[10054] An existing connection was forcibly closed by remote host.
client1.py
from socket import *
import thread
ip='127.1.1.2'
port=5554
s=socket(AF_INET, SOCK_STREAM)
s.connect((ip,port))
data=raw_input("Input lowercase :: ")
while data!="#close":
s.send(data)
data=raw_input("Input next word or type #close to exit: ")
s.close()
client2.py
from socket import *
import thread
ip='127.1.1.2'
port=5554
s=socket(AF_INET, SOCK_STREAM)
s.connect((ip,port))
m=s.recv(1024)
k=m.upper()
print "Uppercase of ",m," in System--> ",k
s.close()
server.py
from socket import *
import thread
ip='127.1.1.2'
port=5554
data=''
def multi_threading(c,a):
while True:
global data
print "Inside client 1 thread"
data= c.recv(1024)
if not data:
break
if "close"==data.rstrip():
break
c.close()
print a,"--terminates connection"
def multi_threading2(c,a):
while True:
print "Inside client 2 thread"
c.send(data)
if not data:
break
if "close"==data.rstrip():
break
c.close()
print a,"--terminates connection"
if __name__=='__main__':
s=socket(AF_INET, SOCK_STREAM)
s.setsockopt(SOL_SOCKET, SO_REUSEADDR,1)
s.bind((ip,port))
s.listen(4)
count=0
while True:
print "Server is listening on port number ",port
c,a=s.accept()
count=count+1
print "--------------------------------------------------"
print "Server connected to system having ip address --> ",a
if(count==1):
thread.start_new_thread(multi_threading,(c,a))
else:
thread.start_new_thread(multi_threading2,(c,a))
What i might be doing wrong?
I'm trying to help by changing your code as little as possible. It isn't how I would write it but should allow you to follow along. This is also not very idomatic Python. I just want you to see how to get the basic interaction going.
Some comments about my changes:
Remove the indent in client1.py so you don't always close the
socket with s.close(). I suspect this was a typo in your post?
In server.py it isn't safe to access the global data between two
threads. At the very least you need a semaphore to protect it.
Every time around multi_threading loop you destroy the last value of
data. You need to append the incoming bytes to a data structure
like a list. I renamed the threads to make it easier to understand.
You are expecting to see close in the server but you don't ever send this because your loop terminates when you type #close. You need to adjust for this.
Your code is order dependent because both client 'sender' and client 'receiver' use the same port. You need to put something into the protocol to distinguish between these two roles so you can start them in either order. This makes the system more robust.
Due to the sender not necessarily having any data I do a crude sleep. This can be avoided by using a shared queue between the threads which would block one end
You need some framing because you can't guarantee the speed at which the independent processes send and receive to the socket. I use \n for this.
There is an edge case if you sent very large strings (and removed the 1024 read) you could not get a full word with the \n through. I ignore this case.
I adjust the loopback address
I wrote this in PyCharm CE. I recommend using an IDE (PyCharm is excellent) with breakpoints. You can step through all the processes bit by bit. Put breakpoints in the threads and step through the actions.
Result:
server.py
from socket import *
import thread
from threading import Lock
import time
ip = '127.0.0.1'
port = 5554
data = []
data_lock = Lock()
def multi_threading_recv(sock, a):
should_run = True
while should_run:
global data
print "Inside client 1 thread"
_data = sock.recv(1024)
if _data:
with data_lock:
for word in _data.split('\n'):
data.append(word)
if "#close" == word:
should_run = False
break
else:
break
sock.close()
print a, "--terminates connection"
def multi_threading_send(sock, a):
while True:
print "Inside client 2 thread"
with data_lock:
if len(data) == 0:
time.sleep(1) # Not ideal. Ideally block on a shared queue
continue
else:
_data = data.pop(0)
if _data == "#close":
break
sock.send(_data + '\n')
c.close()
print a, "--terminates connection"
if __name__ == '__main__':
s = socket(AF_INET, SOCK_STREAM)
s.setsockopt(SOL_SOCKET, SO_REUSEADDR,1)
s.bind((ip,port))
s.listen(4)
count = 0
while True:
print "Server is listening on port number ", port
c, a = s.accept()
print "--------------------------------------------------"
print "Server connected to system having ip address --> ", a
role = c.recv(4)
if role == 'PUSH':
thread.start_new_thread(multi_threading_recv, (c, a))
elif role == 'PULL':
thread.start_new_thread(multi_threading_send, (c,a))
else:
print('invalid role: ' + role)
c.close()
client1.py
from socket import *
ip = '127.0.0.1'
port = 5554
s = socket(AF_INET, SOCK_STREAM)
s.connect((ip,port))
s.send('PUSH')
while True:
data = raw_input("Input word or type #close to exit: ")
s.send(data + '\n')
if data == "#close":
break
s.close()
client2.py
from socket import *
ip = '127.0.0.1'
port = 5554
s = socket(AF_INET, SOCK_STREAM)
s.connect((ip, port))
s.send('PULL')
while True:
data = s.recv(1024)
if data:
words = data.split('\n')
for w in words:
print(w)
else:
break
s.close()
Output:
client1
Input word or type #close to exit: hello
Input word or type #close to exit: world
Input word or type #close to exit: #close
client2:
hello
world
server:
Server is listening on port number 5554
--------------------------------------------------
Server connected to system having ip address --> ('127.0.0.1', 62605)
Server is listening on port number 5554
Inside client 1 thread
('127.0.0.1', 62605) --terminates connection
--------------------------------------------------
Server connected to system having ip address --> ('127.0.0.1', 62614)
Server is listening on port number 5554
Inside client 2 thread
Inside client 2 thread
Inside client 2 thread
('127.0.0.1', 62614) --terminates connection
There is one final comment that the server will go around the loop again and keep on accepting clients. The code doesn't cope with this and I leave it as an exercise for you. You can multiplex multiple senders and receivers if you add a channel number to the PUSH and PULL initiation of the protocol (e.g. PUSH3, PULL3). This will then allow you to store the incoming data in a dictionary keyed by this integer and then send it out to the correct client.
I am trying to modify a server and client chat script implemented in python. One of the requirement is that the client exits when the user types CTRL-D. My question is how do I read that the user typed (ctrl-D) and implement it within this code. Should I just close the socket like c_socket.close() without any message back to the server that I am exiting?
Thanks!
# telnet program example
import socket, select, string, sys
import readline
def prompt() :
sys.stdout.write('<You> ')
sys.stdout.flush()
#main function
if __name__ == "__main__":
if(len(sys.argv) < 3) :
print 'Usage : python MClient hostname port'
sys.exit()
host = sys.argv[1]
port = int(sys.argv[2])
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(2)
# connect to remote host
try :
s.connect((host, port))
except :
print 'Unable to connect'
sys.exit()
print 'Connected to remote host. Start sending messages'
prompt()
while 1:
socket_list = [sys.stdin, s]
# Get the list sockets which are readable
read_sockets, write_sockets, error_sockets = select.select(socket_list , [], [])
for sock in read_sockets:
#incoming message from remote server
if sock == s:
data = sock.recv(4096)
if not data :
print '\nDisconnected from chat server'
sys.exit()
else :
#print data
sys.stdout.write(data)
prompt()
#user entered a message
else :
msg = sys.stdin.readline()
s.send(msg)
prompt()
Last thing first - whether you need to send something to the server before closing the socket or not depends purely on your protocol. Given the simplistic nature of the presented client code, I'd guess that closing of the socket should be enough (and the server should treat unannounced disconnects anyway as one shouldn't consider network I/O as persistent).
Second, CTRL+D will cause the returned message from sys.stdin.readline() to return as empty so you can test against that, e.g.:
msg = sys.stdin.readline()
if msg:
s.send(msg)
prompt()
else:
s.close()
sys.exit()
If you really need to send something to the server (again, depends on the protocol) you can use socket's shutdown() method before calling close().
However, keep in mind that the code presented here doesn't account for pressing the CTRL+D while reading from the socket (i.e. receiving data) so if there is a particularly long data stream coming in your CTRL+D won't be registered. You can solve this by checking the user input (and writing it to buffer for later sending) during the retrieval procedure, or you can just place your receiving code in a separate thread and leave the main thread just for user input.
You can then use the atexit module to cleanly exit from your client at any time.
I'm trying to develop a chat program in python. I want it to have multiple clients so I'm using threading to handle this. However when I try to send the message to all connected clients, the server only sends it to the client which sent the message. I'm not sure if I'm just missing something obvious but here is the code for the server:
import socket
from thread import *
host = '192.168.0.13'
port = 1024
users = int(input("enter number of users: "))
def clienthandler(conn):
while True:
data = conn.recv(1024)
if not data:
break
print data
conn.sendall(data)
conn.close()
serversock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversock.bind((host, port))
serversock.listen(users)
for i in range(users):
conn, addr= serversock.accept()
print 'Connected by', addr
start_new_thread(clienthandler, (conn,))
And here is the code for the client:
import socket
host = '192.168.0.13'
port = 1024
usrname = raw_input("enter a username: ")
usrname = usrname + ": "
clientsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clientsock.connect((host, port))
while True:
x = raw_input('You: ')
x = usrname + x
clientsock.sendall(x)
data = clientsock.recv(1024)
print data
The "all" in sendall means that it sends all of the data you asked it to send. It doesn't mean it sends it on more than one connection. Such an interface would be totally impractical. For example, what would happen if another thread was in the middle of sending something else on one of the connections? What would happen if one of the connections had a full queue?
sendall: Send data to the socket. The socket must be connected to a remote socket. The optional flags argument has the same meaning as for recv() above. Unlike send(), this method continues to send data from string until either all data has been sent or an error occurs. None is returned on success. On error, an exception is raised, and there is no way to determine how much data, if any, was successfully sent. -- 17.2. socket
You can try by pulling up the list of users, and iterating through it, and doing an individual send of the same message, though, unless you are the administrator and want to broadcast a warning, this functionality would be pretty mundane.
import select
import socket
import sys
host = ''
port = 50000
backlog = 5
size = 1024
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((host,port))
server.listen(5)
input = [server,sys.stdin]
running = 1
while running:
inputready,outputready,exceptready = select.select(input,[],[])
for s in inputready:
if s == server:
# handle the server socket
client, address = server.accept()
input.append(client)
elif s == sys.stdin:
# handle standard input
junk = sys.stdin.readline()
running = 0
else:
# handle all other sockets
data = s.recv(size)
if data:
s.send(data)
else:
s.close()
input.remove(s)
server.close()
Whenever I run this code, I get this error message for my argument for the while loop:
inputready,outputready,exceptready = select.select(input,[],[])
TypeError: argument must be an int, or have a fileno() method.
How can I fix this to make the server run properly? Sorry if this is a bad question, I'm new to python and I can't figure this out. Thanks.
Yeah found the solution to your problem their seem to be sys.stdin , the python IDLE GUI for some reason doesn't allow you to use sys.stdin.fileno() in your code, while if you run it in the command prompt or the terminal it will work fine on linux. Link
An if your using windows, you cant pass the sys.stdin as an argument to the select() function, as in windows it accepts only sockets as arguments. As Explained in the documentation Documentation
Note: File objects on Windows are not acceptable, but sockets are. On Windows, the underlying select() function is provided by the WinSock library, and does not handle file descriptors that don’t originate from WinSock.
So to mitigate the problem , such that it works on both windows and linux:
import select
import socket
import sys
host = ''
port = 50000
backlog = 5
size = 1024
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((host,port))
server.listen(backlog)
input1 = [server]
running = 1
while running:
inputready,outputready,exceptready = select.select(input1,[],[])
for s in inputready:
if s == server:
# handle the server socket
client, address = server.accept()
input1.append(client)
elif s == sys.stdin:
# handle standard input
junk = sys.stdin.readline()
running = 0
else:
# handle all other sockets
data = s.recv(size)
if data:
s.send(data)
else:
s.close()
input1.remove(s)
server.close()