- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我用C写了一个运行在Linux上的单线程异步服务器:套接字是非阻塞的,至于轮询,我使用的是epoll。基准测试显示服务器运行良好,根据 Valgrind 的说法,没有内存泄漏或其他问题。
唯一的问题是当一个write()命令被中断时(因为客户端关闭了连接),服务器会遇到一个EPIPE。我通过使用参数 -b 运行基准测试实用程序“siege”来人为地进行中断。它连续执行大量请求,所有请求都完美运行。现在我按下 CTRL-C 并重新启动“围攻”。有时我很幸运,服务器无法发送完整的响应,因为客户端的 fd 无效。正如预期的那样,errno 被设置为 EPIPE。我处理这种情况,在 fd 上执行 close() 然后释放与连接相关的内存。现在的问题是服务器阻塞并且不再正确回答。这是 strace 输出:
epoll_wait(4, {{EPOLLIN, {u32=0, u64=0}}}, 128, -1) = 1
accept(3, {sa_family=AF_INET, sin_port=htons(55328), sin_addr=inet_addr("127.0.0.1")}, [16]) = 5
fcntl64(5, F_GETFL) = 0x2 (flags O_RDWR)
fcntl64(5, F_SETFL, O_RDWR|O_NONBLOCK) = 0
epoll_ctl(4, EPOLL_CTL_ADD, 5, {EPOLLIN|EPOLLERR|EPOLLHUP|EPOLLET, {u32=144039912, u64=144039912}}) = 0
epoll_wait(4, {{EPOLLIN, {u32=144039912, u64=144039912}}}, 128, -1) = 1
read(5, "GET /user/register HTTP/1.1\r\nHos"..., 4096) = 161
send(5, "HTTP/1.1 200 OK\r\nContent-Type: t"..., 106, MSG_NOSIGNAL) = 106 <<<<
send(5, "00001000\r\n", 10, MSG_NOSIGNAL) = -1 EPIPE (Broken pipe) <<<< Why did the previous send() work?
close(5) = 0
epoll_wait(4, {{EPOLLIN, {u32=0, u64=0}}}, 128, -1) = 1
accept(3, {sa_family=AF_INET, sin_port=htons(55329), sin_addr=inet_addr("127.0.0.1")}, [16]) = 5
...
(如果您想知道,我从日志中删除了 printf())
如您所见,客户端建立了一个新连接,该连接随后被接受。然后,它被添加到 EPOLL 队列中。 epoll_wait() 表示客户端发送了数据 (EPOLLIN)。解析请求并组成响应。发送 header 工作正常,但当涉及正文时,write() 会导致 EPIPE。这不是“围攻”中的错误,因为它会阻止任何传入连接,无论来自哪个客户端。
#include "Connection.h"
static ExceptionManager *exc;
void Connection0(ExceptionManager *e) {
exc = e;
}
void Connection_Init(Connection *this) {
Socket_Init(&this->server);
Socket_SetReusableFlag(&this->server);
Socket_SetCloexecFlag(&this->server, true);
Socket_SetBlockingFlag(&this->server, true);
Socket_ListenTCP(&this->server, 8080, SOMAXCONN);
// Add the server socket to epoll
Poll_Init(&this->poll, SOMAXCONN, (void *) &Connection_OnEvent, this);
Poll_AddEvent(&this->poll, NULL, this->server.fd, EPOLLIN | EPOLLET | EPOLLHUP | EPOLLERR);
this->activeConn = 0;
}
void Connection_Destroy(Connection *this) {
Poll_Destroy(&this->poll);
Socket_Destroy(&this->server);
}
void Connection_Process(Connection *this) {
Poll_Process(&this->poll, -1);
}
void Connection_AcceptClient(Connection *this) {
Client *client;
SocketConnection conn = Socket_Accept(&this->server);
SocketConnection_SetBlockingFlag(&conn, true);
client = New(Client);
client->req = NULL;
client->conn = New(SocketConnection);
client->conn->remote = conn.remote;
client->conn->fd = conn.fd;
this->activeConn++;
Poll_AddEvent(&this->poll, client, conn.fd, EPOLLIN | EPOLLET | EPOLLHUP | EPOLLERR);
}
void Connection_DestroyClient(Connection *this, Client *client) {
// Poll_DeleteEvent(&this->poll, client->conn->fd);
SocketConnection_Close(client->conn);
if (client->req != NULL) {
Request_Destroy(client->req);
Memory_Free(client->req);
}
if (client->conn != NULL) {
Memory_Free(client->conn);
}
Memory_Free(client);
this->activeConn--;
}
void Connection_OnEvent(Connection *this, int events, Client *client) {
/* error or connection hung up */
if (client != NULL && (events & (EPOLLHUP | EPOLLERR))) {
String_Print(String("EPOLLHUP | EPOLLERR received\n"));
Connection_DestroyClient(this, client);
return;
}
/* incoming connection */
if (client == NULL && (events & EPOLLIN)) {
if (this->activeConn > SOMAXCONN - 1) { /* TODO */
String_Print(String("Too many connections...\n"));
return;
}
Connection_AcceptClient(this);
return;
}
/* receiving data from client */
if (client != NULL && (events & EPOLLIN)) {
if (client->req == NULL) {
client->req = New(Request);
Request_Init(client->req, client->conn);
}
bool keepOpen = false;
try (exc) {
keepOpen = Request_Parse(client->req);
} catch(&SocketConnection_PipeException, e) {
printf("Caught PipeException on fd=%d\n", client->conn->fd); fflush(stdout);
} catch(&SocketConnection_ConnectionResetException, e) {
printf("Caught ConnectionResetException on fd=%d\n", client->conn->fd); fflush(stdout);
} finally {
if (!keepOpen) {
printf("Will close...\n"); fflush(stdout);
Connection_DestroyClient(this, client);
}
} tryEnd;
}
}
最佳答案
使用sigaction()
将 SIGPIPE
的操作设置为 SIG_IGN
。然后你只会得到-1的返回码,errno
设置为EPIPE
,没有信号。
在 Linux 上,另一种方法是使用 send()
使用 MSG_NOSIGNAL
标志,而不是 write()
。这允许您抑制该写入的信号,而不影响任何其他信号。 BSD 系统上的替代方案是 SO_NOSIGPIPE
套接字选项,它会抑制对该套接字上的所有写入的 SIGPIPE
。
内核 TCP 实现可以随时从对等方接收 TCP RST。该点之后套接字上的下一次写入将导致 EPIPE
错误,如果未被抑制,则将导致 SIGPIPE
信号。因此,即使连续两次写入,第一次也可能成功,而下一次可能因 EPIPE 和 SIGPIPE 而失败。
更新:虽然它不是已发布代码的一部分,但我在您的 strace 输出中看到您正在调用 fcntl64(5, F_SETFL, O_RDONLY|O_NONBLOCK)
。由于 O_RDONLY
为 0,您的代码可能只是将标志设置为 O_NONBLOCK
。它应该获取当前标志,然后将其设置为 OldFlags | O_NONBLOCK
为了设置非阻塞模式。将套接字设置为只读模式似乎很可能在写入时引起问题。或者可能是您不小心使用了 F_GETFD
而不是 F_GETFL
来获取旧标志。
关于c - EPIPE block 服务器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2534357/
我的 blockly.js 文件中有以下代码 Blockly.Blocks['account_number'] = { // Other type. init: function() {
首先抱歉我的英语不好,我正在开发 Image Splitter 应用程序并且已经完成,但是现在的要求是当图像被分割(分成几 block /chunks)那么图像 block 的每一 block (ch
#value: 消息的返回值,当发送到一个 block 时,是该 block 中最后一句话的值。所以 [ 1 + 2. 3 + 4. ] value 计算结果为 7。我发现有时很难使用。有没有办法显式
我想构建一个包含 3 div 的响应式导航栏相同的 width和 height . 我申请了 inline-block到每个 block ,我得到一个我不理解的行为。 问题是,第三 block 由 2
我希望使用 Blockly 来允许非技术人员用户指定测试脚本。 它的一部分需要一个文件选择器,但是,我看不到 Blockly 有一个。是吗? 实际上,我找不到完整的标准 block 列表。谁有网址?
仅当您位于父 block 内部时,父 block 的 props.isSelected 才为 true,但当您在该 block 的 innerBlocks 内进行编辑时则不然。 如何从父 block
仅当您位于父 block 内部时,父 block 的 props.isSelected 才为 true,但当您在该 block 的 innerBlocks 内进行编辑时则不然。 如何从父 block
我想创建一个具有不同背景颜色 block 和不同悬停颜色 block 的导航栏 block 。我可以分别创建不同的悬停颜色 block 或不同的背景颜色 block ,但不能一起创建。所以请告诉我如何
我正在使用看到的代码 here定期执行代码: #define DELAY_IN_MS 1000 __block dispatch_time_t next = dispatch_time(DISPATC
为什么 block 必须被复制而不是保留?两者在引擎盖下有什么区别?在什么情况下不需要复制 block (如果有)? 最佳答案 通常,当您分配一个类的实例时,它会进入堆并一直存在,直到它被释放。但是,
我想弄清楚我这样做是否正确: 如果我有一个 block ,我会这样做: __weak MyClass *weakSelf = self; [self performBlock:^{
我想制作一个 4 block 导航菜单,虽然我已经显示了一个 block ,然后单击打开第二个 block ,从第二个开始选择并再次单击出现第三个 block ,第四个 block 相同...这是我的
例如,这样更好吗? try { synchronized (bean) { // Write something } } catch (Int
我想让一只乌龟检查前方小块的颜色并决定移动到哪里。如果前面的补丁不是白色的,那么乌龟向左或向右旋转并移动。我的 If 决策结构中出现错误,显示“此处应为 TRUE?FALSE,而不是 block 列表
我想创建一个 block 对角矩阵,其中对角 block 重复一定次数,非对角 block 都是零矩阵。例如,假设我们从一个矩阵开始: > diag.matrix [,1] [,2] [
我是区 block 链新手。突然我有一个问题,我们是否可以通过区 block 号来访问以太坊区 block 链上之前的区 block 数据。 例如我创建了一个block1、block2。 block
我是区 block 链新手。突然我有一个问题,我们是否可以通过区 block 号来访问以太坊区 block 链上之前的区 block 数据。 例如我创建了一个block1、block2。 block
我创建了一个等距环境,全部使用 Javascript 和 HTML5 (2D Canvas),大部分情况下工作正常。我面临的问题是使用不同高度的图 block ,然后对图 block 上的对象索引进行
这是令我困惑的代码: public Integer getInteger(BlockingQueue queue) { boolean interrupted = false; try
我有一个基于 TPL 数据流的应用程序,它仅使用批处理 block 和操作 block 就可以正常工作。 我已经添加了一个 TransformBlock 以尝试在发布到批处理 block 之前从源中转
我是一名优秀的程序员,十分优秀!