在第八章的源码中,为什么这些程序一连接就WSARecv()?
另外,我把最开始的WASRecv()删掉后发现,用dos下的telnet命令连接后输入数据都是白色的下划线。如果不去除WSARecv()就没有白色下划线。去除WSARecv的结果:
没有去除WSARecv的结果:
都是乱打了一些字符,另外,如果没有在socket连接后加WASRecv(),则在连接结束后没有程序的提示:
高手指教!谢谢。源码(复制粘贴的,是配套源码的原版)
// Module Name: callback.cpp
//
// Description:
//
//    This sample illustrates how to develop a simple echo server Winsock
//    application using the Overlapped I/O model with callback routines. 
//    This sample is implemented as a console-style application and simply prints
//    messages when connections are established and removed from the server.
//    The application listens for TCP connections on port 5150 and accepts them
//    as they arrive. When this application receives data from a client, it
//    simply echos (this is why we call it an echo server) the data back in
//    it's original form until the client closes the connection.
//
// Compile:
//
//    cl -o callback callback.cpp ws2_32.lib
//
// Command Line Options:
//
//    callback.exe 
//
//    Note: There are no command line options for this sample.#include <winsock2.h>
#include <windows.h>
#include <stdio.h>#define PORT 5150
#define DATA_BUFSIZE 8192typedef struct _SOCKET_INFORMATION {
   OVERLAPPED Overlapped;
   SOCKET Socket;
   CHAR Buffer[DATA_BUFSIZE];
   WSABUF DataBuf;
   DWORD BytesSEND;
   DWORD BytesRECV;
} SOCKET_INFORMATION, * LPSOCKET_INFORMATION;void CALLBACK WorkerRoutine(DWORD Error, DWORD BytesTransferred,
   LPWSAOVERLAPPED Overlapped, DWORD InFlags);DWORD WINAPI WorkerThread(LPVOID lpParameter);SOCKET AcceptSocket;void main(void)
{
   WSADATA wsaData;
   SOCKET ListenSocket;
   SOCKADDR_IN InternetAddr;
   INT Ret;
   HANDLE ThreadHandle;
   DWORD ThreadId;
   WSAEVENT AcceptEvent;   if ((Ret = WSAStartup(0x0202,&wsaData)) != 0)
   {
      printf("WSAStartup failed with error %d\n", Ret);
      WSACleanup();
      return;
   }   if ((ListenSocket = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, 
      WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET) 
   {
      printf("Failed to get a socket %d\n", WSAGetLastError());
      return;
   }   InternetAddr.sin_family = AF_INET;
   InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY);
   InternetAddr.sin_port = htons(PORT);   if (bind(ListenSocket, (PSOCKADDR) &InternetAddr,
      sizeof(InternetAddr)) == SOCKET_ERROR)
   {
      printf("bind() failed with error %d\n", WSAGetLastError());
      return;
   }   if (listen(ListenSocket, 5))
   {
      printf("listen() failed with error %d\n", WSAGetLastError());
      return;
   }   if ((AcceptEvent = WSACreateEvent()) == WSA_INVALID_EVENT)
   {
      printf("WSACreateEvent() failed with error %d\n", WSAGetLastError());
      return;
   }   // Create a worker thread to service completed I/O requests.    if ((ThreadHandle = CreateThread(NULL, 0, WorkerThread, (LPVOID) AcceptEvent, 0, &ThreadId)) == NULL)
   {
      printf("CreateThread failed with error %d\n", GetLastError());
      return;
   }   while(TRUE)
   {
      AcceptSocket = accept(ListenSocket, NULL, NULL);      if (WSASetEvent(AcceptEvent) == FALSE)
      {
         printf("WSASetEvent failed with error %d\n", WSAGetLastError());
         return;
      }
   }
}DWORD WINAPI WorkerThread(LPVOID lpParameter)
{
   DWORD Flags;
   LPSOCKET_INFORMATION SocketInfo;
   WSAEVENT EventArray[1];
   DWORD Index;
   DWORD RecvBytes;   // Save the accept event in the event array.   EventArray[0] = (WSAEVENT) lpParameter;   while(TRUE)
   {
      // Wait for accept() to signal an event and also process WorkerRoutine() returns.      while(TRUE)
      {
         Index = WSAWaitForMultipleEvents(1, EventArray, FALSE, WSA_INFINITE, TRUE);         if (Index == WSA_WAIT_FAILED)
         {
            printf("WSAWaitForMultipleEvents failed with error %d\n", WSAGetLastError());
            return FALSE;
         }         if (Index != WAIT_IO_COMPLETION)
         {
            // An accept() call event is ready - break the wait loop
            break;
         } 
      }      WSAResetEvent(EventArray[Index - WSA_WAIT_EVENT_0]);
   
      // Create a socket information structure to associate with the accepted socket.      if ((SocketInfo = (LPSOCKET_INFORMATION) GlobalAlloc(GPTR,
         sizeof(SOCKET_INFORMATION))) == NULL)
      {
         printf("GlobalAlloc() failed with error %d\n", GetLastError());
         return FALSE;
      }       // Fill in the details of our accepted socket.      SocketInfo->Socket = AcceptSocket;
      ZeroMemory(&(SocketInfo->Overlapped), sizeof(WSAOVERLAPPED));  
      SocketInfo->BytesSEND = 0;
      SocketInfo->BytesRECV = 0;
      SocketInfo->DataBuf.len = DATA_BUFSIZE;
      SocketInfo->DataBuf.buf = SocketInfo->Buffer;      Flags = 0;
      if (WSARecv(SocketInfo->Socket, &(SocketInfo->DataBuf), 1, &RecvBytes, &Flags,
         &(SocketInfo->Overlapped), WorkerRoutine) == SOCKET_ERROR)
      {
         if (WSAGetLastError() != WSA_IO_PENDING)
         {
            printf("WSARecv() failed with error %d\n", WSAGetLastError());
            return FALSE;
         }
      }      printf("Socket %d connected\n", AcceptSocket);
   }   return TRUE;
}void CALLBACK WorkerRoutine(DWORD Error, DWORD BytesTransferred,
   LPWSAOVERLAPPED Overlapped, DWORD InFlags)
{
   DWORD SendBytes, RecvBytes;
   DWORD Flags;   // Reference the WSAOVERLAPPED structure as a SOCKET_INFORMATION structure
   LPSOCKET_INFORMATION SI = (LPSOCKET_INFORMATION) Overlapped;   if (Error != 0)
   {
     printf("I/O operation failed with error %d\n", Error);
   }   if (BytesTransferred == 0)
   {
      printf("Closing socket %d\n", SI->Socket);
   }   if (Error != 0 || BytesTransferred == 0)
   {
      closesocket(SI->Socket);
      GlobalFree(SI);
      return;
   }   // Check to see if the BytesRECV field equals zero. If this is so, then
   // this means a WSARecv call just completed so update the BytesRECV field
   // with the BytesTransferred value from the completed WSARecv() call.   if (SI->BytesRECV == 0)
   {
      SI->BytesRECV = BytesTransferred;
      SI->BytesSEND = 0;
   }
   else
   {
      SI->BytesSEND += BytesTransferred;
   }   if (SI->BytesRECV > SI->BytesSEND)
   {      // Post another WSASend() request.
      // Since WSASend() is not gauranteed to send all of the bytes requested,
      // continue posting WSASend() calls until all received bytes are sent.      ZeroMemory(&(SI->Overlapped), sizeof(WSAOVERLAPPED));      SI->DataBuf.buf = SI->Buffer + SI->BytesSEND;
      SI->DataBuf.len = SI->BytesRECV - SI->BytesSEND;      if (WSASend(SI->Socket, &(SI->DataBuf), 1, &SendBytes, 0,
         &(SI->Overlapped), WorkerRoutine) == SOCKET_ERROR)
      {
         if (WSAGetLastError() != WSA_IO_PENDING)
         {
            printf("WSASend() failed with error %d\n", WSAGetLastError());
            return;
         }
      }
   }
   else
   {
      SI->BytesRECV = 0;      // Now that there are no more bytes to send post another WSARecv() request.      Flags = 0;
      ZeroMemory(&(SI->Overlapped), sizeof(WSAOVERLAPPED));      SI->DataBuf.len = DATA_BUFSIZE;
      SI->DataBuf.buf = SI->Buffer;      if (WSARecv(SI->Socket, &(SI->DataBuf), 1, &RecvBytes, &Flags,
         &(SI->Overlapped), WorkerRoutine) == SOCKET_ERROR)
      {
         if (WSAGetLastError() != WSA_IO_PENDING )
         {
            printf("WSARecv() failed with error %d\n", WSAGetLastError());
            return;
         }
      }
   }
}

解决方案 »

  1.   

    我忘了说明,我指的WSARecv()是在WorkerThread()函数下的第一个WSARecv()。
      

  2.   

    哈哈,你这个问题跟我这个差不多的,你看了就明白的了http://bbs.csdn.net/topics/390418145
      

  3.   

    拿这的socket例子参考一下:
    http://download.csdn.net/detail/geoff08zhang/4571358
      

  4.   

    还是不懂~
    迷惑,短路中……这个WSARecv是用来调用WorkerRoutine的么?
      

  5.   

    而且你的这个示例   WorkerThread线程只是接收数据  那不一直做投递接收动作  还要干嘛?没数据就等 收到数据就再投递recv收下次数据   不然你还要在外面控制 什么时候recv什么时候休息?
      

  6.   

    就是Post接收操作,用来接收数据
      

  7.   

    我打个比方不知道恰不恰当, 今天家里有快递要来, 我告诉保安让他准许快递上楼, 然后我就在家里打游戏, 快递上楼顺利将物品给我。
    若没有和保安打招呼, 保安就回拦住他, 而且保安不会通知我, 我在家等一天也白等WSARecv就相当于和保安打招呼