1

I have a streaming server / motion detection script that works on my laptop, but when I move it to my PI it gives the following error when i try and access the stream:

my laptop ip address - - [23/Jun/2015 13:04:34] "GET / HTTP/1.1" 200 -
Exception in thread Thread-2:
Traceback (most recent call last):
  File "/usr/lib/python2.7/threading.py", line 552, in __bootstrap_inner
    self.run()
  File "/usr/lib/python2.7/threading.py", line 505, in run
    self.__target(*self.__args, **self.__kwargs)
  File "/usr/src/scripts/areadetect_movie__33.py", line 300, in server
    server = HTTPServer(('',port),CamHandler)
  File "/usr/lib/python2.7/SocketServer.py", line 419, in __init__
    self.server_bind()
  File "/usr/lib/python2.7/BaseHTTPServer.py", line 108, in server_bind
    SocketServer.TCPServer.server_bind(self)
  File "/usr/lib/python2.7/SocketServer.py", line 430, in server_bind
    self.socket.bind(self.server_address)
  File "/usr/lib/python2.7/socket.py", line 224, in meth
    return getattr(self._sock,name)(*args)
error: [Errno 98] Address already in use

a) The motion side of the script works, but the server doesn't.

b) I can serve a simple webpage using the same IP address and port, using a different script, so I don't think something else is using that port.

c) Both PI and laptop are on the same local network.

1) Are there any other tests I can do, that could point to what is wrong?

2) What do these errors suggest?

Edit:

ps aux | grep streaming_server_variation_16.py gives:

root      2508 79.7 11.9 111392 45560 ?        Sl   13:19   1:53 /usr/bin/python ./streaming_server_variation_16.py
root      2560  0.0  0.8   5380  3200 pts/0    S+   13:21   0:00 grep streaming_server_variation_16.py

I'm starting two threads like this:

if runtime_frame_count == 0:

    Thread(target = main).start()
    time.sleep(10)
    Thread(target = server).start() 

note 'runtime_frame_count' increments, so this should only run once.

The "main" thread gathers the frames from the camera and performs the motion detection, and the "server" tries to serve the frames gathered.

Could this be why I'm having the same script trying to access the port, but in different threads?

edit 2 to explain exactly what i'm doing:

a) I'm accessing the headless PI, via two open SSH putty connections, from my laptop which has a local IP address of 192.168.1.4 and the PI has a local IP address of 192.168.1.61.

b) I run the script using one SSH connection and watch the script increment the runtime_frame_count which prints out on each new frame gathered; i'll call this SSH window run-ssh-window, then I use the other SSH connection to send the commands, i'll call this command-ssh-window.

c) When thread 2 starts (server) the script outputs from the run-ssh-window

server started on:
127.0.1.1

because of the following code inside that thread:

print ("server started on: ")
print(socket.gethostbyname(socket.gethostname())) 

d) Then I try and access the stream from my laptop's browser by placing the text http://192.168.1.61:1991/ in the browser, when I get the same errors as listed above from the running incrementing script (in the run-ssh-window).

e) following the error, the script continues to increment (in the run-ssh-window), so in the command-ssh-window i sudo netstat -atpen which gives:

Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       User       Inode       PID/Program name
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      0          6188        1962/uv4l
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      0          6509        2306/sshd
tcp        0      0 127.0.0.1:6010          0.0.0.0:*               LISTEN      0          35991       11960/0
tcp        0      0 127.0.0.1:6011          0.0.0.0:*               LISTEN      0          36885       12135/1
tcp        0    352 192.168.1.61:22         192.168.1.4:50175       ESTABLISHED 0          36843       12135/1
tcp        0      0 192.168.1.61:22         192.168.1.4:49853       ESTABLISHED 0          36031       11984/sshd: root@no
tcp        1      0 192.168.1.61:49540      editexternaladdress:443      CLOSE_WAIT  108        7075        2284/mount.davfs
tcp        0      0 192.168.1.61:22         192.168.1.4:49812       ESTABLISHED 0          35928       11960/0
tcp        0      0 192.168.1.61:22         192.168.1.4:50355       ESTABLISHED 0          37350       12214/sshd: root@no

where I cannot see two processes trying to access the port 1991 on 192.168.1.61.

Am I doing anything incorrectly?

I'm still confused what could be happening with the "address already in use" error listed above.

Another edit resulting from comments

I start the socket using the command: server = HTTPServer(('',port),CamHandler) which calls the CamHandler class to deal with constructing the stream.

the CamHandler class looks like this:

class CamHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        print (self.path)
        if self.path.endswith('.mjpg'):
            self.send_response(200)
            self.send_header('Content-type','multipart/x-mixed-replace; boundary=--jpgboundary')
            self.end_headers()
            while(True):
                        global imgRGB #imgRGB is gathered from the camera in the main thread, which starts 10 seconds prior to the server thread (this one)                            
                        r, buf = cv2.imencode(".jpg",imgRGB) # imencode Encodes an image into a memory buffer.

                        # the following 7 lines output the contents of buf to the webpage

                        self.wfile.write("--jpgboundary\r\n")
                        self.send_header('Content-type','image/jpeg')
                        self.send_header('Content-length',str(len(buf)))
                        self.end_headers()
                        self.wfile.write(bytearray(buf))
                        self.wfile.write('\r\n')
                        time.sleep(0.01)
                        k = cv2.waitKey(20)
                        if k == 27: 
                            break

            cv2.destroyAllWindows()
            capture.release()   

        if self.path.endswith('.html') or self.path=="/":# jumps into this block of code at start of request to set up the html page but doesn't come back
            self.send_response(200)
            self.send_header('Content-type','text/html')
            self.end_headers()
            self.wfile.write('<html><head></head><body>')
            self.wfile.write('<img src="http://'+socket.gethostbyname(socket.gethostname())+':'+ str(port) +'/cam.mjpg"/>')
            self.wfile.write('</body></html>')
            return

I too thought there was an issue with the script outputting 127.0.1.1 to I tried:self.wfile.write('<img src="http://'+'192.168.1.61'+':'+ str(port) +'/cam.mjpg"/>') but still I got the same error.

I'm using windows 7 too.

Yet another edit with a simplified version of the whole script.

#====================================================================
# a function to get the image from the camera (this is the only place the camera is accessed)
#====================================================================

def get_cv_frame(): 
    global img                        
    while(1):  
        rc,img = capture.read()        
        if not rc:
            continue                                                     
        return (img)




def cv_frame(frame):

    #all the cv2 movement magic happens and it returns a modified image (numpy array)
    return background




# the server function
def server():    
    global runtime_frame_count, runtime_frame      
    while(1):


        #======================================= server started here
        #=======================================
        server = HTTPServer(('',port),CamHandler)
        #=======================================
        #=======================================

        print ("server started on: ")
        print(socket.gethostbyname(socket.gethostname()))        
        print("server started")
        q1 = cv2.waitKey(20)   
        if (q1 == ord('q')) or (runtime_frame_count >= runtime_frame):                   
            capture.release()
            server.socket.close()
            print("server stopped")        
            cv2.destroyAllWindows()              
            cv2.waitKey(10)
            time.sleep(0.1)
            cv2.waitKey(10)
            cv2.waitKey(10)              
            break    
        server.handle_request()     
    return





class CamHandler(BaseHTTPRequestHandler):

    def do_GET(self):
        print (self.path)
        if self.path.endswith('.mjpg'):
            self.send_response(200)
            self.send_header('Content-type','multipart/x-mixed-replace; boundary=--jpgboundary')
            self.end_headers()
            while(True):
                        global imgRGB
                        r, buf = cv2.imencode(".jpg",imgRGB) # imencode Encodes an image into a memory buffer.

                        self.wfile.write("--jpgboundary\r\n")
                        self.send_header('Content-type','image/jpeg')
                        self.send_header('Content-length',str(len(buf)))
                        self.end_headers()
                        self.wfile.write(bytearray(buf))
                        self.wfile.write('\r\n')
                        time.sleep(0.01)  
                        k = cv2.waitKey(20)
                        if k == 27: 
                            break  
            cv2.destroyAllWindows()
            capture.release()        
            return

        if self.path.endswith('.html') or self.path=="/":# jumps into this block of code at start of request to set up the html page but doesn't come back
            self.send_response(200)
            self.send_header('Content-type','text/html')
            self.end_headers()
            self.wfile.write('<html><head></head><body>')
            self.wfile.write('<img src="http://'+socket.gethostbyname(socket.gethostname())+':'+ str(port) +'/cam.mjpg"/>')
            self.wfile.write('</body></html>')  
            return





# the main function

def main():        
    global capture, average, img, imgRGB, runtime_frame_count, runtime_frame        
    capture = cv2.VideoCapture(0)   
    capture.set(3,REDUCED_SIZE[0])
    capture.set(4,REDUCED_SIZE[1])       
    while(1):      
        img = get_cv_frame() # gets a frame from the camera         
        imgRGB = cv_frame(img) #all the cv2 movement magic happens and it returns a modified image (numpy array)       
        time.sleep(0.1)
        print (runtime_frame_count)
        runtime_frame_count = runtime_frame_count+1            
        q2 = cv2.waitKey(20)             
        if (q2 == ord('q')) or (runtime_frame_count >= runtime_frame):                 
            capture.release()             
            server.socket.close() 
            print("main stopped")     
            cv2.destroyAllWindows()          
            cv2.waitKey(10)
            time.sleep(0.1)
            cv2.waitKey(10)
            cv2.waitKey(10)      
            break     
    return






# this is where the threads are started.
if runtime_frame_count == 0:    
    Thread(target = main).start()# starts the main() function as a thread
    time.sleep(1)
    Thread(target = server).start()# starts the server() function as a new thread a time delay after the first thread was started
  • You said your script is working on your laptop. What OS is running on your laptop? How do you create the "server" socket? – Huygens Jun 29 '15 at 8:31
  • server started on: 127.0.1.1 I think this is your problem, you should be expecting the LAN IP not local host – mrwhale Jul 2 '15 at 2:08
  • Iv'e expanded my question further, based on your questions :) – reggie Jul 2 '15 at 9:59
  • I don't think it is a problem that "127.0.1.1" is displayed, as you only print the IP address corresponding to the host name, and this is not incorrect. But your label "Started server on:" is miss-leading there. Could you tell us when and where do you create the server socket (the call to server = HTTPServer(('',port),CamHandler)? Without seeing your complete code, it is rather difficult to help you. – Huygens Jul 7 '15 at 21:00
  • Hi Huygens, I've given you a simplified version of my code. I've also highlighted where the server socket is created using #=== in the code. – reggie Jul 14 '15 at 13:22
5

I'm no Python expert but I'm surprised that in the server function you create the HTTP socket within the infinite loop. So basically (if I'm not mistaken) you create after each request handling a new server binding. Therefore, I'm not surprised that you get address already in use.

Solution: Try to move the server = HTTPServer(('',port),CamHandler) before while(1):

# the server function
def server():    
    global runtime_frame_count, runtime_frame      
    server = HTTPServer(('',port),CamHandler)
    print ("server started on: ")
    print(socket.gethostbyname(socket.gethostname()))        
    print("server started")
    while(1):
        q1 = cv2.waitKey(20)   
        if (q1 == ord('q')) or (runtime_frame_count >= runtime_frame):                   
            capture.release()
            server.socket.close()
            print("server stopped")        
            cv2.destroyAllWindows()              
            cv2.waitKey(10)
            time.sleep(0.1)
            cv2.waitKey(10)
            cv2.waitKey(10)              
            break    
        server.handle_request()     
    return

Previous answer

Which port are you using?

Is there another application using the same port? You can check the list of used port with this command:

sudo netstat -atpen

And if you know the port number, you can just grep it (e.g. port 8080):

sudo netstat -atpen | grep 8080

Note: sudo will allow you to see the process which is using a particular port. If you don't use sudo, then some processes might not be displayed (but the port usage will be)

PS: I've updated my answer to remove UDP as obviously you are trying to bind a TCP socket.

  • 1
    lsof -i TCP:[port] where [port] is the number is also useful here, presuming this is a TCP socket. – goldilocks Jun 26 '15 at 12:24
  • I'm using port 1991 – reggie Jun 26 '15 at 12:40
  • sudo netstat -atupen | grep 1991 gives udp 0 0 0.0.0.0:123 0.0.0.0:* 0 6488 – reggie Jun 26 '15 at 12:50
  • 2
    @reggie are you sure you did make a typo? I'm asking because your output obviously does not contain 1991... sudo netstat -atpen | grep 1991 – Huygens Jun 26 '15 at 14:06
  • 1
    @reggie Hi I've updated my answer. Check if it helps. – Huygens Jul 14 '15 at 19:03
1

Looks like while terminating / testing the script, your process might not be terminated properly and some part of it still running, occupying the same port.

Here is a quick solution without modifying anything in your script.

Look if any process with the same name is already running by issuing following command.

    ps aux | grep <script-name>

If yes, kill it by

sudo kill -9 <process-id>

Restart the script.

There is another way as per this link.

While creating socket, make use of follwoing option.

sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

By enabling this option, socket will allow reusing the same address even if it's not terminated properly.

Hope it helps.

  • not sure where to add this, should it be just before server = HTTPServer(('',port),CamHandler)? – reggie Jun 26 '15 at 13:41
  • @reggie That's very basic socket setting. Since you're using HTTPServer, it is not advisable to play with its source. – dhruvvyas90 Jun 26 '15 at 16:08
  • Thanks, iv'e removed sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) from my script. – reggie Jun 27 '15 at 5:03
  • @reggie You were supposed to introduce this setting if it were not there not remove it. :| :| – dhruvvyas90 Jun 27 '15 at 7:23
  • I added it, and then removed it :) – reggie Jul 2 '15 at 10:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.