Чтение поврежденных данных из сокета TCP в Ubuntu LinuxLinux

Ответить Пред. темаСлед. тема
Anonymous
 Чтение поврежденных данных из сокета TCP в Ubuntu Linux

Сообщение Anonymous »

У меня есть очень простое TCP-клиент/серверное приложение, написанное на C.
Полный код этого проекта доступен на github.
Клиентская сторона запускает несколько параллельных потоков, каждый из которых нити сделайте следующее:
  • откройте сокет
  • подключите этот сокет к серверу
  • записать в сокет 16 байт предопределенного шаблона данных кусками случайной длины
  • закрыть сокет
  • повторить шаги с 1 по 4 N раз

Код: Выделить всё

static size_t send_ex(int fd, const uint8_t *buff, size_t len, bool by_frags)
{
if ( by_frags )
{
size_t chunk_len, pos;
size_t res;

for ( pos = 0; pos < len;  )
{
chunk_len = (size_t) random();
chunk_len %= (len - pos);
chunk_len++;

res = send(fd, (const char *) &buff[pos], chunk_len, 0);
if ( res != chunk_len) {
return (size_t) -1;
}

pos += chunk_len;
}

return len;
}

return send(fd, buff, len, 0);
}

static void *connection_task(void *arg)
{
connection_ctx_t *ctx = (connection_ctx_t *) arg;
uint32_t buff[4] = {0xAA55AA55, 0x12345678, 0x12345678, 0x12345678};
int res, fd, i;

for ( i = 0; i < count; i++ )
{
fd = socket(AF_INET, SOCK_STREAM, 0);
if ( fd < 0 ) {
fprintf(stderr, "Can't create socket!\n");
break;
}

res = connect(fd, (struct sockaddr *) ctx->serveraddr, sizeof(struct sockaddr_in));
if ( res < 0 ) {
fprintf(stderr, "Connect failed!\n");
close(fd);
break;
}

res = send_ex(fd, (const char *) buff, sizeof(buff), frags);
if ( res != sizeof(buff) ) {
fprintf(stderr, "Send failed!\n");
close(fd);
break;
}

ctx->sent_packs++;

res = close(fd);
if ( res < 0 ) {
fprintf(stderr, "CLI: Close Failed!!\n");
}

msleep(delay);
}

return NULL;
}

Запуск потока на стороне сервера при каждом входящем соединении, который выполняет следующие действия:
  • считывает данные из подключенного сокета, пока не будут прочитаны все 16 байт
  • после чтения хотя бы первых 4 байтов проверяется, что эти байты соответствуют заданному шаблону.

Код: Выделить всё

typedef struct client_ctx_s {
struct sockaddr_in addr;
int fd;
} client_ctx_t;

void *client_task(void *arg)
{
client_ctx_t *client = (client_ctx_t *) arg;
size_t chunk_len, free_space, pos;
uint32_t buff[4] = {0};
int res;

pos = 0;
while ( pos != sizeof(buff) )
{
free_space = sizeof(buff) - pos;
assert(pos < sizeof(buff));

chunk_len = recv(client->fd, &((uint8_t *) buff)[pos], free_space, 0);
switch ( chunk_len ) {
case (size_t) -1:
fprintf(stderr, "%s:%u: ERROR: recv failed (errno = %d; pos = %zu)!\n",
inet_ntoa(client->addr.sin_addr),
ntohs(client->addr.sin_port),
errno, pos);
goto out;
case 0:
if ( pos && pos < sizeof(buff) ) {
fprintf(stderr, "%s:%u: ERROR: incomplete data block (pos = %zu)!\n",
inet_ntoa(client->addr.sin_addr),
ntohs(client->addr.sin_port),
pos);
}
goto out;
default:
assert(chunk_len = 4 &&  buff[0] != 0xAA55AA55) {
fprintf(stderr, "%s:%u: ERROR: data corrupted (%08x)!\n",
inet_ntoa(client->addr.sin_addr),
ntohs(client->addr.sin_port),
buff[0]);
}
}

fprintf(stdout, "%s:%u: %08x %08x %08x %08x\n",
inet_ntoa(client->addr.sin_addr),
ntohs(client->addr.sin_port),
buff[0], buff[1], buff[2], buff[3]);

out:
debug("Connection closed\n");
res = close(client->fd);
assert(res == 0);
free(client);
return NULL;
}
Проблемы, возникающие, когда клиент запускает тысячу потоков отправки, и каждый из них повторяет соединение-отправку-отключение сто раз (

Код: Выделить всё

./client -t 1000 -c 100 -d 0 -f
):
  • Потеря первых байтов отправленного шаблона.
  • Общий размер отправленных данных из сокета было прочитано соответственно менее 16 байт.
image1
Такое поведение повторяется как на локальном хосте, так и на через реальное сетевое соединение.
Изучение TCP-потока поврежденных данных с помощью Wireshark показывает, что:
  • На клиенте проблем нет сторона.
  • Поврежденные данные соответствуют данным, которые передаются вместе с повторно переданными сегментами данных.
image2Я не могу поверить, что эта проблема связана с реализацией TCP/IP в Linux.
Может ли кто-нибудь объяснить, что не так с моим кодом?

Подробнее здесь: https://stackoverflow.com/questions/788 ... untu-linux
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Linux»