Skip to content

Commit 84c7062

Browse files
committed
Optimize Socket::sendfile()
1 parent 90d3e4c commit 84c7062

File tree

8 files changed

+82
-22
lines changed

8 files changed

+82
-22
lines changed

core-tests/src/network/client.cpp

+53
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ using swoole::Pipe;
1010
using swoole::Socks5Proxy;
1111
using swoole::String;
1212
using swoole::network::AsyncClient;
13+
using swoole::network::SyncClient;
1314
using swoole::network::Client;
1415
using swoole::test::create_http_proxy;
1516
using swoole::test::create_socks5_proxy;
@@ -249,6 +250,58 @@ TEST(client, ssl_1) {
249250
ASSERT_TRUE(buf.contains("Baidu"));
250251
}
251252

253+
TEST(client, ssl_sendfile) {
254+
bool connected = false;
255+
bool closed = false;
256+
String buf(65536);
257+
258+
swoole_event_init(SW_EVENTLOOP_WAIT_EXIT);
259+
260+
auto file = swoole::make_tmpfile();
261+
file.write(SW_STRL(TEST_REQUEST_BAIDU));
262+
263+
Client client(SW_SOCK_TCP, true);
264+
client.enable_ssl_encrypt();
265+
client.onConnect = [&connected, &file](Client *cli) {
266+
connected = true;
267+
cli->sendfile(cli, file.get_path().c_str(), 0, file.get_size());
268+
};
269+
270+
client.onError = [](Client *cli) {};
271+
client.onClose = [&closed](Client *cli) { closed = true; };
272+
client.onReceive = [&buf](Client *cli, const char *data, size_t length) { buf.append(data, length); };
273+
274+
ASSERT_EQ(client.connect(&client, TEST_DOMAIN_BAIDU, 443, -1, 0), 0);
275+
276+
swoole_event_wait();
277+
278+
ASSERT_TRUE(connected);
279+
ASSERT_TRUE(closed);
280+
ASSERT_TRUE(buf.contains("Baidu"));
281+
}
282+
283+
TEST(client, sync_ssl_sendfile) {
284+
auto file = swoole::make_tmpfile();
285+
file.write(SW_STRL(TEST_REQUEST_BAIDU));
286+
287+
SyncClient client(SW_SOCK_TCP);
288+
ASSERT_TRUE(client.connect(TEST_DOMAIN_BAIDU, 443, -1));
289+
ASSERT_TRUE(client.enable_ssl_encrypt());
290+
ASSERT_TRUE(client.sendfile(file.get_path().c_str()));
291+
292+
String buf(65536);
293+
while (true) {
294+
ssize_t nr = client.recv(buf.str, buf.size - buf.length);
295+
if (nr <= 0) {
296+
break;
297+
}
298+
buf.grow(nr);
299+
}
300+
client.close();
301+
ASSERT_TRUE(buf.contains("baidu.com"));
302+
unlink(file.get_path().c_str());
303+
}
304+
252305
static void proxy_async_test(Client &client, bool https) {
253306
swoole_event_init(SW_EVENTLOOP_WAIT_EXIT);
254307

include/swoole_client.h

+4
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,10 @@ class SyncClient {
309309
return client.send(&client, buf, len, 0);
310310
}
311311

312+
bool sendfile(const char *filename, off_t offset = 0, size_t length = 0) {
313+
return client.sendfile(&client, filename, offset, length) == SW_OK;
314+
}
315+
312316
ssize_t recv(char *buf, size_t len) {
313317
return client.recv(&client, buf, len, 0);
314318
}

include/swoole_file.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -162,11 +162,11 @@ class File {
162162
fd_ = -1;
163163
}
164164

165-
int get_fd() {
165+
int get_fd() const {
166166
return fd_;
167167
}
168168

169-
const std::string &get_path() {
169+
const std::string &get_path() const {
170170
return path_;
171171
}
172172

include/swoole_socket.h

+4-5
Original file line numberDiff line numberDiff line change
@@ -325,10 +325,10 @@ struct Socket {
325325
return !(retval == 0 || (retval < 0 && catch_read_error(errno) == SW_CLOSE));
326326
}
327327

328-
/**
329-
* socket io operation
330-
*/
331-
int sendfile(const char *filename, off_t offset, size_t length);
328+
int sendfile_async(const char *filename, off_t offset, size_t length);
329+
int sendfile_blocking(const char *filename, off_t offset, size_t length, double timeout);
330+
ssize_t sendfile(const File &fp, off_t *offset, size_t length);
331+
332332
ssize_t recv(void *__buf, size_t __n, int __flags);
333333
ssize_t send(const void *__buf, size_t __n, int __flags);
334334
ssize_t peek(void *__buf, size_t __n, int __flags);
@@ -355,7 +355,6 @@ struct Socket {
355355
ssize_t send_blocking(const void *__data, size_t __len);
356356
ssize_t send_async(const void *__data, size_t __len);
357357
ssize_t recv_blocking(void *__data, size_t __len, int flags);
358-
int sendfile_blocking(const char *filename, off_t offset, size_t length, double timeout);
359358
ssize_t writev_blocking(const struct iovec *iov, size_t iovcnt);
360359

361360
int connect(const Address &sa) {

src/coroutine/socket.cc

+1-8
Original file line numberDiff line numberDiff line change
@@ -1325,14 +1325,7 @@ bool Socket::sendfile(const char *filename, off_t offset, size_t length) {
13251325
ssize_t n, sent_bytes;
13261326
while ((size_t) offset < length) {
13271327
sent_bytes = (length - offset > SW_SENDFILE_CHUNK_SIZE) ? SW_SENDFILE_CHUNK_SIZE : length - offset;
1328-
#ifdef SW_USE_OPENSSL
1329-
if (socket->ssl) {
1330-
n = socket->ssl_sendfile(file, &offset, sent_bytes);
1331-
} else
1332-
#endif
1333-
{
1334-
n = ::swoole_sendfile(sock_fd, file.get_fd(), &offset, sent_bytes);
1335-
}
1328+
n = socket->sendfile(file, &offset, sent_bytes);
13361329
if (n > 0) {
13371330
continue;
13381331
} else if (n == 0) {

src/network/client.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -728,7 +728,7 @@ static int Client_tcp_sendfile_sync(Client *cli, const char *filename, off_t off
728728
}
729729

730730
static int Client_tcp_sendfile_async(Client *cli, const char *filename, off_t offset, size_t length) {
731-
if (cli->socket->sendfile(filename, offset, length) < 0) {
731+
if (cli->socket->sendfile_async(filename, offset, length) < 0) {
732732
swoole_set_last_error(errno);
733733
return SW_ERR;
734734
}

src/network/socket.cc

+16-5
Original file line numberDiff line numberDiff line change
@@ -105,12 +105,12 @@ int Socket::sendfile_blocking(const char *filename, off_t offset, size_t length,
105105

106106
ssize_t n, sent_bytes;
107107
while (offset < (off_t) length) {
108-
if (wait_event(timeout_ms, SW_EVENT_WRITE) < 0) {
109-
return SW_ERR;
110-
}
111108
sent_bytes = (length - offset > SW_SENDFILE_CHUNK_SIZE) ? SW_SENDFILE_CHUNK_SIZE : length - offset;
112-
n = ::swoole_sendfile(fd, file.get_fd(), &offset, sent_bytes);
109+
n = sendfile(file, &offset, sent_bytes);
113110
if (n <= 0) {
111+
if (errno == EAGAIN && wait_event(timeout_ms, ssl_want_read ? SW_EVENT_READ : SW_EVENT_WRITE) < 0) {
112+
return SW_ERR;
113+
}
114114
swoole_sys_warning("sendfile(%d, %s) failed", fd, filename);
115115
return SW_ERR;
116116
}
@@ -649,7 +649,18 @@ static void Socket_sendfile_destructor(BufferChunk *chunk) {
649649
delete task;
650650
}
651651

652-
int Socket::sendfile(const char *filename, off_t offset, size_t length) {
652+
ssize_t Socket::sendfile(const File &fp, off_t *offset, size_t length) {
653+
#ifdef SW_USE_OPENSSL
654+
if (ssl) {
655+
return ssl_sendfile(fp, offset, length);
656+
} else
657+
#endif
658+
{
659+
return ::swoole_sendfile(fd, fp.get_fd(), offset, length);
660+
}
661+
}
662+
663+
int Socket::sendfile_async(const char *filename, off_t offset, size_t length) {
653664
std::unique_ptr<SendfileRequest> task(new SendfileRequest(filename, offset, length));
654665
if (!task->file.ready()) {
655666
swoole_sys_warning("open(%s) failed", filename);

src/server/master.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1441,7 +1441,7 @@ int Server::send_to_connection(SendData *_send) {
14411441
// sendfile to client
14421442
else if (_send->info.type == SW_SERVER_EVENT_SEND_FILE) {
14431443
SendfileTask *task = (SendfileTask *) _send_data;
1444-
if (conn->socket->sendfile(task->filename, task->offset, task->length) < 0) {
1444+
if (conn->socket->sendfile_async(task->filename, task->offset, task->length) < 0) {
14451445
return false;
14461446
}
14471447
}

0 commit comments

Comments
 (0)