本站首页    管理页面    写新日志    退出


 

 

 


最新日志

练车
今天是2011年07月02号
温馨
CInternetSession 类
CHttpFile实现Get/Post
在MFC中加一个控制台DOS界面
strtol 函数
outputParam
有关CTime和ColeDateTime
variant_t ,_bstr_t 与

 


 

最近的评论

回复:CHttpFile实现Get/Po
回复:好久没有来了
回复:参数自整定的模糊PID
回复:电子设计大赛自由命题可参考的题目
回复:数字万用表使用方法
回复:公交车上巨搞笑的一幕
回复:电子设计大赛自由命题可参考的题目
回复:电子设计大赛自由命题可参考的题目
回复:电子设计大赛自由命题可参考的题目
回复:暑假回来

 


 

连接




    

OVERLAPPED IO
sccwqiang 发表于 2008-2-22 23:47:01

        重叠模式 之 完成例程   完成例程是另外一种管理重叠I/O请求的方法,完成例程其实就是一些函数,在开始时有我们传递给一个重叠I/O请求,当一个重叠I/O请求完成后,系统会调用这些完成例程。完成例程必须有以下的函数原型: void   CALLBACK   CompletionROUTINE(       DWORD   dwError,       DWORD   cbTransferred,       LPWSAOVERLAPPED    lpOverlapped,       DWORD   dwFlags ); dwError,表示一个重叠I/O请求后的完成状态。 cbTransferred,实际传输的字节量。 dwFlags,尚未使用,设为0。      重叠模式 之 基于事件通知的重叠模型 重叠模式是的总体设计以WIN32重叠I/O机制为基础,要想在一个套接字上使用重叠I/O模型,必须使用WSA_FLAG_OVERLAPPED这个标志,如下: s=WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED); 如果使用的是socket函数,则默认设置为WSA_FLAG_OVERLAPPED。 使用重叠模式,就不得不熟悉WSAOVERLAPPED结构,下面是这个结构的定义: typedef  struct  WSAOVERLAPPED {     DWORD    Internal;     DWORD    InternalHigh;     DWORD    Offset;     DWORD    OffsetHigh;     WSAEVENT   hEvent; }  WSAOVERLAPPED, FAR * LPWSAOVERLAPPED; 其中前4个参数都是系统内部调用的,不关我们的事。 WSAOVERLAPPED结构中的hEvent即可和一个事件对象进行关联:用WSACreateEvent创建一个事件对象,将重叠结构的hEvent字段分配给新创建的事件对象。然后调用下列winsock函数(带重叠结构类型的参数), WSASend 、WSASendTo、 WSARecv、 WSARecvFrom、 WSAIoctl、AcceptEx、 TransimitFile 在对重叠I/O请求完成后,Winsock会更改重叠结构中的事件对象的事件传信状态,从“未传信”-->“已传信”,由于WSACreate最开始在一种未传信的工作状态中,并用一种人工重设模式创建句柄的,所以在I/O请求完成后我们的程序有责任将工作状态从“已传信”转到“未传信”,即调用WSAResetEvent函数。 对重叠I/O请求完成后,我们可以调用WSAGetOverlappedResult函数来判断重叠调用是否成功,定义如下: BOOL   WSAGetOverlappedResult(      SOCKET    s,      LPWSAOVERLAPPED   lpOverlapped,      LPDWORD      lpcbTransfer,      BOOL    fWait,      LPDWORD    lpdwFlags ); 其中,lpcbTransfer对应一个双字变量,负责接收一次重叠发送或接收操作实际传输的字节数。 fWait,用于决定是否应该等待一次重叠操作完成。 lpdwFlags,负责接收结果标志。 下面是一个完整的过程: 1.创建一个套接字,开始在指定的端口上监听连接请求。 2.接收进入的连接请求。 3.为接受的套接字新建一个WSAOVERLAPPED结构,并为该结构分配一个事件对象句柄,同时把该对象句柄分配给一个事件数组,以便由WSAWaitForMultipleEvent函数使用。 4.在套接字上投递一个异步WSARecv请求,指定参数为WSAOVERLAPPED结构。 5.使用步骤3中的事件数组,调用WSAWaitForMultipleEvent,等待与重叠调用关联的事件对像进入“已传信”状态(即,等待事件触发) 6.WSAWaitForMultipleEvent函数完成后,针对事件数组,调用WSAResetEvent重设事件对象,并对完成的重叠请求进行处理。 7.使用WSAGetOverlappedResult函数,判断重叠调用的返回状态。 8.在套接字上投递另一个重叠WSARecv请求。 9.重复5--8步骤。 代码如下: #include #include #include #define PORT 5150#define DATA_BUFSIZE 8192 typedef struct _SOCKET_INFORMATION {   CHAR Buffer[DATA_BUFSIZE];   WSABUF DataBuf;   SOCKET Socket;   WSAOVERLAPPED Overlapped;   DWORD BytesSEND;   DWORD BytesRECV;} SOCKET_INFORMATION, * LPSOCKET_INFORMATION; DWORD WINAPI ProcessIO(LPVOID lpParameter); DWORD EventTotal = 0;WSAEVENT EventArray[WSA_MAXIMUM_WAIT_EVENTS];LPSOCKET_INFORMATION SocketArray[WSA_MAXIMUM_WAIT_EVENTS];CRITICAL_SECTION CriticalSection;   void main(void){   WSADATA wsaData;   SOCKET ListenSocket, AcceptSocket;   SOCKADDR_IN InternetAddr;   DWORD Flags;   DWORD ThreadId;   DWORD RecvBytes;   INT Ret;    InitializeCriticalSection(&CriticalSection);    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;   }    // Setup the listening socket for connections.    if ((AcceptSocket = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0,      WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)    {      printf("Failed to get a socket %d\n", WSAGetLastError());      return;   }    if ((EventArray[0] = WSACreateEvent()) == WSA_INVALID_EVENT)   {      printf("WSACreateEvent failed with error %d\n", WSAGetLastError());      return;   }    // Create a thread to service overlapped requests    if (CreateThread(NULL, 0, ProcessIO, NULL, 0, &ThreadId) == NULL)   {      printf("CreateThread failed with error %d\n", GetLastError());      return;   }    EventTotal = 1;    while(TRUE)   {       // Accept inbound connections       if ((AcceptSocket = accept(ListenSocket, NULL, NULL)) == INVALID_SOCKET)      {          printf("accept failed with error %d\n", WSAGetLastError());          return;      }       EnterCriticalSection(&CriticalSection);       // Create a socket information structure to associate with the accepted socket.       if ((SocketArray[EventTotal] = (LPSOCKET_INFORMATION) GlobalAlloc(GPTR,         sizeof(SOCKET_INFORMATION))) == NULL)      {         printf("GlobalAlloc() failed with error %d\n", GetLastError());         return;      }       // Fill in the details of our accepted socket.       SocketArray[EventTotal]->Socket = AcceptSocket;      ZeroMemory(&(SocketArray[EventTotal]->Overlapped), sizeof(OVERLAPPED));      SocketArray[EventTotal]->BytesSEND = 0;      SocketArray[EventTotal]->BytesRECV = 0;      SocketArray[EventTotal]->DataBuf.len = DATA_BUFSIZE;      SocketArray[EventTotal]->DataBuf.buf = SocketArray[EventTotal]->Buffer;       if ((SocketArray[EventTotal]->Overlapped.hEvent = EventArray[EventTotal] =           WSACreateEvent()) == WSA_INVALID_EVENT)      {         printf("WSACreateEvent() failed with error %d\n", WSAGetLastError());         return;      }       // Post a WSARecv request to to begin receiving data on the socket       Flags = 0;      if (WSARecv(SocketArray[EventTotal]->Socket,          &(SocketArray[EventTotal]->DataBuf), 1, &RecvBytes, &Flags,         &(SocketArray[EventTotal]->Overlapped), NULL) == SOCKET_ERROR)      {         if (WSAGetLastError() != ERROR_IO_PENDING)         {            printf("WSARecv() failed with error %d\n", WSAGetLastError());            return;         }      }       EventTotal++;       LeaveCriticalSection(&CriticalSection);       //      // Signal the first event in the event array to tell the worker thread to      // service an additional event in the event array      //      if (WSASetEvent(EventArray[0]) == FALSE)      {         printf("WSASetEvent failed with error %d\n", WSAGetLastError());         return;      }   } } DWORD WINAPI ProcessIO(LPVOID lpParameter){   DWORD Index;   DWORD Flags;   LPSOCKET_INFORMATION SI;   DWORD BytesTransferred;   DWORD i;   DWORD RecvBytes, SendBytes;    // Process asynchronous WSASend, WSARecv requests.    while(TRUE)   {       if ((Index = WSAWaitForMultipleEvents(EventTotal, EventArray, FALSE,         WSA_INFINITE, FALSE)) == WSA_WAIT_FAILED)      {         printf("WSAWaitForMultipleEvents failed %d\n", WSAGetLastError());         return 0;      }       // If the event triggered was zero then a connection attempt was made      // on our listening socket.       if ((Index - WSA_WAIT_EVENT_0) == 0)      {         WSAResetEvent(EventArray[0]);         continue;      }       SI = SocketArray[Index - WSA_WAIT_EVENT_0];      WSAResetEvent(EventArray[Index - WSA_WAIT_EVENT_0]);       if (WSAGetOverlappedResult(SI->Socket, &(SI->Overlapped), &BytesTransferred,         FALSE, &Flags) == FALSE || BytesTransferred == 0)      {         printf("Closing socket %d\n", SI->Socket);          if (closesocket(SI->Socket) == SOCKET_ERROR)         {            printf("closesocket() failed with error %d\n", WSAGetLastError());         }          GlobalFree(SI);         WSACloseEvent(EventArray[Index - WSA_WAIT_EVENT_0]);          // Cleanup SocketArray and EventArray by removing the socket event handle         // and socket information structure if they are not at the end of the         // arrays.          EnterCriticalSection(&CriticalSection);          if ((Index - WSA_WAIT_EVENT_0) + 1 != EventTotal)            for (i = Index - WSA_WAIT_EVENT_0; i < EventTotal; i++)            {               EventArray[i] = EventArray[i + 1];               SocketArray[i] = SocketArray[i + 1];            }          EventTotal--;          LeaveCriticalSection(&CriticalSection);          continue;      }       // 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->Overlapped.hEvent = EventArray[Index - WSA_WAIT_EVENT_0];          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), NULL) == SOCKET_ERROR)         {            if (WSAGetLastError() != ERROR_IO_PENDING)            {               printf("WSASend() failed with error %d\n", WSAGetLastError());               return 0;            }         }      }      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->Overlapped.hEvent = EventArray[Index - WSA_WAIT_EVENT_0];          SI->DataBuf.len = DATA_BUFSIZE;         SI->DataBuf.buf = SI->Buffer;          if (WSARecv(SI->Socket, &(SI->DataBuf), 1, &RecvBytes, &Flags,            &(SI->Overlapped), NULL) == SOCKET_ERROR)         {            if (WSAGetLastError() != ERROR_IO_PENDING)            {               printf("WSARecv() failed with error %d\n", WSAGetLastError());               return 0;            }         }      }   }}                     select模型: select函数原型 int select(     int nfds,     fd_set   FAR * readfds,     fd_set   FAR * writefds,     fd_set   FAR * exceptfds,     const struct  timeval  FAR * timeout ); nfds为了保持与早期兼容,可忽略。 fd_set,代表一系列特定的套接字的集合,readset用于检查可读性,writeset用于检查可写性,exceptset用于检查异常数据,具体用法如下: 假定我们想测试一个套接字是否可读,必须将该套接字增加到readset中,再等待select函数完成,完成后判断该套接字是否仍然是readset集合的一部分,是,则该套接字可读。三个参数至少有一个不为null。 其中的timeval的结构如下: struct timeval {    long      tv_sec;  (秒)    long      tv_usec; (毫秒) } 如select函数调用失败,返回SOCKET_ERROR. 对fd_set集合进行操作,可用宏: FD_CLR(s,*set):从set中删除套接字s; FD_ISSET(s,*set):检查s是否是set集合的一员,返回true或false FD_SET(s,*set):将套接字s加入集合set FD_ZERO(*set):将set初始化为空集合。 WSAAsyncSelect 模型   利用这个模型,应用程序可在一个套接字上接收以Windows消息为基础的网络时间通知。使用这种模型,必须提供一个“窗口”,用于接收消息。函数原型如下: int WSAAsyncSelect(         SOCKET   s,         HWND    hwnd,         unsigned   int  wMsg,         Long   lEvent ); s:对应套接字 hwnd:接收消息的窗体句柄 wMsg:发送的消息,应该为一个比WM_USER大的值。 IEvent:对应为一系列网络事件的组合,包括:FD_READ,FD_WRITE,FD_ACCEPT,FD_CONNECT,FD_CLOSE. 如:WSAAsyncSelect(s,hwnd,WM_SOCKET,FD_CONNECT|FD_READ|FD_WRITE|FD_CLOSE) 在调用WSAAsyncSelect后,即在hwnd对应的窗体回调函数中对网络事件(消息)进行处理: LRESULT CALLBACK WindowProc(     HWND   hWnd,     UINT     uMsg,      WPARAM  wParam,     LPARAM    lParam ); 其中wParam指定在其上面发生了一个网络事件的套接字。 lParam低字节指定了已经发生的网络事件,而lParam的高字节包含了可能出现的错误代码。在网络事件消息到达的时候,先调用WSAGETSELECTERROR宏返回高字节包含的错误信息。若没有错误,则调用WSAGETSELECTEVENT宏返回lParam低字节部分。 WSAEventSelect 模型 和WSAAsyncSelect模型不同的是,这种模型中网络事件会投递至一个事件对象句柄,而非窗口句柄。所以要求我们针对每一个套接字都要建立一个事件对象。用WSACreateEvent函数,定义如下: WSAEVENT   WSACreateEvent(void); 然后调用WSAEventSelect函数,定义如下: int   WSAEventSelect(         SOCKET  s;         WSAEVENT    hEventObject,         long    lNetworkEvents ); 鉴于这个模型的复杂性,还是用代码说话吧: #include #include #include #define PORT 5150#define DATA_BUFSIZE 8192 typedef struct _SOCKET_INFORMATION {   CHAR Buffer[DATA_BUFSIZE];   WSABUF DataBuf;   SOCKET Socket;   DWORD BytesSEND;   DWORD BytesRECV;} SOCKET_INFORMATION, * LPSOCKET_INFORMATION; BOOL CreateSocketInformation(SOCKET s);void FreeSocketInformation(DWORD Event); DWORD EventTotal = 0;WSAEVENT EventArray[WSA_MAXIMUM_WAIT_EVENTS];LPSOCKET_INFORMATION SocketArray[WSA_MAXIMUM_WAIT_EVENTS]; void main(void){   SOCKET Listen;   SOCKET Accept;   SOCKADDR_IN InternetAddr;   DWORD Event;   WSANETWORKEVENTS NetworkEvents;   WSADATA wsaData;   DWORD Ret;   DWORD Flags;   DWORD RecvBytes;   DWORD SendBytes;    if ((Ret = WSAStartup(0x0202, &wsaData)) != 0)  //初始化winsock   {      printf("WSAStartup() failed with error %d\n", Ret);      return;   }    if ((Listen = socket (AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) //创建Listen套接字   {      printf("socket() failed with error %d\n", WSAGetLastError());      return;   }    CreateSocketInformation(Listen);  //创建一个_SOCKET_INFORMATION结构实体    if (WSAEventSelect(Listen, EventArray[EventTotal - 1], FD_ACCEPT|FD_CLOSE) == SOCKET_ERROR)   {      printf("WSAEventSelect() failed with error %d\n", WSAGetLastError());      return;   }    InternetAddr.sin_family = AF_INET;   InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY);   InternetAddr.sin_port = htons(PORT);    if (bind(Listen, (PSOCKADDR) &InternetAddr, sizeof(InternetAddr)) == SOCKET_ERROR)   {      printf("bind() failed with error %d\n", WSAGetLastError());      return;   }    if (listen(Listen, 5))   {      printf("listen() failed with error %d\n", WSAGetLastError());      return;   }           while(TRUE)   {      // Wait for one of the sockets to receive I/O notification and       if ((Event = WSAWaitForMultipleEvents(EventTotal, EventArray, FALSE,         WSA_INFINITE, FALSE)) == WSA_WAIT_FAILED)      {         printf("WSAWaitForMultipleEvents failed with error %d\n", WSAGetLastError());         return;      } //通过SocketArray[Event - WSA_WAIT_EVENT_0]获得事件是在哪个socket上发生 //通过WSAEnumNetworkEvents获得发生了什么类型的网络事件      if (WSAEnumNetworkEvents(SocketArray[Event - WSA_WAIT_EVENT_0]->Socket, EventArray[Event -          WSA_WAIT_EVENT_0], &NetworkEvents) == SOCKET_ERROR)  //必须减去预定义值,才能得到实际的索引位置      {         printf("WSAEnumNetworkEvents failed with error %d\n", WSAGetLastError());         return;      }             if (NetworkEvents.lNetworkEvents & FD_ACCEPT)      {         if (NetworkEvents.iErrorCode[FD_ACCEPT_BIT] != 0)         {            printf("FD_ACCEPT failed with error %d\n", NetworkEvents.iErrorCode[FD_ACCEPT_BIT]);            break;         }          if ((Accept = accept(SocketArray[Event - WSA_WAIT_EVENT_0]->Socket, NULL, NULL)) == INVALID_SOCKET)         {              printf("accept() failed with error %d\n", WSAGetLastError());            break;         }          if (EventTotal > WSA_MAXIMUM_WAIT_EVENTS)         {            printf("Too many connections - closing socket.\n");            closesocket(Accept);            break;         }          CreateSocketInformation(Accept);//一旦有套接字accepted了,就创建事件对象和LPSOCKET_INFORMATION 结构          if (WSAEventSelect(Accept, EventArray[EventTotal - 1], FD_READ|FD_WRITE|FD_CLOSE) == SOCKET_ERROR) //继续对accepted 的 套接字调用WSAEventSelect         {            printf("WSAEventSelect() failed with error %d\n", WSAGetLastError());            return;         }          printf("Socket %d connected\n", Accept);      }       // Try to read and write data to and from the data buffer if read and write events occur.       if (NetworkEvents.lNetworkEvents & FD_READ ||         NetworkEvents.lNetworkEvents & FD_WRITE)      {         if (NetworkEvents.lNetworkEvents & FD_READ &&            NetworkEvents.iErrorCode[FD_READ_BIT] != 0)         {            printf("FD_READ failed with error %d\n", NetworkEvents.iErrorCode[FD_READ_BIT]);            break;         }          if (NetworkEvents.lNetworkEvents & FD_WRITE &&             NetworkEvents.iErrorCode[FD_WRITE_BIT] != 0)         {            printf("FD_WRITE failed with error %d\n", NetworkEvents.iErrorCode[FD_WRITE_BIT]);            break;         }          LPSOCKET_INFORMATION SocketInfo = SocketArray[Event - WSA_WAIT_EVENT_0];          // Read data only if the receive buffer is empty.          if (SocketInfo->BytesRECV == 0)         {            SocketInfo->DataBuf.buf = SocketInfo->Buffer;            SocketInfo->DataBuf.len = DATA_BUFSIZE;             Flags = 0;            if (WSARecv(SocketInfo->Socket, &(SocketInfo->DataBuf), 1, &RecvBytes,               &Flags, NULL, NULL) == SOCKET_ERROR)            {               if (WSAGetLastError() != WSAEWOULDBLOCK)               {                  printf("WSARecv() failed with error %d\n", WSAGetLastError());                  FreeSocketInformation(Event - WSA_WAIT_EVENT_0);                  return;               }            }             else            {               SocketInfo->BytesRECV = RecvBytes;            }         }          // Write buffer data if it is available.          if (SocketInfo->BytesRECV > SocketInfo->BytesSEND)         {            SocketInfo->DataBuf.buf = SocketInfo->Buffer + SocketInfo->BytesSEND;            SocketInfo->DataBuf.len = SocketInfo->BytesRECV - SocketInfo->BytesSEND;             if (WSASend(SocketInfo->Socket, &(SocketInfo->DataBuf), 1, &SendBytes, 0,               NULL, NULL) == SOCKET_ERROR)            {               if (WSAGetLastError() != WSAEWOULDBLOCK)               {                  printf("WSASend() failed with error %d\n", WSAGetLastError());                  FreeSocketInformation(Event - WSA_WAIT_EVENT_0);                  return;               }                // A WSAEWOULDBLOCK error has occured. An FD_WRITE event will be posted               // when more buffer space becomes available            }            else            {               SocketInfo->BytesSEND += SendBytes;                if (SocketInfo->BytesSEND == SocketInfo->BytesRECV)               {                  SocketInfo->BytesSEND = 0;                  SocketInfo->BytesRECV = 0;               }            }         }      }       if (NetworkEvents.lNetworkEvents & FD_CLOSE)      {         if (NetworkEvents.iErrorCode[FD_CLOSE_BIT] != 0)         {            printf("FD_CLOSE failed with error %d\n", NetworkEvents.iErrorCode[FD_CLOSE_BIT]);            break;         }          printf("Closing socket information %d\n", SocketArray[Event - WSA_WAIT_EVENT_0]->Socket);          FreeSocketInformation(Event - WSA_WAIT_EVENT_0);      }   }   return;} BOOL CreateSocketInformation(SOCKET s){   LPSOCKET_INFORMATION SI;         if ((EventArray[EventTotal] = WSACreateEvent()) == WSA_INVALID_EVENT)   {      printf("WSACreateEvent() failed with error %d\n", WSAGetLastError());      return FALSE;   }    if ((SI = (LPSOCKET_INFORMATION) GlobalAlloc(GPTR,      sizeof(SOCKET_INFORMATION))) == NULL)   {      printf("GlobalAlloc() failed with error %d\n", GetLastError());      return FALSE;   }    // Prepare SocketInfo structure for use.    SI->Socket = s;   SI->BytesSEND = 0;   SI->BytesRECV = 0;    SocketArray[EventTotal] = SI;    EventTotal++;    return(TRUE);} void FreeSocketInformation(DWORD Event){   LPSOCKET_INFORMATION SI = SocketArray[Event];   DWORD i;    closesocket(SI->Socket);    GlobalFree(SI);    WSACloseEvent(EventArray[Event]);    // Squash the socket and event arrays    for (i = Event; i < EventTotal; i++)   {      EventArray[i] = EventArray[i + 1];      SocketArray[i] = SocketArray[i + 1];   }    EventTotal--;} 有了源代码,一切都是那么清晰,呵呵。 终于可以进入重叠模型了。。。 《windows网络编程技术》之 Winsock基础 Tag: 前段时间根据客服的反映,老翁的前置机程序存在不工作的情况,初步表现为GPRS登录失败,我查看了报文(强烈要求老板发奖金,有什么问题我总是冲锋在前)发现基本出现在网络频繁断开的情况后(网络每隔10分钟被断开一次,socket错误10053,什么原因还不得而知)。忘了说了,前置机是通过TCP连接到省局的GPRS代理服务器(是由小赖开发的)然后和现场的终端进行通信。前置机程序中是通过delphi的clientsocket进行连接的。一下子还真不知道是什么原因。对于socket这块我绝对不是专家,知其然,不知其所以然。于是我决定先从清理基本概念开始: 鸟瞰TCP/IP体系结构  首先从TCP/IP体系结构开始(这也是不少公司面试时的必备良题啊),相信下图已经表达得非常清除了。 500)this.width=500'> 其次是winsocket与tcp/ip(其实,不止TCP/IP协议族,这里只讨论TCP/IP)  TCP/IP协议核心与应用程序关系图。500)this.width=500'> 最后是常用协议特性: 500)this.width=500'>  关于定址 Winsock中,通过SOCKADDR_IN结构来描述IP地址和服务端口: struct sockaddr_in {       short                             sin_family;       u_short                         sin_port;       struct in_addr               sin_addr;       char                              sin_zero[8]; }; 哦,我只关心IP协议,所以sin_family = AF_INET; 关于端口要注意哦,0-1023为固定服务保留的(别打他们的注意了);1024-49151供普通用户的普通用户进程使用;49152-65535是动态和私有端口。 几个特殊地址:   INADDR_ANY:允许服务器应用监听主机上每个网络接口上的客户机活动;   INADDR_BROADCAST用于在一个IP网络中发送广播UDP数据报。 字节排序: 从主机字节顺序---> 网络字节顺序 返回四字节,用于IP地址 u_long htonl(u_long hostlong) int WSAHtonl(         SOCKET s,         u_long hostlong,         u_long FAR * lpnetlong ); 返回两字节,用于端口号 u_short htons(u_short hostshort); int WSAHtons(       SOCKET s,       u_short hostshort,       u_short FAR * lpnetshort );  对应的反向函数: u_long ntohl(u_long netong) int WSANtohl(         SOCKETs,         u_long netong,         u_long FAR * lphostlong ); u_short htons(u_short netshort); int WSANtons(       SOCKET s,       u_short netshort,       u_short FAR * lphostshort );  进入winsocket  下面开始整理winsocket 的一些细节:  所有的winsocket应用其实都是调用winsock dll 中的方法,所以通过WSAstartup加载是第一步。否则就会出错:WSANOTINITIALISED(10093)。 下面先来看看面向连接的协议: 从服务器端来看: 1.bind,将套接字和一个已知的地址进行绑定。   500)this.width=500'> 这样就创建了一个流套接字,这个步骤最常见的错误是WSAEADDRINUSE (10048) ,表示另外一个进程已经和本地IP和端口进行了绑定,或者那个IP地址和端口号处于TIME_WAIT状态。 2.Listen,将套接字置于监听状态。   ........................

阅读全文(2176) | 回复(0) | 编辑 | 精华


发表评论:
昵称:
密码:
主页:
标题:
验证码:  (不区分大小写,请仔细填写,输错需重写评论内容!)

 

 

 


站点首页 | 联系我们 | 博客注册 | 博客登陆

Sponsored By W3CHINA
W3CHINA Blog 0.8 Processed in 0.063 second(s), page refreshed 144335364 times.
《全国人大常委会关于维护互联网安全的决定》  《计算机信息网络国际联网安全保护管理办法》
苏ICP备05006046号