Полный код этого проекта доступен на 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 байт.
Такое поведение повторяется как на локальном хосте, так и на через реальное сетевое соединение.
Изучение TCP-потока поврежденных данных с помощью Wireshark показывает, что:
- На клиенте проблем нет сторона.
- Поврежденные данные соответствуют данным, которые передаются вместе с повторно переданными сегментами данных.
Может ли кто-нибудь объяснить, что не так с моим кодом?
Подробнее здесь: https://stackoverflow.com/questions/788 ... untu-linux