Socket I/O模型全接触[2]

[入库:2005年8月18日] [更新:2007年3月24日]

本文简介:选择自 flyinwuhan 的 blog

同样要使用线程:
procedure tlistenthread.execute;
var
  hevent : wsaevent;
  ret    : integer;
  ne     : twsanetworkevents;
  sock   : tsocket;
  adr    : tsockaddrin;
  smsg   : string;
  index,
  eventtotal : dword;
  eventarray : array [0..wsa_maximum_wait_events-1] of wsaevent;
begin
  ...socket...bind...
  hevent := wsacreateevent();
  wsaeventselect( listensock, hevent, fd_accept or fd_close );
  ...listen...

  while ( not terminated ) do
  begin
    index := wsawaitformultipleevents( eventtotal, @eventarray[0], false, wsa_infinite, false );
    fillchar( ne, sizeof(ne), 0 );
    wsaenumnetworkevents( sockarray[index-wsa_wait_event_0],  eventarray[index-wsa_wait_event_0], @ne );

    if ( ne.lnetworkevents and fd_accept ) > 0 then
    begin
      if ne.ierrorcode[fd_accept_bit] <> 0 then
         continue;

      ret := sizeof(adr);
      sock := accept( sockarray[index-wsa_wait_event_0], adr, ret );
      if eventtotal > wsa_maximum_wait_events-1 then//这里wsa_maximum_wait_events同样是64
      begin
        closesocket( sock );
        continue;
      end;

      hevent := wsacreateevent();
      wsaeventselect( sock, hevent, fd_read or fd_write or fd_close );
      sockarray[eventtotal] := sock;
      eventarray[eventtotal] := hevent;
      inc( eventtotal );
    end;

    if ( ne.lnetworkevents and fd_read ) > 0 then
    begin
      if ne.ierrorcode[fd_read_bit] <> 0 then
         continue;
      fillchar( recvbuf[0], pack_size_receive, 0 );
      ret := recv( sockarray[index-wsa_wait_event_0], recvbuf[0], pack_size_receive, 0 );
      ......
    end;
  end;
end;

四:overlapped i/o 事件通知模型

后来,微软通过调查发现,老陈不喜欢上下楼收发信件,因为上下楼其实很浪费时间。于是微软再次改进他们的信箱。新式的信箱采用了更为先进的技术,只要用户告诉微软自己的家在几楼几号,新式信箱会把信件直接传送到用户的家中,然后告诉用户,你的信件已经放到你的家中了!老陈很高兴,因为他不必再亲自收发信件了!

overlapped i/o 事件通知模型和wsaeventselect模型在实现上非常相似,主要区别在“overlapped”,overlapped模型是让应用程序使用重叠数据结构(wsaoverlapped),一次投递一个或多个winsock i/o请求。这些提交的请求完成后,应用程序会收到通知。什么意思呢?就是说,如果你想从socket上接收数据,只需要告诉系统,由系统为你接收数据,而你需要做的只是为系统提供一个缓冲区~~~~~
listen线程和wsaeventselect模型一模一样,recv/send线程则完全不同:
procedure toverlapthread.execute;
var
  dwtemp : dword;
  ret    : integer;
  index  : dword;
begin
  ......

  while ( not terminated ) do
  begin
    index := wsawaitformultipleevents( flinks.count, @flinks.events[0], false, recv_time_out, false );
    dec( index, wsa_wait_event_0 );
    if index > wsa_maximum_wait_events-1 then //超时或者其他错误
       continue;

    wsaresetevent( flinks.events[index] );
    wsagetoverlappedresult( flinks.sockets[index], flinks.poverlaps[index], @dwtemp, false, flinks.pdwflags[index]^ );

    if dwtemp = 0 then //连接已经关闭
    begin
      ......
      continue;
    end else
    begin
      fmmain.listbox1.items.add( flinks.pbufs[index]^.buf );
    end;

    //初始化缓冲区
    flinks.pdwflags[index]^ := 0;
    fillchar( flinks.poverlaps[index]^, sizeof(wsaoverlapped), 0 );
    flinks.poverlaps[index]^.hevent := flinks.events[index];
    fillchar( flinks.pbufs[index]^.buf^, buffer_size, 0 );

    //递一个接收数据请求
    wsarecv( flinks.sockets[index], flinks.pbufs[index], 1, flinks.pdwrecvd[index]^, flinks.pdwflags[index]^, flinks.poverlaps[index], nil );
  end;
end;

五:overlapped i/o 完成例程模型

老陈接收到新的信件后,一般的程序是:打开信封----掏出信纸----阅读信件----回复信件......为了进一步减轻用户负担,微软又开发了一种新的技术:用户只要告诉微软对信件的操作步骤,微软信箱将按照这些步骤去处理信件,不再需要用户亲自拆信/阅读/回复了!老陈终于过上了小资生活!

本文关键:Socket I/O模型全接触
 

本站最佳浏览方式为 分辨率 1024x768 IE 6.0(或更高版本的 IE浏览器)

go top