diff --git a/src/lua/bsdsocket.lua b/src/lua/bsdsocket.lua
index ab3ae58eb8e648f9787934644653b9a5dc98ba27..d5431929955fd8f468c1d930bab71634e06ec3c6 100644
--- a/src/lua/bsdsocket.lua
+++ b/src/lua/bsdsocket.lua
@@ -500,19 +500,11 @@ socket_methods.accept = function(self)
     return socket
 end
 
-socket_methods.read = function(self, size, timeout)
-    if timeout == nil then
-        timeout = TIMEOUT_INFINITY
-    end
-
+local function readchunk(self, size, timeout)
     if self.rbuf == nil then
         self.rbuf = ''
     end
 
-    if size == nil then
-        size = 4294967295
-    end
-
     if string.len(self.rbuf) >= size then
         self._errno = nil
         local data = string.sub(self.rbuf, 1, size)
@@ -574,34 +566,11 @@ local function readline_check(self, eols, limit)
     return nil
 end
 
-socket_methods.readline = function(self, limit, eol, timeout)
-    if type(limit) == 'table' then -- :readline({eol}[, timeout ])
-        if eol ~= nil then
-            timeout = eol
-            eol = limit
-            limit = nil
-        else
-            eol = limit
-            limit = nil
-        end
-    elseif eol ~= nil then
-        if type(eol) ~= 'table' then
-            eol = { eol }
-        end
-    end
-
-    if timeout == nil then
-        timeout = TIMEOUT_INFINITY
-    end
-
+local function readline(self, limit, eol, timeout)
     if self.rbuf == nil then
         self.rbuf = ''
     end
 
-    if limit == nil then
-        limit = 4294967295
-    end
-
     self._errno = nil
     local data = readline_check(self, eol, limit)
     if data ~= nil then
@@ -651,6 +620,26 @@ socket_methods.readline = function(self, limit, eol, timeout)
     end
 end
 
+socket_methods.read = function(self, opts, timeout)
+    timeout = timeout and tonumber(timeout) or TIMEOUT_INFINITY
+    if type(opts) == 'number' then
+        return readchunk(self, opts, timeout)
+    elseif type(opts) == 'string' then
+        return readline(self, 4294967295, { opts }, timeout)
+    elseif type(opts) == 'table' then
+        local chunk = opts.chunk or opts.size or 4294967295
+        local delimiter = opts.delimiter or opts.line
+        if delimiter == nil then
+            return readchunk(self, chunk, timeout)
+        elseif type(delimiter) == 'string' then
+            return readline(self, chunk, { delimiter }, timeout)
+        elseif type(delimiter) == 'table' then
+            return readline(self, chunk, delimiter, timeout)
+        end
+    end
+    error('Usage: s:read(delimiter|chunk|{delimiter = x, chunk = x}, timeout)')
+end
+
 socket_methods.write = function(self, octets, timeout)
     if timeout == nil then
         timeout = TIMEOUT_INFINITY
diff --git a/test/box/bsdsocket.result b/test/box/bsdsocket.result
index aff05e6d658b3b98293ea2597cfe4e37b4d216ad..845e1e3d4f4e0318c936ff607fb312beecd664ed 100644
--- a/test/box/bsdsocket.result
+++ b/test/box/bsdsocket.result
@@ -386,20 +386,20 @@ lua sc:send("\nnew line")
 ---
  - true
 ...
-lua sa:readline({'\n'}, 1)
+lua sa:read('\n', 1)
 ---
  - Hello, world
 
 ...
-lua sa:readline(1, {'ine'}, 1)
+lua sa:read({chunk = 1, line = 'ine'}, 1)
 ---
  - n
 ...
-lua sa:readline({'ine'}, 1)
+lua sa:read('ine', 1)
 ---
  - ew line
 ...
-lua sa:readline({'ine'}, 0.1)
+lua sa:read('ine', 0.1)
 ---
  - nil
 ...
@@ -407,7 +407,7 @@ lua sc:send('Hello, world')
 ---
  - true
 ...
-lua sa:readline({','}, 1)
+lua sa:read(',', 1)
 ---
  - Hello,
 ...
@@ -715,7 +715,7 @@ lua s:write('HEAD / HTTP/1.0\r\nHost: tarantool.org\r\n\r\n')
 ---
  - true
 ...
-lua header = s:readline(4000, { '\n\n', '\r\n\r\n' }, 1)
+lua header = s:read({chunk = 4000, line = { '\n\n', '\r\n\r\n' }}, 1)
 ---
 ...
 lua string.match(header, '\r\n\r\n$') ~= nil
@@ -855,3 +855,145 @@ lua s:error()
 ---
  - Connection timed out
 ...
+lua path = '/tmp/tarantool-test-socket'
+---
+...
+lua s = box.socket('PF_UNIX', 'SOCK_STREAM', 'ip')
+---
+...
+lua s:setsockopt('SOL_SOCKET', 'SO_REUSEADDR', true)
+---
+ - true
+...
+lua s:error()
+---
+ - nil
+...
+lua s:bind('unix/', path)
+---
+ - true
+...
+lua s:error()
+---
+ - nil
+...
+lua s:listen(128)
+---
+ - true
+...
+lua f = box.fiber.wrap(function() for i=1,2 do s:readable() local sc = s:accept(); sc:write('ok!'); sc:shutdown(); sc:close() end end)
+---
+...
+lua c = box.socket.tcp_connect('unix/', path)
+---
+...
+lua c:error()
+---
+ - nil
+...
+lua x = c:read('!')
+---
+...
+lua x, type(x), #x
+---
+ - ok!
+ - string
+ - 3
+...
+lua x = c:read('!')
+---
+...
+lua c:error()
+---
+ - nil
+...
+lua x, type(x), #x
+---
+ - 
+ - string
+ - 0
+...
+lua x = c:read('!')
+---
+...
+lua c:error()
+---
+ - nil
+...
+lua x, type(x), #x
+---
+ - 
+ - string
+ - 0
+...
+lua c:close()
+---
+ - true
+...
+lua c = box.socket.tcp_connect('unix/', path)
+---
+...
+lua c:error()
+---
+ - nil
+...
+lua x = c:read(3)
+---
+...
+lua c:error()
+---
+ - nil
+...
+lua x, type(x), #x
+---
+ - ok!
+ - string
+ - 3
+...
+lua x = c:read(1)
+---
+...
+lua c:error()
+---
+ - nil
+...
+lua x, type(x), #x
+---
+ - 
+ - string
+ - 0
+...
+lua x = c:read(1)
+---
+...
+lua c:error()
+---
+ - nil
+...
+lua x, type(x), #x
+---
+ - 
+ - string
+ - 0
+...
+lua x = c:sysread(1)
+---
+...
+lua c:error()
+---
+ - nil
+...
+lua x, type(x), #x
+---
+ - 
+ - string
+ - 0
+...
+lua c:close()
+---
+ - true
+...
+lua s:close()
+---
+ - true
+...
diff --git a/test/box/bsdsocket.test b/test/box/bsdsocket.test
index c29876d7f0b052ebd30d8c0c28b152056c36a6ef..8ca6a8931eae214d21e5c72b5b4a50c950205ae7 100644
--- a/test/box/bsdsocket.test
+++ b/test/box/bsdsocket.test
@@ -117,13 +117,13 @@ exec admin "lua sa:recv()"
 exec admin "lua sc:send('Hello')"
 exec admin "lua sc:send(', world')"
 exec admin "lua sc:send(\"\\nnew line\")"
-exec admin "lua sa:readline({'\\n'}, 1)"
-exec admin "lua sa:readline(1, {'ine'}, 1)"
-exec admin "lua sa:readline({'ine'}, 1)"
-exec admin "lua sa:readline({'ine'}, 0.1)"
+exec admin "lua sa:read('\\n', 1)"
+exec admin "lua sa:read({chunk = 1, line = 'ine'}, 1)"
+exec admin "lua sa:read('ine', 1)"
+exec admin "lua sa:read('ine', 0.1)"
 
 exec admin "lua sc:send('Hello, world')"
-exec admin "lua sa:readline({','}, 1)"
+exec admin "lua sa:read(',', 1)"
 exec admin "lua sc:shutdown('W')"
 exec admin "lua sa:read(100, 1)"
 exec admin "lua sa:read(100, 1)"
@@ -223,7 +223,7 @@ exec admin "lua s = box.socket.tcp_connect('tarantool.org', 80)"
 exec admin "lua string.match(tostring(s), ', aka') ~= nil"
 exec admin "lua string.match(tostring(s), ', peer') ~= nil"
 exec admin "lua s:write('HEAD / HTTP/1.0\\r\\nHost: tarantool.org\\r\\n\\r\\n')"
-exec admin "lua header = s:readline(4000, { '\\n\\n', '\\r\\n\\r\\n' }, 1)"
+exec admin "lua header = s:read({chunk = 4000, line = { '\\n\\n', '\\r\\n\\r\\n' }}, 1)"
 exec admin "lua string.match(header, '\\r\\n\\r\\n$') ~= nil"
 # exec admin "lua string.match(header, '200 [Oo][Kk]') ~= nil"
 exec admin "lua s:close()"
@@ -272,3 +272,47 @@ exec admin "lua box.fiber.sleep(.1)"
 exec admin "lua s:close()"
 exec admin "lua ch:get(1)"
 exec admin "lua s:error()"
+
+path = '/tmp/tarantool-test-socket'
+if os.path.exists(path):
+        os.unlink(path)
+exec admin "lua path = '%s'" % path
+exec admin "lua s = box.socket('PF_UNIX', 'SOCK_STREAM', 'ip')"
+exec admin "lua s:setsockopt('SOL_SOCKET', 'SO_REUSEADDR', true)"
+exec admin "lua s:error()"
+exec admin "lua s:bind('unix/', path)"
+exec admin "lua s:error()"
+exec admin "lua s:listen(128)"
+exec admin "lua f = box.fiber.wrap(function() for i=1,2 do s:readable() local sc = s:accept(); sc:write('ok!'); sc:shutdown(); sc:close() end end)"
+
+exec admin "lua c = box.socket.tcp_connect('unix/', path)"
+exec admin "lua c:error()"
+exec admin "lua x = c:read('!')"
+exec admin "lua x, type(x), #x"
+exec admin "lua x = c:read('!')"
+exec admin "lua c:error()"
+exec admin "lua x, type(x), #x"
+exec admin "lua x = c:read('!')"
+exec admin "lua c:error()"
+exec admin "lua x, type(x), #x"
+exec admin "lua c:close()"
+
+exec admin "lua c = box.socket.tcp_connect('unix/', path)"
+exec admin "lua c:error()"
+exec admin "lua x = c:read(3)"
+exec admin "lua c:error()"
+exec admin "lua x, type(x), #x"
+exec admin "lua x = c:read(1)"
+exec admin "lua c:error()"
+exec admin "lua x, type(x), #x"
+exec admin "lua x = c:read(1)"
+exec admin "lua c:error()"
+exec admin "lua x, type(x), #x"
+exec admin "lua x = c:sysread(1)"
+exec admin "lua c:error()"
+exec admin "lua x, type(x), #x"
+exec admin "lua c:close()"
+
+exec admin "lua s:close()"
+
+os.unlink(path)