Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python Socket Listening

All of the below mentioned is on windows machines using python 2.7

Hello,

I am currently attempting to listen on a socket for data send by a remote program. This data is then printed to the screen and user input is requested that is then returned to remote program. In testing I have been able to have the remote program send me a menu of command line programs (cmd, ipconfig, whoami, ftp) and then my program returns with a number as a selection of the menu option.

The remote program receives my response and sends the output of the selected command. ipconfig and whoami work perfectly, but cmd and ftp only returns the output of the terminal once. (I.E. I can enter one command into the FTP program and send that too the remote program before I never hear back)

The part of my code that fails is that if ready[0]: never becomes ready a second time after the first conversation.

I know the remote program is functioning correctly as I can use netcat to act in lieu of my code and operate the cmd terminal indefinitely.

How do I go about properly implementing a python socket listener that can account for this type of connection?

My "program" in its entirety:

import socket, sys, struct, time, select

host = ''
port = 50000
connectionSevered=0

try:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error:
    print 'Failed to create socket'
    sys.exit()
print '[+] Listening for connections on port '+str(port)+'.'

s.bind((host,port))
s.listen(5)         

def recvall(the_socket,timeout=2):
    global connectionSevered
    data='';          # Data found by recv
    total_data=[];    # Finally list of everything

    s.setblocking(0)  #make socket non blocking
    begin=time.time() #beginning time

    while 1:
        ready = select.select([client], [], [], .2)
        if time.time()-begin > timeout:
            print 'Timeout reached'
            #Leave loop, timer has reached its threshold
            break
        if ready[0]:
            print 'In ready loop!'
            try:
                data = client.recv(4096)    #attempt to fetch data
                if data:
                    begin=time.time()       #reset timeout timer
                    total_data.append(data) 
                    data='';
            except socket.error:
                print '[+] Lost connection to client. Printing buffer...'
                connectionSevered=1   # Let main loop know connection has errored
                pass
        time.sleep(1)
    #join all parts to make final string
    return ''.join(total_data)

client, address = s.accept()
print '[+] Client connected!'

while (connectionSevered==0): # While connection hasn't errored
    print "connectionSevered="+str(connectionSevered) # DEBUG
    recvall(s)
    response = raw_input()                  #take user input
    client.sendto(response)                   #send input
client.close(0)

Please let me know if you need more information, any help would be greatly appreciated, I am very new to this and eager to learn.

like image 884
Mr S Avatar asked Apr 07 '13 23:04

Mr S


People also ask

What is listen () method in Python?

The .listen() method has a backlog parameter. It specifies the number of unaccepted connections that the system will allow before refusing new connections. Starting in Python 3.5, it's optional. If not specified, a default backlog value is chosen.

How do you listen to a socket?

To listen on a socketCall the listen function, passing as parameters the created socket and a value for the backlog, maximum length of the queue of pending connections to accept. In this example, the backlog parameter was set to SOMAXCONN.

How do you stop a listening socket in Python?

In most cases you will open a new thread or process once a connection is accepted. To close the connection, break the while loop.

What is the difference between bind () and listen ()?

A server has a bind() method which binds it to a specific IP and port so that it can listen to incoming requests on that IP and port. A server has a listen() method which puts the server into listen mode. This allows the server to listen to incoming connections.


2 Answers

Playing around with this for a while finally got it working nice with a telnet session locally using python 2.7.

What it does is it sets up a thread that runs when the client connects listening for client stuff.

When the client sends a return ("\r\n" might have to change that if your interacting with a Linux system?) the message gets printed to the server, while this is happening if there is a raw input at the server side this will get sent to the client:

import socket
import threading
host = ''
port = 50000
connectionSevered=0

class client(threading.Thread):
    def __init__(self, conn):
        super(client, self).__init__()
        self.conn = conn
        self.data = ""
    def run(self):
        while True:
            self.data = self.data + self.conn.recv(1024)
            if self.data.endswith(u"\r\n"):
                print self.data
                self.data = ""

    def send_msg(self,msg):
        self.conn.send(msg)

    def close(self):
        self.conn.close()

try:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind((host,port))
    s.listen(5)
except socket.error:
    print 'Failed to create socket'
    sys.exit()

print '[+] Listening for connections on port: {0}'.format(port)


conn, address = s.accept()
c = client(conn)
c.start()
print '[+] Client connected: {0}'.format(address[0])
c.send_msg(u"\r\n")
print "connectionSevered:{0}".format(connectionSevered) 
while (connectionSevered==0):
    try:
        response = raw_input()  
        c.send_msg(response + u"\r\n")
    except:
        c.close()

The above answer will not work for more than a single connection. I have updated it by adding another thread for taking connections. It it now possible to have more than a single user connect.

import socket
import threading
import sys
host = ''
port = 50000

class client(threading.Thread):
    def __init__(self, conn):
        super(client, self).__init__()
        self.conn = conn
        self.data = ""

    def run(self):
        while True:
            self.data = self.data + self.conn.recv(1024)
            if self.data.endswith(u"\r\n"):
                print self.data
                self.data = ""

    def send_msg(self,msg):
        self.conn.send(msg)

    def close(self):
        self.conn.close()

class connectionThread(threading.Thread):
    def __init__(self, host, port):
        super(connectionThread, self).__init__()
        try:
            self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.s.bind((host,port))
            self.s.listen(5)
        except socket.error:
            print 'Failed to create socket'
            sys.exit()
        self.clients = []

    def run(self):
        while True:
            conn, address = self.s.accept()
            c = client(conn)
            c.start()
            c.send_msg(u"\r\n")
            self.clients.append(c)
            print '[+] Client connected: {0}'.format(address[0])



def main():
    get_conns = connectionThread(host, port)
    get_conns.start()
    while True:
        try:
            response = raw_input() 
            for c in get_conns.clients:
                c.send_msg(response + u"\r\n")
        except KeyboardInterrupt:
            sys.exit()

if __name__ == '__main__':
    main()

Clients are not able to see what other clients say, messages from the server will be sent to all clients. I will leave that as an exercise for the reader.

like image 82
Noelkd Avatar answered Oct 19 '22 08:10

Noelkd


If you're in Python 3 by now and still wondering about sockets, here's a basic way of using them:

server.py

import time
import socket

# creating a socket object
s = socket.socket(socket.AF_INET,
                  socket.SOCK_STREAM)

# get local Host machine name
host = socket.gethostname() # or just use (host == '')
port = 9999

# bind to pot
s.bind((host, port))

# Que up to 5 requests
s.listen(5)

while True:
    # establish connection
    clientSocket, addr = s.accept()
    print("got a connection from %s" % str(addr))
    currentTime = time.ctime(time.time()) + "\r\n"
    clientSocket.send(currentTime.encode('ascii'))
    clientSocket.close()

client.py

import socket

# creates socket object
s = socket.socket(socket.AF_INET,
                  socket.SOCK_STREAM)

host = socket.gethostname() # or just use (host = '')
port = 9999

s.connect((host, port))

tm = s.recv(1024) # msg can only be 1024 bytes long

s.close()
print("the time we got from the server is %s" % tm.decode('ascii'))

Run server.py first, then run client.py.

This is just send and receive the currentTime.

What's new in Python 3.4 sockets?

A major difference between python 2.7 sockets and python 3.4 sockets is the sending messages. you have to .encode() (usually using 'ascii' or blank as parameters/arguments) and then using .decode()

For example use .encode() to send, and use .decode() to receive.

Extra info: client/server socket tutorial

like image 28
Leigh Flix Avatar answered Oct 19 '22 08:10

Leigh Flix