We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Locust insists on using IPv6 despite being in an IPv4 stack.
### Prerequisites

- [X] I am using [the latest version of Locust](https://github.com/locustio/locust/releases/)
- [X] I am reporting a bug, not asking a question

### Description

I have an environment that is IPv4-only, but there is an IPv6 address listed in /etc/hosts. When I try to connect to the master using the following command, it results in an error:

```
# locust -f ./p4_basic_code.py --worker --master-host locust-master -L DEBUG
[2024-04-25 06:24:31,138] ip-192-168-0-235.ap-northeast-3.compute.internal/DEBUG/locust.runners: Failed to connect to master locust-master:5557, retry 1/60.
```

By changing [self.socket.setsockopt(zmq.IPV6, 1)](https://github.com/locustio/locust/blob/master/locust/rpc/zmqrpc.py#L18) to 0 resolves the issue.
```
# cat /etc/hosts
127.0.0.1 localhost
192.168.0.235 ip-192-168-0-235.ap-northeast-3.compute.internal
127.255.0.1 locust-master
2600:f0f0:0:0:0:0:0:1 locust-master
```

I recommend detecting whether the current environment supports IPv6 before enabling it.

### Command line

locust -f ./p4_basic_code.py --worker --master-host locust-master -L DEBUG

### Locustfile contents

```python3
N/A
```


### Python version

3.11

### Locust version

2.26.0

### Operating system

Debian 12

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `locust/rpc/zmqrpc.py`
Content:
```
1 from locust.exception import RPCError, RPCReceiveError, RPCSendError
2 from locust.util.exception_handler import retry
3 
4 import msgpack.exceptions as msgerr
5 import zmq.error as zmqerr
6 import zmq.green as zmq
7 
8 from .protocol import Message
9 
10 
11 class BaseSocket:
12     def __init__(self, sock_type):
13         context = zmq.Context()
14         self.socket = context.socket(sock_type)
15 
16         self.socket.setsockopt(zmq.TCP_KEEPALIVE, 1)
17         self.socket.setsockopt(zmq.TCP_KEEPALIVE_IDLE, 30)
18         self.socket.setsockopt(zmq.IPV6, 1)
19 
20     @retry()
21     def send(self, msg):
22         try:
23             self.socket.send(msg.serialize(), zmq.NOBLOCK)
24         except zmqerr.ZMQError as e:
25             raise RPCSendError("ZMQ sent failure") from e
26 
27     @retry()
28     def send_to_client(self, msg):
29         try:
30             self.socket.send_multipart([msg.node_id.encode(), msg.serialize()])
31         except zmqerr.ZMQError as e:
32             raise RPCSendError("ZMQ sent failure") from e
33 
34     def recv(self):
35         try:
36             data = self.socket.recv()
37             msg = Message.unserialize(data)
38         except msgerr.ExtraData as e:
39             raise RPCReceiveError("ZMQ interrupted message") from e
40         except zmqerr.ZMQError as e:
41             raise RPCError("ZMQ network broken") from e
42         return msg
43 
44     def recv_from_client(self):
45         try:
46             data = self.socket.recv_multipart()
47             addr = data[0].decode()
48         except UnicodeDecodeError as e:
49             raise RPCReceiveError("ZMQ interrupted or corrupted message") from e
50         except zmqerr.ZMQError as e:
51             raise RPCError("ZMQ network broken") from e
52         try:
53             msg = Message.unserialize(data[1])
54         except (UnicodeDecodeError, msgerr.ExtraData) as e:
55             raise RPCReceiveError("ZMQ interrupted or corrupted message", addr=addr) from e
56         return addr, msg
57 
58     def close(self, linger=None):
59         self.socket.close(linger=linger)
60 
61 
62 class Server(BaseSocket):
63     def __init__(self, host, port):
64         BaseSocket.__init__(self, zmq.ROUTER)
65         if port == 0:
66             self.port = self.socket.bind_to_random_port(f"tcp://{host}")
67         else:
68             try:
69                 self.socket.bind("tcp://%s:%i" % (host, port))
70                 self.port = port
71             except zmqerr.ZMQError as e:
72                 raise RPCError(f"Socket bind failure: {e}")
73 
74 
75 class Client(BaseSocket):
76     def __init__(self, host, port, identity):
77         BaseSocket.__init__(self, zmq.DEALER)
78         self.socket.setsockopt(zmq.IDENTITY, identity.encode())
79         self.socket.connect("tcp://%s:%i" % (host, port))
80
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/locust/rpc/zmqrpc.py b/locust/rpc/zmqrpc.py
--- a/locust/rpc/zmqrpc.py
+++ b/locust/rpc/zmqrpc.py
@@ -4,6 +4,7 @@
 import msgpack.exceptions as msgerr
 import zmq.error as zmqerr
 import zmq.green as zmq
+from urllib3.util.connection import HAS_IPV6
 
 from .protocol import Message
 
@@ -15,7 +16,8 @@
 
         self.socket.setsockopt(zmq.TCP_KEEPALIVE, 1)
         self.socket.setsockopt(zmq.TCP_KEEPALIVE_IDLE, 30)
-        self.socket.setsockopt(zmq.IPV6, 1)
+        if HAS_IPV6:
+            self.socket.setsockopt(zmq.IPV6, 1)
 
     @retry()
     def send(self, msg):

{"golden_diff": "diff --git a/locust/rpc/zmqrpc.py b/locust/rpc/zmqrpc.py\n--- a/locust/rpc/zmqrpc.py\n+++ b/locust/rpc/zmqrpc.py\n@@ -4,6 +4,7 @@\n import msgpack.exceptions as msgerr\n import zmq.error as zmqerr\n import zmq.green as zmq\n+from urllib3.util.connection import HAS_IPV6\n \n from .protocol import Message\n \n@@ -15,7 +16,8 @@\n \n         self.socket.setsockopt(zmq.TCP_KEEPALIVE, 1)\n         self.socket.setsockopt(zmq.TCP_KEEPALIVE_IDLE, 30)\n-        self.socket.setsockopt(zmq.IPV6, 1)\n+        if HAS_IPV6:\n+            self.socket.setsockopt(zmq.IPV6, 1)\n \n     @retry()\n     def send(self, msg):\n", "issue": "Locust insists on using IPv6 despite being in an IPv4 stack.\n### Prerequisites\r\n\r\n- [X] I am using [the latest version of Locust](https://github.com/locustio/locust/releases/)\r\n- [X] I am reporting a bug, not asking a question\r\n\r\n### Description\r\n\r\nI have an environment that is IPv4-only, but there is an IPv6 address listed in /etc/hosts. When I try to connect to the master using the following command, it results in an error:\r\n\r\n```\r\n# locust -f ./p4_basic_code.py --worker --master-host locust-master -L DEBUG\r\n[2024-04-25 06:24:31,138] ip-192-168-0-235.ap-northeast-3.compute.internal/DEBUG/locust.runners: Failed to connect to master locust-master:5557, retry 1/60.\r\n```\r\n\r\nBy changing [self.socket.setsockopt(zmq.IPV6, 1)](https://github.com/locustio/locust/blob/master/locust/rpc/zmqrpc.py#L18) to 0 resolves the issue.\r\n```\r\n# cat /etc/hosts\r\n127.0.0.1 localhost\r\n192.168.0.235 ip-192-168-0-235.ap-northeast-3.compute.internal\r\n127.255.0.1 locust-master\r\n2600:f0f0:0:0:0:0:0:1 locust-master\r\n```\r\n\r\nI recommend detecting whether the current environment supports IPv6 before enabling it.\r\n\r\n### Command line\r\n\r\nlocust -f ./p4_basic_code.py --worker --master-host locust-master -L DEBUG\r\n\r\n### Locustfile contents\r\n\r\n```python3\r\nN/A\r\n```\r\n\r\n\r\n### Python version\r\n\r\n3.11\r\n\r\n### Locust version\r\n\r\n2.26.0\r\n\r\n### Operating system\r\n\r\nDebian 12\n", "before_files": [{"content": "from locust.exception import RPCError, RPCReceiveError, RPCSendError\nfrom locust.util.exception_handler import retry\n\nimport msgpack.exceptions as msgerr\nimport zmq.error as zmqerr\nimport zmq.green as zmq\n\nfrom .protocol import Message\n\n\nclass BaseSocket:\n    def __init__(self, sock_type):\n        context = zmq.Context()\n        self.socket = context.socket(sock_type)\n\n        self.socket.setsockopt(zmq.TCP_KEEPALIVE, 1)\n        self.socket.setsockopt(zmq.TCP_KEEPALIVE_IDLE, 30)\n        self.socket.setsockopt(zmq.IPV6, 1)\n\n    @retry()\n    def send(self, msg):\n        try:\n            self.socket.send(msg.serialize(), zmq.NOBLOCK)\n        except zmqerr.ZMQError as e:\n            raise RPCSendError(\"ZMQ sent failure\") from e\n\n    @retry()\n    def send_to_client(self, msg):\n        try:\n            self.socket.send_multipart([msg.node_id.encode(), msg.serialize()])\n        except zmqerr.ZMQError as e:\n            raise RPCSendError(\"ZMQ sent failure\") from e\n\n    def recv(self):\n        try:\n            data = self.socket.recv()\n            msg = Message.unserialize(data)\n        except msgerr.ExtraData as e:\n            raise RPCReceiveError(\"ZMQ interrupted message\") from e\n        except zmqerr.ZMQError as e:\n            raise RPCError(\"ZMQ network broken\") from e\n        return msg\n\n    def recv_from_client(self):\n        try:\n            data = self.socket.recv_multipart()\n            addr = data[0].decode()\n        except UnicodeDecodeError as e:\n            raise RPCReceiveError(\"ZMQ interrupted or corrupted message\") from e\n        except zmqerr.ZMQError as e:\n            raise RPCError(\"ZMQ network broken\") from e\n        try:\n            msg = Message.unserialize(data[1])\n        except (UnicodeDecodeError, msgerr.ExtraData) as e:\n            raise RPCReceiveError(\"ZMQ interrupted or corrupted message\", addr=addr) from e\n        return addr, msg\n\n    def close(self, linger=None):\n        self.socket.close(linger=linger)\n\n\nclass Server(BaseSocket):\n    def __init__(self, host, port):\n        BaseSocket.__init__(self, zmq.ROUTER)\n        if port == 0:\n            self.port = self.socket.bind_to_random_port(f\"tcp://{host}\")\n        else:\n            try:\n                self.socket.bind(\"tcp://%s:%i\" % (host, port))\n                self.port = port\n            except zmqerr.ZMQError as e:\n                raise RPCError(f\"Socket bind failure: {e}\")\n\n\nclass Client(BaseSocket):\n    def __init__(self, host, port, identity):\n        BaseSocket.__init__(self, zmq.DEALER)\n        self.socket.setsockopt(zmq.IDENTITY, identity.encode())\n        self.socket.connect(\"tcp://%s:%i\" % (host, port))\n", "path": "locust/rpc/zmqrpc.py"}], "after_files": [{"content": "from locust.exception import RPCError, RPCReceiveError, RPCSendError\nfrom locust.util.exception_handler import retry\n\nimport msgpack.exceptions as msgerr\nimport zmq.error as zmqerr\nimport zmq.green as zmq\nfrom urllib3.util.connection import HAS_IPV6\n\nfrom .protocol import Message\n\n\nclass BaseSocket:\n    def __init__(self, sock_type):\n        context = zmq.Context()\n        self.socket = context.socket(sock_type)\n\n        self.socket.setsockopt(zmq.TCP_KEEPALIVE, 1)\n        self.socket.setsockopt(zmq.TCP_KEEPALIVE_IDLE, 30)\n        if HAS_IPV6:\n            self.socket.setsockopt(zmq.IPV6, 1)\n\n    @retry()\n    def send(self, msg):\n        try:\n            self.socket.send(msg.serialize(), zmq.NOBLOCK)\n        except zmqerr.ZMQError as e:\n            raise RPCSendError(\"ZMQ sent failure\") from e\n\n    @retry()\n    def send_to_client(self, msg):\n        try:\n            self.socket.send_multipart([msg.node_id.encode(), msg.serialize()])\n        except zmqerr.ZMQError as e:\n            raise RPCSendError(\"ZMQ sent failure\") from e\n\n    def recv(self):\n        try:\n            data = self.socket.recv()\n            msg = Message.unserialize(data)\n        except msgerr.ExtraData as e:\n            raise RPCReceiveError(\"ZMQ interrupted message\") from e\n        except zmqerr.ZMQError as e:\n            raise RPCError(\"ZMQ network broken\") from e\n        return msg\n\n    def recv_from_client(self):\n        try:\n            data = self.socket.recv_multipart()\n            addr = data[0].decode()\n        except UnicodeDecodeError as e:\n            raise RPCReceiveError(\"ZMQ interrupted or corrupted message\") from e\n        except zmqerr.ZMQError as e:\n            raise RPCError(\"ZMQ network broken\") from e\n        try:\n            msg = Message.unserialize(data[1])\n        except (UnicodeDecodeError, msgerr.ExtraData) as e:\n            raise RPCReceiveError(\"ZMQ interrupted or corrupted message\", addr=addr) from e\n        return addr, msg\n\n    def close(self, linger=None):\n        self.socket.close(linger=linger)\n\n\nclass Server(BaseSocket):\n    def __init__(self, host, port):\n        BaseSocket.__init__(self, zmq.ROUTER)\n        if port == 0:\n            self.port = self.socket.bind_to_random_port(f\"tcp://{host}\")\n        else:\n            try:\n                self.socket.bind(\"tcp://%s:%i\" % (host, port))\n                self.port = port\n            except zmqerr.ZMQError as e:\n                raise RPCError(f\"Socket bind failure: {e}\")\n\n\nclass Client(BaseSocket):\n    def __init__(self, host, port, identity):\n        BaseSocket.__init__(self, zmq.DEALER)\n        self.socket.setsockopt(zmq.IDENTITY, identity.encode())\n        self.socket.connect(\"tcp://%s:%i\" % (host, port))\n", "path": "locust/rpc/zmqrpc.py"}]}