You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

106 lines
2.4 KiB

Как узнать, что TCP полностью завершился?
В raw API прямого callback'а вида:
on_connection_closed()
нет.
Обычно используют собственное состояние:
struct conn {
bool closing;
};
и после успешного:
tcp_close(pcb);
conn->closing = true;
считают соединение закрытым для приложения.
Сам TCP завершится позже внутри lwIP.
А вызовется ли err callback?
Обычно нет.
tcp_err()
вызывается при ненормальном завершении:
RST
abort
потеря PCB
сетевые ошибки
но не при штатном FIN/ACK закрытии.
Нужно ли освобождать память после tcp_close()?
Сам pcb освобождать нельзя:
tcp_close(pcb);
/* НЕЛЬЗЯ */
mem_free(pcb);
lwIP сделает это самостоятельно.
Но ваши данные (arg) нужно освободить самостоятельно.
Обычно так:
struct my_conn *c = arg;
tcp_arg(pcb, NULL);
free(c);
tcp_close(pcb);
или
free(c);
tcp_close(pcb);
pcb = NULL;
если после этого код больше не обращается к c.
Безопасная практика
После успешного tcp_close():
if (tcp_close(pcb) == ERR_OK) {
pcb = NULL;
}
и считать объект недействительным.
Потому что lwIP может уничтожить его в любой момент по мере завершения TCP state machine.
Типичный шаблон
static void close_conn(struct my_conn *c)
{
err_t err;
err = tcp_close(c->pcb);
if (err == ERR_OK) {
c->pcb = NULL;
free(c);
} else {
/* ERR_MEM -> попробуем позже */
}
}
Но если free(c) делается сразу, нужно быть уверенным, что никакие callback'и lwIP больше не используют arg. Часто перед закрытием сначала снимают callback'и:
tcp_arg(pcb, NULL);
tcp_recv(pcb, NULL);
tcp_sent(pcb, NULL);
tcp_err(pcb, NULL);
а затем вызывают tcp_close().
Это особенно важно в сложных приложениях с собственными структурами соединений.