Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

socket.connect_ex return wrongly #125632

Closed
chosen-ox opened this issue Oct 17, 2024 · 12 comments
Closed

socket.connect_ex return wrongly #125632

chosen-ox opened this issue Oct 17, 2024 · 12 comments
Assignees
Labels
stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error

Comments

@chosen-ox
Copy link

chosen-ox commented Oct 17, 2024

Bug report

Bug description:

# client.py
import socket
import time
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# s.setblocking(0)
while True:
    err = s.connect_ex(('localhost', 10128))
    print(err)
    time.sleep(3)
    
#server.py
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('localhost', 10128))
s.listen()

According to connect_ex doc, it should return 0 if connection is successful. Here I start client first and keep connect_ex to test if it connects successfully.
When I start server, the connect_ex should succeed and return 0. However, if nonblocking is set on client socket, it will return non-zero even if the connection is successful. If nonblocking is not set, it works good.

CPython versions tested on:

3.11

Operating systems tested on:

Windows

@chosen-ox chosen-ox added the type-bug An unexpected behavior, bug, or error label Oct 17, 2024
@zware
Copy link
Member

zware commented Oct 17, 2024

In your server.py, there is no s.accept(); the script just ends without ever actually making a connection. If you add print(s.accept()) to the end of your server.py, does it then work as expected?

@chosen-ox
Copy link
Author

In your server.py, there is no s.accept(); the script just ends without ever actually making a connection. If you add print(s.accept()) to the end of your server.py, does it then work as expected?

Sry, I did not cite all of my server code. Here is the whole file

# server.py
sockets = [s]
while True:
    readable, writable, exceptional = select.select(sockets, [], sockets)
    for s in readable:
        if s is sockets[0]:
            conn, addr = s.accept()
            sockets.append(conn)
            print("Connected to ", addr)
        else:
            data = s.recv(1024)
            if data:
                print("Received data: ", data)
            else:
                print("Connection closed")
                s.close()
                sockets.remove(s)
                continue
        for s in exceptional:
            print("Exceptional condition")
            s.close()
            sockets.remove(s)
            continue

Actually, the server will know the connection is built. But connect_ex returns abnormally if nonblocking is set.

@Zheaoli
Copy link
Contributor

Zheaoli commented Oct 17, 2024

Confirm this issue is exist on main branch.

Plz assign this issue to me, I will find the root cause

@ZeroIntensity
Copy link
Member

Plz assign this issue to me, I will find the root cause

I see you requested assignment here as well: #125641

Typically, assignment isn't necessary--just leave a comment saying that you're working on it, and that's enough to prevent someone from beating you to it (you don't need to be assigned to the issue to submit a PR). But first, it's a good idea to ask the issue author if they would like to author the fix. I'll assign this to you because we need contributors, but let's not make this a habit :)

Please ping me if you would like to have your assignment removed--some issues are more complicated than they originally seem.

@ZeroIntensity ZeroIntensity added the stdlib Python modules in the Lib dir label Oct 17, 2024
@Zheaoli
Copy link
Contributor

Zheaoli commented Oct 18, 2024

I think this not a bug, is excepted behavior

EINPROGRESS
              The socket is nonblocking and the connection cannot be
              completed immediately.  (UNIX domain sockets failed with
              EAGAIN instead.)  It is possible to [select(2)](https://man7.org/linux/man-pages/man2/select.2.html) or [poll(2)](https://man7.org/linux/man-pages/man2/poll.2.html)
              for completion by selecting the socket for writing.  After
              [select(2)](https://man7.org/linux/man-pages/man2/select.2.html) indicates writability, use [getsockopt(2)](https://man7.org/linux/man-pages/man2/getsockopt.2.html) to read
              the SO_ERROR option at level SOL_SOCKET to determine
              whether connect() completed successfully (SO_ERROR is
              zero) or unsuccessfully (SO_ERROR is one of the usual
              error codes listed here, explaining the reason for the
              failure).

FYI https://man7.org/linux/man-pages/man2/connect.2.html

@chosen-ox
Copy link
Author

I think this not a bug, is excepted behavior

EINPROGRESS
              The socket is nonblocking and the connection cannot be
              completed immediately.  (UNIX domain sockets failed with
              EAGAIN instead.)  It is possible to [select(2)](https://man7.org/linux/man-pages/man2/select.2.html) or [poll(2)](https://man7.org/linux/man-pages/man2/poll.2.html)
              for completion by selecting the socket for writing.  After
              [select(2)](https://man7.org/linux/man-pages/man2/select.2.html) indicates writability, use [getsockopt(2)](https://man7.org/linux/man-pages/man2/getsockopt.2.html) to read
              the SO_ERROR option at level SOL_SOCKET to determine
              whether connect() completed successfully (SO_ERROR is
              zero) or unsuccessfully (SO_ERROR is one of the usual
              error codes listed here, explaining the reason for the
              failure).

FYI https://man7.org/linux/man-pages/man2/connect.2.html

So if I set socket to nonblocking. I cannot use that connect_ex returns 0 to check whether there is a successful connection? If so, this should be written in connect_ex doc.

@Zheaoli
Copy link
Contributor

Zheaoli commented Oct 18, 2024

We have already describe the behavior in the documents

Like connect(address), but return an error indicator instead of raising an exception for errors returned by the C-level connect() call (other problems, such as “host not found,” can still raise exceptions).

In your circumstance, if you try to use connect directly, an exception will be raised BlockingIOError: [Errno 115] Operation now in progress. And when you use connect_ex, you will get the code 115

@chosen-ox
Copy link
Author

We have already describe the behavior in the documents

Like connect(address), but return an error indicator instead of raising an exception for errors returned by the C-level connect() call (other problems, such as “host not found,” can still raise exceptions).

In your circumstance, if you try to use connect directly, an exception will be raised BlockingIOError: [Errno 115] Operation now in progress. And when you use connect_ex, you will get the code 115

If I run the client with blocking, and then I run the server. I can get a 0 same as the connect_ex doc.
image

If I run the client with nonblocking, and then I run the server. I cannot get the 0.
image

According to my search, code 10061 means Connection Refused. 10056 means A connection attempt targeted an already connected socket. So 0 between these two code is indicating a successful connection.

10035 means Resource temporarily unavailable. There should be a 0 between 10035 and 10056 in nonblocking situation.

I don't think the doc talks about this thing.

@Zheaoli
Copy link
Contributor

Zheaoli commented Oct 18, 2024

10056 is the Windows error code. FYI https://learn.microsoft.com/en-us/windows/win32/winsock/windows-sockets-error-codes-2. This part is not belong to CPython. In connect_ex, we just use syscall directly and return the error code

@chosen-ox
Copy link
Author

chosen-ox commented Oct 18, 2024

10056 is the Windows error code. FYI https://learn.microsoft.com/en-us/windows/win32/winsock/windows-sockets-error-codes-2. This part is not belong to CPython. In connect_ex, we just use syscall directly and return the error code

I just test same code on linux. Both blocking and nonblocking situation can output a 0. So this is a bug when using connect_ex on windows with nonblocking socket. I think this should be mentioned in connect_ex description for other users.

Thank you for your time and help!

@ZeroIntensity
Copy link
Member

Thank you for dealing with this @Zheaoli! Should this get closed?

@Zheaoli
Copy link
Contributor

Zheaoli commented Oct 18, 2024

Thank you for dealing with this @Zheaoli! Should this get closed?

I think this issue should be closed. We can not take care all the behavior of the syscall under the API. The developer need to take care of the detail from the document which is belong to the platform they are using

@ZeroIntensity ZeroIntensity closed this as not planned Won't fix, can't repro, duplicate, stale Oct 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

4 participants