2013-08-09 2 views
0

Я пытаюсь написать очень простую программу на C. По какой-то причине я не могу использовать writeFileEx и recvfrom в той же программе, что и каждый вызов writeFileEx заставляет recvfrom сбой.Windows writeFileEx и recvfrom Программа сбоев

Вот соответствующий фрагмент код

struct sockaddr_in server, client_address; 
int client_length, recv_len; 
char buf[BUFLEN]; 
WSADATA wsa; 
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0) 
{ 
    //Error 
} 

SOCKET s = socket (AF_INET, SOCK_DGRAM, 0); 
if (s == INVALID_SOCKET) 
{ 
//invalid socket error 
} 

server.sin_family = AF_INET; 
server.sin_addr.s_addr= INADDR_ANY; 
server.sin_port = htons (PORT); 

if (bind(s, (stuct sockaddr*) &server, sizeof(server)) == SOCKET_ERROR) 
{ 
    //bind error 
} 

OVERLAPPED ovWrite; 
memset(&ovWrite,0,sizeof(ovWrite)); 
ovWrite.offset=0; 
ovWrite.OffsetHigh=0; 
ovWrite.hEvent = CreateEvent (0,TRUE,0,0); 

memset(buf,'\0',BUFLEN); 


while (1) 
{ 
    if (!recvfrom(s, buf, BUFLEN,0,(struct sockaddr *) &client_address, &client_length) 
    { 
    fprintf(stderr, "Recvfrom Failed %d\n", WSAGetlastError()); 
    } 

    if (!WriteFileEx(serialHandle, buf, strlen(buf),&ovWrite,NULL)) 
    { 
    fprintf(stderr, "Error writing to COM port %d\n", GetlastError()); 
    } 
    memset(buf,'\0', BUFLEN); 
} 

Я использую LCC компилятор, и в результате программа падает на второй итерации цикла с нарушением прав доступа 0xc0000005. Когда я заменяю recvfrom другим источником ввода, таким как stdin, программа работает нормально. Это известная проблема или два вызова функций просто не могут существовать вместе?

+0

«Это известная проблема или два вызова функций просто не могут существовать вместе?» - нет. У вашего кода есть ошибки. –

+0

Почему адрес процедуры завершения NULL? –

+0

Я сделал это как можно более минималистским, чтобы устранить любые ошибки, но все равно сбой. Можете ли вы определить ошибку в приведенном выше фрагменте? – user2667394

ответ

0

recvfrom() не добавить '\0' к buf, так по крайней мере(), если recvfrom() читает BUFLEN байт, или при первом вызове, если buf не инициализируется за пределами вашего кода snipplet, вызывая strlen() вызывает UB. Кроме того, ваш if(recvfrom(...)) ошибочен, потому что в случае успеха `recvfrom() возвращает количество полученных байтов, поэтому условие будет истинным. Вместо этого, вы можете сделать это так:

size_t received; 

.... 

if ((received = recvfrom(s, buf, BUFLEN,0,(struct sockaddr *) &client_addres, &client_length)) <= 0) 
{ 
    fprintf(stderr, "Recvfrom Failed %d\n", WSAGetlastError()); 
} 

if (!WriteFileEx(serialHandle, buf, received,&ovWrite,NULL)) 
{ 
    fprintf(stderr, "Error writing to COM port %d\n", GetlastError()); 
} 
+0

IIRC, WriteFileEx() требует действительного указателя подпрограммы завершения, а не NULL. –

+0

@Martin James: Я просто искал google: последний параметр 'lpOverlapped' может быть' NULL', если файл не был открыт с 'FILE_FLAG_OVERLAPPED' –

+0

Извините, действительный код if (! Recvfrom (....)) – user2667394

0

ОК, я назначу себя доставку ответ :) Некоторые моменты:

1) В отличие от WASRecv, скажем, WriteFileEx() всегда требует действительного завершения чтобы вызвать завершение асинхронного вызова записи. Для этого вызова недоступны другие механизмы сигнализации, такие как использование hEvent synchro. Передача NULL, скорее всего, приведет к AV.

2) В общем, сообщения UDP могут быть любой длины 0..64K. recvFrom() возвращает фактическую длину такого сообщения, и это значение должно использоваться для его обработки - не любой вызов BUFFER_LEN или strlen() (см. ответ Ingo :).

3) Стек IP может обрабатывать одновременно блокировку, считываемую из одного потока, и запись от другого - не обязательно использовать асинхронный, перекрываемый ввод-вывод.

4) Если вы собираетесь использовать перекрывающиеся ввода-вывода, настоятельно рекомендуется использовать другой блок и буфер OVL для каждого вызова - в общем, несколько операций перекрытия могут быть поставлены в очередь в одно и то же время, и они должны каждый из них имеет свой собственный буфер/OVL. Я использую malloced struct (или, если C++, новый экземпляр класса) или * структуру, выделенную из пула, для каждого вызова, чтобы обеспечить это. Строка/экземпляр может быть фид/удалена/повторно использована в процедуре завершения после обработки (или помещена в очередь с потоком и обрабатывается/освобождается/удаляется/повторно перенаправляется позже, в другом месте).

5) Поток, который хочет выполнять перекрывающиеся ввода-вывода с процедурами завершения, должен выглядеть как цикл вокруг одного из предупреждающих ожидающих вызовов. WaitForSingleObjectEx() удобен, так как он может ждать на семафоре, который формирует основу очереди производителей-потребителей предупреждающим образом, позволяя другим потокам сигнализировать команды/буферы/все в потоке, выполняющем перекрывающиеся ввода-вывода.

Смежные вопросы