У меня возникли некоторые проблемы с AF_UNIX
обменом сокетами, потому что после записи буфера данных, кажется, остаются некоторые зависающие байты, чтобы прочитать, что я не знаю, откуда они берутся.
Я пишу многопоточный серверПрограмма на C, которая общается с клиентами через AF_UNIX
сокетов, должна реализовывать простой чат.Помимо прочего, сервер должен осуществлять передачу файлов между клиентами и серверами, и у меня возникли проблемы при попытке отправить довольно большой файл (269 КБ) с сервера на клиент.(С файлами меньшего размера у меня нет проблем)
Для передачи файлов я использую функцию mmap()
, которая возвращает указатель на карту файла, который я хочу отправить, затем я использую write()
для записи, чтоданные на сокете связаны с клиентом, который должен получить файл.После вызова write()
я проверяю возвращаемое значение на размер файла.(всегда проверено)
Клиент, после получения файла, проверяет размер прочитанных данных (всегда проверяется) и начинает ждать других сообщений, поэтому он вызывает блокировку read()
. Это - это точка, в которой я обнаружил ошибку, потому что клиент читает что-то, чего не должно быть, , как будто что-то осталось прочитать в сокете .Я отлаживал эту часть (как серверную, так и клиентскую) в течение двух дней, и я пока не смог понять причину проблемы.
Я уверен, что ни один другой поток не пишет в один и тот же сокет в одно и то же время
Кто-нибудь из вас имеет представление о причине этой ошибки?
Я пытаюсь опубликовать некоторый полезный код, думая о нормальной последовательности операций:
Прежде всего структура сообщения:
struct message_hdr
{
op_t op;
char sender[MAX_NAME_LENGTH+1];
};
struct message_data_hdr{
char receiver[MAX_NAME_LENGTH+1];
unsigned int len;
};
struct message_data
{
message_data_hdr_t hdr;
char *buf;
};
struct message
{
message_hdr_t hdr;
message_data_t data;
};
Сервер-> клиентская передача файла начинается ссервер, который отправляет message_hdr_t
клиенту, ожидающему read()
(клиент ожидает получить только message_hdr_t
).
int sendHeader(long fd, message_hdr_t* hdr)
{
if(hdr == NULL || fd < 0) {errno = EINVAL; return -1;}
int test;
struct iovec iov;
iov.iov_base = hdr;
iov.iov_len = sizeof(message_hdr_t);
test = writev(fd, &iov, 1);
return test;
}
Клиент понимает из кода операции (message.hdr.op
) что это сообщение типа файла и оно начинает ждать файла,
Итак, сервер отправляет его:
int sendData(long fd, message_data_t *msg)
{
if(msg == NULL || fd < 0) {errno = EINVAL; return -1;}
int test;
struct iovec iov;
iov.iov_base = &(msg->hdr);
iov.iov_len = sizeof(message_data_hdr_t);
test = writev(fd, &(iov), 1);
if(test == -1){return -1;}
if (msg->hdr.len != 0)
{
test = write(fd, msg->buf, msg->hdr.len);
if(test <= 0)
return -1;
}
return test;
}
И клиент читает его:
int readData(long fd, message_data_t *data)
{
if(data == NULL || fd < 0) {errno = EINVAL; return -1;}
int test;
struct iovec iov;
iov.iov_base = &(data->hdr);
iov.iov_len = sizeof(message_data_hdr_t);
test = readv(fd, &iov, 1);
if(test <= 0){return -1;}
if(data->hdr.len != 0)
{
data->buf = malloc(data->hdr.len);
if(data->buf == NULL){return -1;}
test = read(fd, data->buf, data->hdr.len);
if((unsigned int)test != data->hdr.len)
return -1;
}
return test;
}
В этот момент клиент получил файл и перезапустил его в ожидании новых сообщений:
int readMsg(long fd, message_t *msg)
{
if(msg == NULL || fd < 0) {errno = EINVAL; return -1;}
int test;
test = readHeader(fd, &(msg->hdr));
if(test == -1 || test == 0){return -1;}
test += readData(fd, &(msg->data));
return test;
}
Это точка, в которой клиент должен просто ждать, потому что нет сообщений о доходах, в этом случае он что-то читаетчто я не знаю, откуда это.
Когда я пытаюсьраспечатайте это нежелательное сообщение с помощью GDB:
{hdr = {op = 512,
sender = "\000\000\020G\032\324\t\000\000\n\000\000\000\000\030\021B\bC\n\000\000\v\000\000\000\000\021D\v\222\000"},
data = {hdr = {receiver = "\000\000\000\000\021E\022C\n\000\000\b\v\000\000\000\000\021F\020I\n\000\000\020\000\006\b\002\n\000\000\006",
len = 131072},
buf = 0x7ffff7f2f010 ""}`
Конечно, это бессмысленно.
Я надеюсь, что это описание будет полезно
Спасибо всем заранее.