An operation was attempted on something that is not a socket (tried fixing a lot)

15,547

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.

Share:
15,547
Will
Author by

Will

Updated on June 07, 2022

Comments

  • Will
    Will almost 2 years

    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())
    
  • Eryk Sun
    Eryk Sun about 8 years
    For Python 3, ctypes.pythonapi._PyOS_SigintEvent() returns the handle for a Windows event that gets set for SIGINT. Append this to the handle array to allow the WaitForMultipleObjects call to be interruptible by Ctrl+C. Python 3's _winapi.WaitForMultipleObjects does this for you, but only if don't ask it to wait for all objects, since it wouldn't make sense to require waiting for Ctrl+C.