Windows writeFileEx和recvfrom Crashes程序

时间:2013-08-09 10:00:39

标签: c windows sockets serial-port

我正在尝试编写一个非常简单的C程序。出于某种原因,我不能在同一个程序中使用writeFileEx和recvfrom,因为每次调用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的循环的第二次迭代时崩溃。 当我用另一个输入源如stdin替换recvfrom时,程序运行正常。 这是一个已知问题还是2个函数调用根本不能一起存在?

2 个答案:

答案 0 :(得分:0)

recvfrom()未向'\0'添加buf,因此至少()如果recvfrom()读取BUFLEN个字节,或在第一次调用时,如果buf未在代码片段之外初始化,则调用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());
}

答案 1 :(得分:0)

好的,我会提升自己的答案:)一些要点:

1)与WASRecv不同,例如,WriteFileEx()总是需要一个有效的完成例程来回调异步写调用的完成。其他信令机制(如使用hEvent synchro)不适用于此调用。传递NULL可能会导致AV。

2)通常,UDP消息可以是任何长度0..64K。 recvFrom()返回此类消息的实际长度,该值应该用于处理它 - 而不是任何BUFFER_LEN或strlen()调用(参见Ingo答案:)。

3)IP堆栈可以同时处理来自一个线程的阻塞读取和来自另一个线程的写入 - 并非必须采用异步,重叠的I / O.

4)如果您打算使用重叠I / O,强烈建议为每次调用使用不同的OVL块和缓冲区 - 通常,多个重叠操作可以同时排队,并且每个都必须排队拥有自己的缓冲区/ OVL。我使用malloced结构(或者,如果是C ++,新类实例),或者从池中分配的*结构,为每次调用确保这一点。结构/实例可以在处理之后在完成例程中被提供/删除/重新处理,(或者在线程中排队并在以后的某个地方处理/释放/删除/重新执行)。

5)希望与完成例程执行重叠I / O的线程看起来像是围绕其中一个可警告等待调用的循环。 WaitForSingleObjectEx()很方便,因为它可以以可警告的方式等待构成生产者 - 消费者队列基础的信号量,允许其他线程向执行重叠I / O的线程发出命令/缓冲/信号。