I'm trying to create a simple server that receiving an option and returning a method.
So I looked for a few examples and I found this one:
def start_server(ip="0.0.0.0", port=8820):
sock = socket.socket()
sock.bind((ip, port))
sock.listen(1)
print "Server started listening on %s:%d" % (ip, port)
return sock
def new_client(sock):
c_sock, c_addr = sock.accept()
print "got new client %s" % c_addr
return c_sock, c_addr
How do I create the start server and client calls?
I want the client to send an option and the server return the method
with a loop that ends in call the quit method.
like an example method if the client pressed "name":
def get_name():
return "My name is Server!"
thanks!
Here's a quick sample that creates an "echo" server. (It just sends all the data it gets from a client back to the client.)
Add this to the end of your existing code:
import select
def main():
lsock = start_server()
rfds=[lsock]
while True:
readyfds, _, _ = select.select(rfds, [], [])
for fd in readyfds:
if fd == lsock:
csock, caddr = new_client(lsock)
rfds.append(csock)
else:
rdata = fd.recv(1024)
if rdata:
print("Got some data from client socket %s" % fd)
# Send data back to client
fd.send(rdata)
else:
print("Client socket closed %s" % fd)
rfds.remove(fd)
fd.close()
main()
Annotation: We are using select here to allow a single thread to wait on multiple file descriptors at once. Whenever a connection request comes in from a client, the listening socket becomes "ready"; we then accept the connection and add the new socket to the set of descriptors in our selection list.
When we receive data from any other socket, we call recv. If that succeeds, we send the same data back to the client (obviously a real server would do something more useful with the data). If the recv returns zero, that means the client closed the socket, so then we remove the descriptor from the selection list.
One more thing: In the line print "got new client %s" % c_addr, c_addr is a tuple (address and port), hence the formatting fails due to TypeError: not all arguments converted during string formatting. Easy fix is to make it: print "got new client %s" % str(c_addr)
Related
This question already has an answer here:
Python Bidirectional TCP Socket Hanging on socket.recv
(1 answer)
Closed 3 years ago.
I'm trying to make a client-server application in which:
the client sends a message (name of a function) to the server
the server receives the message, calls the corresponding function and returns the results to the client.
I'm able to do this only if the message from the client is one; if I want to call two or more functions, and therefore send two or more messages, I get some problems because I need to add a loop inside the server.
In particular, what is not clear to me is the socket function recv(). Usually, to receive data I write something like this (without setblocking()) and I never had any problems:
while True:
data = sock.recv(BUFFER)
results += data.decode()
if not data:
break
But if I add a while True: to the server (in order to wait for the other functions), then the client never exits from sock.rev(). Why? I expect that function to be always blocking or always non-blocking based on how it was set sock.setblocking().
I already tried with settimeout() and it worked, but performances are really important so I would like to avoid every possible delay.
Anyway, the main question is why recv() is behaving differently; then if you had any suggestions to solve my task it would be really appreciated.
Here's a simple simulation of the real application.
Client:
import socket
BUFFER = 1024
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address= ('localhost', 14000)
sock.connect(bridge_address)
msg1 = "function 1".encode()
msg2 = "function 2".encode()
results1 = " "
results2 = " "
sock.sendall(msg1)
while True:
data = sock.recv(BUFFER)
results1 += data.decode()
if not data:
print('no more data')
break
sock.sendall(msg2)
while True:
data = sock.recv(BUFFER)
results2 += data.decode()
if not data:
print('no more data')
break
sock.close()
print('Results 1: ',results1)
print('Results 2: ',results2)
Server:
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = ('localhost', 14000)
sock.bind(server_address)
sock.listen(1)
msg = ""
for i in range(4096):
msg += str(i) + " "
while True:
print('waiting for a connection')
client, client_address = sock.accept()
try:
while True:
data = client.recv(128)
if not data:
print('no more data from')
break
client.sendall(msg.encode())
finally:
print('connection closed.\n')
client.close()
You are explicitly forcing the server side socket to recieve the message from the client, even when the client is not sending anything.
data = client.recv(128)
if not data:
print('no more data from')
break
if case in the code snippet above will only execute when the client socket goes down.
One method to solve this would be to first send the size of the message and then call recv accordingly for the specified number of bytes.
I'm attempting to write a simple multiplayer type text game. I currently have a simple chat server right now. It's working just like it should, echoing the message to all the people connected.
I can't figure out how to take my next step. I want to associate the client connected with a player object. The player objects house the available commands someone can type in, so in order to move forward with parsing input I have to be able to do this - I just don't know how.
Currently the player object is just a standard object class with a few properties like 'name', 'id', 'location', that has a list of commands available to them. If you need a code example of that I can provide one.
Any ideas?
import socket, select
from helpers.colorize import colorize
class Server(object):
def __init__(self, host, port):
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.server.bind((host, port))
self.server.listen(1)
self.clients = [self.server]
def start(self):
while True:
read_sockets,write_sockets,error_sockets = select.select(self.clients, [], [])
for sock in read_sockets:
#new conn
if sock == self.server:
sockfd, addr = self.server.accept()
self.clients.append(sockfd)
print "Connection from %s %s" % addr
#looks like a message
else:
#data recieved, lets try and do something
try:
data = sock.recv(4096)
if data: #we have something, parse it
self.sendall(sock, data) #give it to everyone for now
except: #disconnection, remove from our lists
self.sendall(sock, ("%s %s disconnected" % addr))
print "%s %s disconnected." % addr
socket.close()
self.clients.remove(sock)
continue
self.server.close()
def send(self, sock, message):
sock.send(colorize(message))
def sendall(self, sock, message):
#Do not send the message to master socket and the client who has send us the message
for socket in self.clients:
if socket != self.server:
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__":
s = Server('localhost', 2222)
s.start()
You can use a dict to map fds of client sockets to client objects.
When you receive some new messages, you can fetch the corresponding object from the dict and invoke methods on it.
I have a twisted server script listening on a unix socket and it receives the data when the client is in twisted but it doesn't work if i send it via a vanilla python socket code.
class SendProtocol(LineReceiver):
"""
This works
"""
def connectionMade(self):
print 'sending log'
self.sendLine(self.factory.logMessage)
if __name__ == '__main__':
address = FilePath('/tmp/test.sock')
startLogging(sys.stdout)
clientFactory = ClientFactory()
clientFactory.logMessage = 'Dfgas35||This is a message from server'
clientFactory.protocol = SendProtocol
port = reactor.connectUNIX(address.path, clientFactory)
reactor.run()
But this doesn't (server doesn't get any data)
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock_addr = '/tmp/test.sock'
try:
sock.connect(sock_addr)
except socket.error, msg:
print >> sys.stderr, msg
sys.exit(1)
sock.setblocking(0) # not needed though tried both ways
print 'connected %s' % sock.getpeername()
print 'End END to abort'
while True:
try:
line = raw_input('Enter mesg: ')
if line.strip() == 'END':
break
line += '\n'
print 'sending'
sock.sendall(line)
finally:
sock.close()
Your two client programs send different data. One sends \r\n-terminated lines. The other sends \n-terminated lines. Perhaps your server is expecting \r\n-terminated lines and this is why the latter example doesn't appear to work. Your non-Twisted example also closes the socket after the first line it sends but continues with its read-send loop.
This question already has an answer here:
Sending data from one Protocol to another Protocol in Twisted?
(1 answer)
Closed 8 years ago.
The code below receives data through sockets from an iPhone, and then I want to send that received data to another python script running through a different socket. My attempt is below. The other server receives the message fine however I am getting an errno 9 bad file descriptor as soon as I send the second message. Is there anyway to change the below code so it can continuously send received data straight to another socket?
import os
from twisted.internet.protocol import Protocol, Factory
from twisted.internet import reactor
from threading import Thread
class IphoneChat(Protocol):
def connectionMade(self):
self.factory.clients.append(self)
print "A new client has connected"
def connectionLost(self, reason):
print "client disconnected"
def dataReceived(self, data):
print "Message Received: ", data
TCP_IP = '127.0.0.1'
TCP_PORT = 5000
BUFFER_SIZE = 1024
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TCP_IP, TCP_PORT))
s.send(data)
s.close()
def message(self, message):
self.transport.write(message + '\n')
factory = Factory()
factory.protocol = IphoneChat
factory.clients = []
reactor.listenTCP(3000, factory)
print "listening to 3000"
reactor.run()
There are a couple of errors in your IphoneChat code: a missing import socket and self.s = socket.socket(...) should just bind to a local variable s, not to the instance variable self.s.
Nevertheless, I think that the exception (socket.error: [Errno 9] Bad file descriptor) is actually being raised in the "other" Python script for which you don't show any code. It would be helpful to see that code, however, it is likely that you are closing the main server socket in response to the connection being closed by the IphoneChat script, rather than the per connection socket returned by socket.accept(). Here's some rough code that should work as the receiving server:
import socket
s = socket.socket()
s.bind(('127.0.0.1', 5000))
s.listen(1)
while True:
print "Waiting for connection... ",
conn, addr = s.accept()
print "Got connection from {}".format(addr)
while True:
msg = conn.recv(1024)
if msg == '':
print "Remote disconnected"
break
print "Got msg: %r" % msg
# N.B. close connection to remote peer, not the main server socket "s"
conn.shutdown(socket.SHUT_RDWR)
conn.close()
My guess is that you have code similar to the above, but that you are closing the main server socket instead of the remote connection.
I have this code
class ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler):
def handle(self):
_data = self.request.recv(1024)
Utils.log("Received from %s: %s" % (self.client_address, _data))
calling it with
kamcon_server = ThreadedTCPServer((HOST, 3011), ThreadedTCPRequestHandler)
server_thread = threading.Thread(target = kamcon_server.serve_forever)
server_thread.setDaemon(True)
server_thread.start()
I can connect to the host, and the server can send the data, but when the client sends something to the server, the connection is automatically closed. Why? Thank you.
Your handle() method is only calling recv() once per connection. If you want to handle multiple messages from the client, you need to loop. You should think about your protocol as well, so that you can handle request/response messages larger than 1024 bytes (e.g. parse _data and figure out if you have a complete message, buffer partial requests, etc).
For example:
def handle(self):
close = 0
while not close:
_data = self.request.recv(1024)
if not _data:
# EOF, client closed, just return
return
Utils.log("Received from %s: %s" % (self.client_address, _data))
self.request.send('got %d bytes\r\n' % len(_data))
if 'quit' in _data:
close = 1
Client session:
% telnet localhost 3011
hi
got 4 bytes
bye
got 5 bytes
telnet> quit
Try this code, it allows multiple connections to same port and not close socket until client do it:
import SocketServer
import socket, threading
class MyTCPHandler(SocketServer.BaseRequestHandler):
BUFFER_SIZE = 4096
def handle(self):
while 1:
#get input with wait if no data
data = self.request.recv(self.BUFFER_SIZE)
#suspect many more data (try to get all - without stop if no data)
if (len(data)==self.BUFFER_SIZE):
while 1:
try: #error means no more data
data += self.request.recv(self.BUFFER_SIZE, socket.MSG_DONTWAIT)
except:
break
#no data found exit loop (posible closed socket)
if (data == ""): break
#processing input
print "%s (%s) wrote: %s" % (self.client_address[0], threading.currentThread().getName(), data.strip())
if __name__ == "__main__":
HOST, PORT = "localhost", 9999
server = SocketServer.ThreadingTCPServer((HOST, PORT), MyTCPHandler)
server.serve_forever()
You can also use ForkingTCPServer instead ThreadingTCPServer.
the handle() method is called once a new TCP connection is set up, not once every time there is data available. You're supposed to handle all comminication of a TCP session in this method.
Since all you do is read one chunk of data, the connection getst closed when the handle() method returns.
Look into how TCP connections work, at the end of every 'Stream' of TCP data the connection is closed, to tell the listener that no more data is incoming in that batch. Roughly a TCP connection is as follows:
Open Connection
Send Data
Close Connection
If you're just looking at sending packets of data, try using UDP instead that way each packet will be read on arrival, provided you're listening for it.
It might be worth telling us what your planning on using this server for...
Anyway hope that helps.