9

When I'm opening a network connection in Python like

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('www.heise.de', 80))

I can read the connection state from the console:

netstat --all --program|grep <PID>
tcp   0  0 10.10.10.6:39328   www.heise.de:http  VERBUNDEN  23829/python

But how can I read this connection state, CONNECTED, CLOSE_WAIT, ... from within Python? Reading through the socket documentation didn't give me any hint on that.

1
  • You are conflating socket state with port state with connection state. No two of these are the same. Commented Jul 28, 2018 at 10:20

3 Answers 3

13

This is only for Linux:

You need getsockopt call. level is "IPPROTO_TCP" and option is "TCP_INFO", as suggested by tcp manual. It is going to return the tcp_info data as defined here where you can also find the enumeration for STATE values.

you can try this sample:

    import socket
    import struct

    def getTCPInfo(s):
        fmt = "B"*7+"I"*21
        x = struct.unpack(fmt, s.getsockopt(socket.IPPROTO_TCP, socket.TCP_INFO, 92))
        print x

    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    getTCPInfo(s)
    s.connect(('www.google.com', 80))
    getTCPInfo(s)
    s.send("hi\n\n")
    getTCPInfo(s)
    s.recv(1024)
    getTCPInfo(s)

what you are looking for is the First item (integer) in the printed tuple. You can cross check the result with the tcp_info definition.

Note: size of tcp_info should be 104 but i got it working with 92, not sure what happened but it worked for me.

Sign up to request clarification or add additional context in comments.

3 Comments

A pity, that there is no more high level function for that. Thanks for pointing out how to do it anyways. The 92 sounds like 7+4*21+1 (terminal 0) for me.
struct.unpack("B"*7+"I"*24, s.getsockopt(socket.SOL_TCP, socket.TCP_INFO, 104)) is more complete according to this
Not sure how popular this is still in 2019, but here are 2 clarifications: 1. Size needs to be a number divisible by 4. Since python would use these 4 "units" to represent one hex. 2. To get the correct size for your machine you need to look into /usr/include/linux/tcp.h and see how many and what type of fields are defined there. u_8 is (1), u_32 is (4), u_64 is (8) and so on. So look what values are you interested in and decode those using unpack. To check the exact size that you need after you get the format right, you can use calcsize() from the struct module.
1

I've just duct-taped together half of a solution for this problem in case Google brings anyone else here.

import urllib2
import psutil

page = urllib2.urlopen(URL) # dummy URL
sock = page.fp              # The socket object that's being held open
fileno = sock.fileno()

proc = psutil.Process()
connections = proc.connections()
matches = [x for x in connections if x.fd == fileno]
if not matches:
    status = None
else:
    assert len(matches) == 1
    match = matches[0]
    status = match.status

What to do once this socket is identified is still TBD.

Comments

0

On Linux, you can use the TCP_INFO option of getsockopt(2) to learn the state of the connection.

1 Comment

s.getsockopt() needs two options, level and option. I suppose, TCP_INFO refers to option. What do I have to use for level? I tried some values, but none works.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.