We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
attach is causing an "Invalid Argument" exception from os.read
``` python
stream = client.attach(container, stream=True, stdout=True, stderr=True)
for chunk in stream:
    pass
```

Results in:

```
  File "/Users/michael/work/oss/marina/marina/build.py", line 695, in watcher
    for chunk in stream:
  File ".venv/lib/python3.5/site-packages/docker/utils/socket.py", line 67, in frames_iter
    yield read(socket, n)
  File ".venv/lib/python3.5/site-packages/docker/utils/socket.py", line 25, in read
    return os.read(socket.fileno(), n)
OSError: [Errno 22] Invalid argument
```

Using docker-py 1.10.2 on OS X 10.11.6 with docker for mac 1.12.0-rc3. Reverting to 1.9.0 fixes the issue.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `docker/utils/socket.py`
Content:
```
1 import errno
2 import os
3 import select
4 import struct
5 
6 import six
7 
8 try:
9     from ..transport import NpipeSocket
10 except ImportError:
11     NpipeSocket = type(None)
12 
13 
14 class SocketError(Exception):
15     pass
16 
17 
18 def read(socket, n=4096):
19     """
20     Reads at most n bytes from socket
21     """
22 
23     recoverable_errors = (errno.EINTR, errno.EDEADLK, errno.EWOULDBLOCK)
24 
25     # wait for data to become available
26     if not isinstance(socket, NpipeSocket):
27         select.select([socket], [], [])
28 
29     try:
30         if hasattr(socket, 'recv'):
31             return socket.recv(n)
32         return os.read(socket.fileno(), n)
33     except EnvironmentError as e:
34         if e.errno not in recoverable_errors:
35             raise
36 
37 
38 def read_exactly(socket, n):
39     """
40     Reads exactly n bytes from socket
41     Raises SocketError if there isn't enough data
42     """
43     data = six.binary_type()
44     while len(data) < n:
45         next_data = read(socket, n - len(data))
46         if not next_data:
47             raise SocketError("Unexpected EOF")
48         data += next_data
49     return data
50 
51 
52 def next_frame_size(socket):
53     """
54     Returns the size of the next frame of data waiting to be read from socket,
55     according to the protocol defined here:
56 
57     https://docs.docker.com/engine/reference/api/docker_remote_api_v1.24/#/attach-to-a-container
58     """
59     try:
60         data = read_exactly(socket, 8)
61     except SocketError:
62         return 0
63 
64     _, actual = struct.unpack('>BxxxL', data)
65     return actual
66 
67 
68 def frames_iter(socket):
69     """
70     Returns a generator of frames read from socket
71     """
72     n = next_frame_size(socket)
73     while n > 0:
74         yield read(socket, n)
75         n = next_frame_size(socket)
76
```
--- 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/docker/utils/socket.py b/docker/utils/socket.py
--- a/docker/utils/socket.py
+++ b/docker/utils/socket.py
@@ -69,7 +69,11 @@
     """
     Returns a generator of frames read from socket
     """
-    n = next_frame_size(socket)
-    while n > 0:
-        yield read(socket, n)
+    while True:
         n = next_frame_size(socket)
+        if n == 0:
+            break
+        while n > 0:
+            result = read(socket, n)
+            n -= len(result)
+            yield result

{"golden_diff": "diff --git a/docker/utils/socket.py b/docker/utils/socket.py\n--- a/docker/utils/socket.py\n+++ b/docker/utils/socket.py\n@@ -69,7 +69,11 @@\n     \"\"\"\n     Returns a generator of frames read from socket\n     \"\"\"\n-    n = next_frame_size(socket)\n-    while n > 0:\n-        yield read(socket, n)\n+    while True:\n         n = next_frame_size(socket)\n+        if n == 0:\n+            break\n+        while n > 0:\n+            result = read(socket, n)\n+            n -= len(result)\n+            yield result\n", "issue": "attach is causing an \"Invalid Argument\" exception from os.read\n``` python\nstream = client.attach(container, stream=True, stdout=True, stderr=True)\nfor chunk in stream:\n    pass\n```\n\nResults in:\n\n```\n  File \"/Users/michael/work/oss/marina/marina/build.py\", line 695, in watcher\n    for chunk in stream:\n  File \".venv/lib/python3.5/site-packages/docker/utils/socket.py\", line 67, in frames_iter\n    yield read(socket, n)\n  File \".venv/lib/python3.5/site-packages/docker/utils/socket.py\", line 25, in read\n    return os.read(socket.fileno(), n)\nOSError: [Errno 22] Invalid argument\n```\n\nUsing docker-py 1.10.2 on OS X 10.11.6 with docker for mac 1.12.0-rc3. Reverting to 1.9.0 fixes the issue.\n\n", "before_files": [{"content": "import errno\nimport os\nimport select\nimport struct\n\nimport six\n\ntry:\n    from ..transport import NpipeSocket\nexcept ImportError:\n    NpipeSocket = type(None)\n\n\nclass SocketError(Exception):\n    pass\n\n\ndef read(socket, n=4096):\n    \"\"\"\n    Reads at most n bytes from socket\n    \"\"\"\n\n    recoverable_errors = (errno.EINTR, errno.EDEADLK, errno.EWOULDBLOCK)\n\n    # wait for data to become available\n    if not isinstance(socket, NpipeSocket):\n        select.select([socket], [], [])\n\n    try:\n        if hasattr(socket, 'recv'):\n            return socket.recv(n)\n        return os.read(socket.fileno(), n)\n    except EnvironmentError as e:\n        if e.errno not in recoverable_errors:\n            raise\n\n\ndef read_exactly(socket, n):\n    \"\"\"\n    Reads exactly n bytes from socket\n    Raises SocketError if there isn't enough data\n    \"\"\"\n    data = six.binary_type()\n    while len(data) < n:\n        next_data = read(socket, n - len(data))\n        if not next_data:\n            raise SocketError(\"Unexpected EOF\")\n        data += next_data\n    return data\n\n\ndef next_frame_size(socket):\n    \"\"\"\n    Returns the size of the next frame of data waiting to be read from socket,\n    according to the protocol defined here:\n\n    https://docs.docker.com/engine/reference/api/docker_remote_api_v1.24/#/attach-to-a-container\n    \"\"\"\n    try:\n        data = read_exactly(socket, 8)\n    except SocketError:\n        return 0\n\n    _, actual = struct.unpack('>BxxxL', data)\n    return actual\n\n\ndef frames_iter(socket):\n    \"\"\"\n    Returns a generator of frames read from socket\n    \"\"\"\n    n = next_frame_size(socket)\n    while n > 0:\n        yield read(socket, n)\n        n = next_frame_size(socket)\n", "path": "docker/utils/socket.py"}], "after_files": [{"content": "import errno\nimport os\nimport select\nimport struct\n\nimport six\n\ntry:\n    from ..transport import NpipeSocket\nexcept ImportError:\n    NpipeSocket = type(None)\n\n\nclass SocketError(Exception):\n    pass\n\n\ndef read(socket, n=4096):\n    \"\"\"\n    Reads at most n bytes from socket\n    \"\"\"\n\n    recoverable_errors = (errno.EINTR, errno.EDEADLK, errno.EWOULDBLOCK)\n\n    # wait for data to become available\n    if not isinstance(socket, NpipeSocket):\n        select.select([socket], [], [])\n\n    try:\n        if hasattr(socket, 'recv'):\n            return socket.recv(n)\n        return os.read(socket.fileno(), n)\n    except EnvironmentError as e:\n        if e.errno not in recoverable_errors:\n            raise\n\n\ndef read_exactly(socket, n):\n    \"\"\"\n    Reads exactly n bytes from socket\n    Raises SocketError if there isn't enough data\n    \"\"\"\n    data = six.binary_type()\n    while len(data) < n:\n        next_data = read(socket, n - len(data))\n        if not next_data:\n            raise SocketError(\"Unexpected EOF\")\n        data += next_data\n    return data\n\n\ndef next_frame_size(socket):\n    \"\"\"\n    Returns the size of the next frame of data waiting to be read from socket,\n    according to the protocol defined here:\n\n    https://docs.docker.com/engine/reference/api/docker_remote_api_v1.24/#/attach-to-a-container\n    \"\"\"\n    try:\n        data = read_exactly(socket, 8)\n    except SocketError:\n        return 0\n\n    _, actual = struct.unpack('>BxxxL', data)\n    return actual\n\n\ndef frames_iter(socket):\n    \"\"\"\n    Returns a generator of frames read from socket\n    \"\"\"\n    while True:\n        n = next_frame_size(socket)\n        if n == 0:\n            break\n        while n > 0:\n            result = read(socket, n)\n            n -= len(result)\n            yield result\n", "path": "docker/utils/socket.py"}]}